Files
ResearchKit/ResearchKitActiveTask/Common/ORKOrderedTask+ORKPredefinedActiveTask.m
Pariece McKinney 5c5d295bd5 Public release 3.1.0
2024-10-15 17:05:47 -04:00

3084 lines
169 KiB
Objective-C

/*
Copyright (c) 2015, Apple Inc. All rights reserved.
Copyright (c) 2016, Sage Bionetworks
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKOrderedTask+ORKPredefinedActiveTask.h"
#import "ORKOrderedTask_Private.h"
#import "ORKAccelerometerRecorder.h"
#import "ORKActiveStep_Internal.h"
#import "ORKAmslerGridStep.h"
#import "ORKAnswerFormat_Internal.h"
#import "ORKAudioLevelNavigationRule.h"
#import "ORKAudioRecorder.h"
#import "ORKAudioStep.h"
#import "ORKCompletionStep.h"
#import "ORKCountdownStep.h"
#import "ORKEnvironmentSPLMeterStep.h"
#import "ORKHolePegTestPlaceStep.h"
#import "ORKHolePegTestRemoveStep.h"
#import "ORKTouchAnywhereStep.h"
#import "ORKFitnessStep.h"
#import "ORKFormStep.h"
#import "ORKHealthQuantityTypeRecorder.h"
#import "ORKNavigableOrderedTask.h"
#import "ORKPSATStep.h"
#import "ORKQuestionStep.h"
#import "ORKReactionTimeStep.h"
#import "ORKNormalizedReactionTimeStep.h"
#import "ORKSpatialSpanMemoryStep.h"
#import "ORKSpeechRecognitionStep.h"
#import "ORKStep_Private.h"
#import "ORKStroopStep.h"
#import "ORKTappingIntervalStep.h"
#import "ORKAudioFitnessStep.h"
#import "ORKTimedWalkStep.h"
#import "ORKToneAudiometryStep.h"
#import "ORKTowerOfHanoiStep.h"
#import "ORKTrailmakingStep.h"
#import "ORKRangeOfMotionStep.h"
#import "ORKShoulderRangeOfMotionStep.h"
#import "ORKWaitStep.h"
#import "ORKWalkingTaskStep.h"
#import "ORKResultPredicate.h"
#import "ORKSpeechInNoiseStep.h"
#import "ORKdBHLToneAudiometryStep.h"
#import "ORKdBHLToneAudiometryOnboardingStep.h"
#import "ORKSkin.h"
#import "ORKHelpers_Internal.h"
#import "UIImage+ResearchKit.h"
#import <limits.h>
#pragma mark - Predefined
NSString *const ORKInstruction0StepIdentifier = @"instruction";
NSString *const ORKInstruction1StepIdentifier = @"instruction1";
NSString *const ORKInstruction2StepIdentifier = @"instruction2";
NSString *const ORKInstruction3StepIdentifier = @"instruction3";
NSString *const ORKInstruction4StepIdentifier = @"instruction4";
NSString *const ORKInstruction5StepIdentifier = @"instruction5";
NSString *const ORKInstruction6StepIdentifier = @"instruction6";
NSString *const ORKInstruction7StepIdentifier = @"instruction7";
NSString *const ORKCountdownStepIdentifier = @"countdown";
NSString *const ORKCountdown1StepIdentifier = @"countdown1";
NSString *const ORKCountdown2StepIdentifier = @"countdown2";
NSString *const ORKCountdown3StepIdentifier = @"countdown3";
NSString *const ORKCountdown4StepIdentifier = @"countdown4";
NSString *const ORKCountdown5StepIdentifier = @"countdown5";
NSString *const ORKFollowUpQuestions0StepIdentifier = @"followUpQuestion0";
NSString *const ORKEditSpeechTranscript0StepIdentifier = @"editSpeechTranscript0";
NSString *const ORKConclusionStepIdentifier = @"conclusion";
NSString *const ORKActiveTaskLeftHandIdentifier = @"left";
NSString *const ORKActiveTaskMostAffectedHandIdentifier = @"mostAffected";
NSString *const ORKActiveTaskRightHandIdentifier = @"right";
NSString *const ORKActiveTaskSkipHandStepIdentifier = @"skipHand";
NSString *const ORKTouchAnywhereStepIdentifier = @"touch.anywhere";
NSString *const ORKAudioRecorderIdentifier = @"audio";
NSString *const ORKAccelerometerRecorderIdentifier = @"accelerometer";
NSString *const ORKStreamingAudioRecorderIdentifier = @"streamingAudio";
NSString *const ORKPedometerRecorderIdentifier = @"pedometer";
NSString *const ORKDeviceMotionRecorderIdentifier = @"deviceMotion";
NSString *const ORKLocationRecorderIdentifier = @"location";
NSString *const ORKHeartRateRecorderIdentifier = @"heartRate";
void ORKStepArrayAddStep(NSMutableArray *array, ORKStep *step) {
[step validateParameters];
[array addObject:step];
}
@implementation ORKOrderedTask (ORKMakeTaskUtilities)
+ (NSArray<ORKRecorderConfiguration*>*)makeRecorderConfigurationsWithOptions:(ORKPredefinedTaskOption)options {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
HKUnit *bpmUnit = [[HKUnit countUnit] unitDividedByUnit:[HKUnit minuteUnit]];
HKQuantityType *heartRateType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
#endif
NSMutableArray<ORKRecorderConfiguration*> *recorderConfigurations = [NSMutableArray arrayWithCapacity:5];
if (!(ORKPredefinedTaskOptionExcludePedometer & options)) {
[recorderConfigurations addObject:[[ORKPedometerRecorderConfiguration alloc] initWithIdentifier:ORKPedometerRecorderIdentifier]];
}
if (!(ORKPredefinedTaskOptionExcludeAccelerometer & options)) {
[recorderConfigurations addObject:[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:ORKAccelerometerRecorderIdentifier
frequency:100]];
}
if (!(ORKPredefinedTaskOptionExcludeDeviceMotion & options)) {
[recorderConfigurations addObject:[[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier
frequency:100]];
}
#if ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION
if (!(ORKPredefinedTaskOptionExcludeLocation & options)) {
[recorderConfigurations addObject:[[ORKLocationRecorderConfiguration alloc] initWithIdentifier:ORKLocationRecorderIdentifier]];
}
#endif
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
if (!(ORKPredefinedTaskOptionExcludeHeartRate & options)) {
[recorderConfigurations addObject:[[ORKHealthQuantityTypeRecorderConfiguration alloc] initWithIdentifier:ORKHeartRateRecorderIdentifier
healthQuantityType:heartRateType unit:bpmUnit]];
}
#endif
return [recorderConfigurations copy];
}
+ (ORKCompletionStep *)makeCompletionStep {
ORKCompletionStep *step = [[ORKCompletionStep alloc] initWithIdentifier:ORKConclusionStepIdentifier];
step.title = ORKLocalizedString(@"TASK_COMPLETE_TITLE", nil);
step.text = ORKLocalizedString(@"TASK_COMPLETE_TEXT", nil);
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
return step;
}
+ (NSDateComponentsFormatter *)textTimeFormatter {
NSDateComponentsFormatter *formatter = [NSDateComponentsFormatter new];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleSpellOut;
// Exception list: Korean, Chinese (all), Thai, and Vietnamese.
NSArray *nonSpelledOutLanguages = @[@"ko", @"zh", @"th", @"vi", @"ja"];
NSString *currentLanguage = [[NSBundle mainBundle] preferredLocalizations].firstObject;
NSString *currentLanguageCode = [NSLocale componentsFromLocaleIdentifier:currentLanguage][NSLocaleLanguageCode];
if ((currentLanguageCode != nil) && [nonSpelledOutLanguages containsObject:currentLanguageCode]) {
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;
}
formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropAll;
return formatter;
}
@end
@implementation ORKOrderedTask (ORKPredefinedActiveTask)
#pragma mark - AmslerGridTask
NSString *const ORKAmslerGridStepLeftIdentifier = @"amsler.grid.left";
NSString *const ORKAmslerGridStepRightIdentifier = @"amsler.grid.right";
NSString *const ORKAmslerGridCalibrationLeftIdentifier = @"amsler.grid.calibration.left";
NSString *const ORKAmslerGridCalibrationRightIdentifier = @"amsler.grid.calibration.Right";
+ (ORKOrderedTask *)amslerGridTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(NSString *)intendedUseDescription
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"AMSLER_GRID_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"AMSLER_GRID_INTRO_TEXT", nil);
step.image = [UIImage imageNamed:@"amslerGrid" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"AMSLER_GRID_TITLE", nil);
step.text = ORKLocalizedString(@"AMSLER_GRID_INSTRUCTION_TEXT", nil);
NSString *leftEye = ORKLocalizedString(@"AMSLER_GRID_LEFT_EYE", nil);
NSString *detailText = [@"\n" stringByAppendingString:[NSString stringWithFormat:ORKLocalizedString(@"AMSLER_GRID_INSTRUCTION_DETAIL_TEXT", nil), leftEye]];
step.detailText = detailText;
step.image = [UIImage imageNamed:@"amslerGrid" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKAmslerGridStep *step = [[ORKAmslerGridStep alloc] initWithIdentifier:ORKAmslerGridStepLeftIdentifier];
step.eyeSide = ORKAmslerGridEyeSideLeft;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction2StepIdentifier];
step.title = ORKLocalizedString(@"AMSLER_GRID_TITLE", nil);
step.text = ORKLocalizedString(@"AMSLER_GRID_INSTRUCTION_TEXT", nil);
NSString *rightEye = ORKLocalizedString(@"AMSLER_GRID_RIGHT_EYE", nil);
NSString *detailText = [@"\n" stringByAppendingString:[NSString stringWithFormat:ORKLocalizedString(@"AMSLER_GRID_INSTRUCTION_DETAIL_TEXT", nil), rightEye]];
step.detailText = detailText;
step.image = [UIImage imageNamed:@"amslerGrid" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKAmslerGridStep *step = [[ORKAmslerGridStep alloc] initWithIdentifier:ORKAmslerGridStepRightIdentifier];
step.eyeSide = ORKAmslerGridEyeSideRight;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKCompletionStep *completionStep = [self makeCompletionStep];
ORKStepArrayAddStep(steps, completionStep);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - holePegTestTask
NSString *const ORKHolePegTestDominantPlaceStepIdentifier = @"hole.peg.test.dominant.place";
NSString *const ORKHolePegTestDominantRemoveStepIdentifier = @"hole.peg.test.dominant.remove";
NSString *const ORKHolePegTestNonDominantPlaceStepIdentifier = @"hole.peg.test.non.dominant.place";
NSString *const ORKHolePegTestNonDominantRemoveStepIdentifier = @"hole.peg.test.non.dominant.remove";
+ (ORKNavigableOrderedTask *)holePegTestTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
dominantHand:(ORKBodySagittal)dominantHand
numberOfPegs:(int)numberOfPegs
threshold:(double)threshold
rotated:(BOOL)rotated
timeLimit:(NSTimeInterval)timeLimit
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
BOOL dominantHandLeft = (dominantHand == ORKBodySagittalLeft);
NSTimeInterval stepDuration = (timeLimit == 0) ? CGFLOAT_MAX : timeLimit;
NSString *pegs = [NSNumberFormatter localizedStringFromNumber:@(numberOfPegs) numberStyle:NSNumberFormatterNoStyle];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_TITLE_%@", nil), pegs];
step.text = intendedUseDescription;
step.detailText = [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_INTRO_TEXT_%@", nil), pegs];
step.image = [UIImage imageNamed:@"phoneholepeg" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_TITLE_%@", nil), pegs];
step.text = dominantHandLeft ? [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_INTRO_TEXT_2_LEFT_HAND_FIRST_%@%@", nil), pegs, pegs] : [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_INTRO_TEXT_2_RIGHT_HAND_FIRST_%@%@", nil), pegs, pegs];
step.detailText = ORKLocalizedString(@"HOLE_PEG_TEST_CALL_TO_ACTION", nil);
UIImage *image1 = [UIImage imageNamed:@"holepegtest1" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *image2 = [UIImage imageNamed:@"holepegtest2" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *image3 = [UIImage imageNamed:@"holepegtest3" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *image4 = [UIImage imageNamed:@"holepegtest4" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *image5 = [UIImage imageNamed:@"holepegtest5" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *image6 = [UIImage imageNamed:@"holepegtest6" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.image = [UIImage animatedImageWithImages:@[image1, image2, image3, image4, image5, image6] duration:4];
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
{
ORKHolePegTestPlaceStep *step = [[ORKHolePegTestPlaceStep alloc] initWithIdentifier:ORKHolePegTestDominantPlaceStepIdentifier];
step.title = [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_TITLE_%@", nil), pegs];
step.text = [dominantHandLeft ? ORKLocalizedString(@"HOLE_PEG_TEST_PLACE_INSTRUCTION_LEFT_HAND", nil) : ORKLocalizedString(@"HOLE_PEG_TEST_PLACE_INSTRUCTION_RIGHT_HAND", nil) stringByAppendingString:[@"\n" stringByAppendingString:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)]];
step.spokenInstruction = step.text;
step.movingDirection = dominantHand;
step.dominantHandTested = YES;
step.numberOfPegs = numberOfPegs;
step.threshold = threshold;
step.rotated = rotated;
step.shouldTintImages = YES;
step.stepDuration = stepDuration;
ORKStepArrayAddStep(steps, step);
}
{
ORKHolePegTestRemoveStep *step = [[ORKHolePegTestRemoveStep alloc] initWithIdentifier:ORKHolePegTestDominantRemoveStepIdentifier];
step.title = [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_TITLE_%@", nil), pegs];
step.text = [dominantHandLeft ? ORKLocalizedString(@"HOLE_PEG_TEST_REMOVE_INSTRUCTION_LEFT_HAND", nil) : ORKLocalizedString(@"HOLE_PEG_TEST_REMOVE_INSTRUCTION_RIGHT_HAND", nil) stringByAppendingString:[@"\n" stringByAppendingString:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)]];
step.spokenInstruction = step.text;
step.movingDirection = (dominantHand == ORKBodySagittalLeft) ? ORKBodySagittalRight : ORKBodySagittalLeft;
step.dominantHandTested = YES;
step.numberOfPegs = numberOfPegs;
step.threshold = threshold;
step.shouldTintImages = YES;
step.stepDuration = stepDuration;
ORKStepArrayAddStep(steps, step);
}
{
ORKHolePegTestPlaceStep *step = [[ORKHolePegTestPlaceStep alloc] initWithIdentifier:ORKHolePegTestNonDominantPlaceStepIdentifier];
step.title = [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_TITLE_%@", nil), pegs];
step.text = [dominantHandLeft ? ORKLocalizedString(@"HOLE_PEG_TEST_PLACE_INSTRUCTION_RIGHT_HAND", nil) : ORKLocalizedString(@"HOLE_PEG_TEST_PLACE_INSTRUCTION_LEFT_HAND", nil) stringByAppendingString:[@"\n" stringByAppendingString:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)]];
step.spokenInstruction = step.text;
step.movingDirection = (dominantHand == ORKBodySagittalLeft) ? ORKBodySagittalRight : ORKBodySagittalLeft;
step.dominantHandTested = NO;
step.numberOfPegs = numberOfPegs;
step.threshold = threshold;
step.rotated = rotated;
step.shouldTintImages = YES;
step.stepDuration = stepDuration;
ORKStepArrayAddStep(steps, step);
}
{
ORKHolePegTestRemoveStep *step = [[ORKHolePegTestRemoveStep alloc] initWithIdentifier:ORKHolePegTestNonDominantRemoveStepIdentifier];
step.title = [[NSString alloc] initWithFormat:ORKLocalizedString(@"HOLE_PEG_TEST_TITLE_%@", nil), pegs];
step.text = [dominantHandLeft ? ORKLocalizedString(@"HOLE_PEG_TEST_REMOVE_INSTRUCTION_RIGHT_HAND", nil) : ORKLocalizedString(@"HOLE_PEG_TEST_REMOVE_INSTRUCTION_LEFT_HAND", nil) stringByAppendingString:[@"\n" stringByAppendingString:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)]];
step.spokenInstruction = step.text;
step.movingDirection = dominantHand;
step.dominantHandTested = NO;
step.numberOfPegs = numberOfPegs;
step.threshold = threshold;
step.shouldTintImages = YES;
step.stepDuration = stepDuration;
ORKStepArrayAddStep(steps, step);
}
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKCompletionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
// The task is actually dynamic. The direct navigation rules are used for skipping the peg
// removal steps if the user doesn't succeed in placing all the pegs in the allotted time
// (the rules are removed from `ORKHolePegTestPlaceStepViewController` if she succeeds).
ORKNavigableOrderedTask *task = [[ORKNavigableOrderedTask alloc] initWithIdentifier:identifier steps:steps];
ORKStepNavigationRule *navigationRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:ORKHolePegTestNonDominantPlaceStepIdentifier];
[task setNavigationRule:navigationRule forTriggerStepIdentifier:ORKHolePegTestDominantPlaceStepIdentifier];
navigationRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:ORKConclusionStepIdentifier];
[task setNavigationRule:navigationRule forTriggerStepIdentifier:ORKHolePegTestNonDominantPlaceStepIdentifier];
return task;
}
#pragma mark - twoFingerTappingInterval
NSString *const ORKTappingStepIdentifier = @"tapping";
+ (ORKOrderedTask *)twoFingerTappingIntervalTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(NSString *)intendedUseDescription
duration:(NSTimeInterval)duration
handOptions:(ORKPredefinedTaskHandOption)handOptions
options:(ORKPredefinedTaskOption)options {
NSString *durationString = [ORKDurationStringFormatter() stringFromTimeInterval:duration];
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"TAPPING_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"TAPPING_INTRO_TEXT", nil);
NSString *imageName = @"phonetapping";
if (![[NSLocale preferredLanguages].firstObject hasPrefix:@"en"]) {
imageName = [imageName stringByAppendingString:@"_notap"];
}
step.image = [UIImage imageNamed:imageName inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
// Setup which hand to start with and how many hands to add based on the handOptions parameter
// Hand order is randomly determined.
NSUInteger handCount = ((handOptions & ORKPredefinedTaskHandOptionBoth) == ORKPredefinedTaskHandOptionBoth) ? 2 : 1;
BOOL undefinedHand = (handOptions == 0);
BOOL rightHand;
switch (handOptions) {
case ORKPredefinedTaskHandOptionLeft:
rightHand = NO; break;
case ORKPredefinedTaskHandOptionRight:
case ORKPredefinedTaskHandOptionUnspecified:
rightHand = YES; break;
default:
rightHand = (arc4random()%2 == 0); break;
}
for (NSUInteger hand = 1; hand <= handCount; hand++) {
NSString * (^appendIdentifier) (NSString *) = ^ (NSString * stepIdentifier) {
if (undefinedHand) {
return stepIdentifier;
} else {
NSString *handIdentifier = rightHand ? ORKActiveTaskRightHandIdentifier : ORKActiveTaskLeftHandIdentifier;
return [NSString stringWithFormat:@"%@.%@", stepIdentifier, handIdentifier];
}
};
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:appendIdentifier(ORKInstruction1StepIdentifier)];
// Set the title based on the hand
if (undefinedHand) {
step.title = ORKLocalizedString(@"TAPPING_TASK_TITLE", nil);
} else if (rightHand) {
step.title = ORKLocalizedString(@"TAPPING_TASK_TITLE_RIGHT", nil);
} else {
step.title = ORKLocalizedString(@"TAPPING_TASK_TITLE_LEFT", nil);
}
// Set the instructions for the tapping test screen that is displayed prior to each hand test
NSString *restText = ORKLocalizedString(@"TAPPING_INTRO_TEXT_2_REST_PHONE", nil);
NSString *tappingTextFormat = ORKLocalizedString(@"TAPPING_INTRO_TEXT_2_FORMAT", nil);
NSString *tappingText = [NSString localizedStringWithFormat:tappingTextFormat, durationString];
NSString *handText = nil;
if (hand == 1) {
if (undefinedHand) {
handText = ORKLocalizedString(@"TAPPING_INTRO_TEXT_2_MOST_AFFECTED", nil);
} else if (rightHand) {
handText = ORKLocalizedString(@"TAPPING_INTRO_TEXT_2_RIGHT_FIRST", nil);
} else {
handText = ORKLocalizedString(@"TAPPING_INTRO_TEXT_2_LEFT_FIRST", nil);
}
} else {
if (rightHand) {
handText = ORKLocalizedString(@"TAPPING_INTRO_TEXT_2_RIGHT_SECOND", nil);
} else {
handText = ORKLocalizedString(@"TAPPING_INTRO_TEXT_2_LEFT_SECOND", nil);
}
}
step.text = [NSString localizedStringWithFormat:@"%@ %@ %@", restText, handText, tappingText];
// Continue button will be different from first hand and second hand
if (hand == 1) {
step.detailText = ORKLocalizedString(@"TAPPING_CALL_TO_ACTION", nil);
} else {
step.detailText = ORKLocalizedString(@"TAPPING_CALL_TO_ACTION_NEXT", nil);
}
// Set the image
UIImage *im1 = [UIImage imageNamed:@"handtapping01" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *im2 = [UIImage imageNamed:@"handtapping02" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *imageAnimation = [UIImage animatedImageWithImages:@[im1, im2] duration:1];
if (rightHand || undefinedHand) {
step.image = imageAnimation;
} else {
step.image = [imageAnimation ork_flippedImage:UIImageOrientationUpMirrored];
}
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
// TAPPING STEP
{
NSMutableArray *recorderConfigurations = [NSMutableArray arrayWithCapacity:5];
if (!(ORKPredefinedTaskOptionExcludeAccelerometer & options)) {
[recorderConfigurations addObject:[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:ORKAccelerometerRecorderIdentifier
frequency:100]];
}
ORKTappingIntervalStep *step = [[ORKTappingIntervalStep alloc] initWithIdentifier:appendIdentifier(ORKTappingStepIdentifier)];
step.title = ORKLocalizedString(@"TAPPING_TASK_TITLE", nil);
if (undefinedHand) {
step.text = ORKLocalizedString(@"TAPPING_INSTRUCTION", nil);
} else if (rightHand) {
step.text = ORKLocalizedString(@"TAPPING_INSTRUCTION_RIGHT", nil);
} else {
step.text = ORKLocalizedString(@"TAPPING_INSTRUCTION_LEFT", nil);
}
if (UIAccessibilityIsVoiceOverRunning()) {
step.text = [NSString stringWithFormat:ORKLocalizedString(@"AX_TAPPING_INSTRUCTION_VOICEOVER", nil), step.text];
}
step.stepDuration = duration;
step.shouldContinueOnFinish = YES;
step.recorderConfigurations = recorderConfigurations;
step.optional = (handCount == 2);
ORKStepArrayAddStep(steps, step);
}
// Flip to the other hand (ignored if handCount == 1)
rightHand = !rightHand;
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:[steps copy]];
return task;
}
#pragma mark - audioTask
NSString *const ORKAudioStepIdentifier = @"audio";
NSString *const ORKAudioTooLoudStepIdentifier = @"audio.tooloud";
+ (ORKNavigableOrderedTask *)audioTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
speechInstruction:(nullable NSString *)speechInstruction
shortSpeechInstruction:(nullable NSString *)shortSpeechInstruction
duration:(NSTimeInterval)duration
recordingSettings:(nullable NSDictionary *)recordingSettings
checkAudioLevel:(BOOL)checkAudioLevel
options:(ORKPredefinedTaskOption)options {
recordingSettings = recordingSettings ? : @{ AVFormatIDKey : @(kAudioFormatAppleLossless),
AVNumberOfChannelsKey : @(2),
AVSampleRateKey: @(44100.0) };
if (options & ORKPredefinedTaskOptionExcludeAudio) {
@throw [NSException exceptionWithName:NSGenericException reason:@"Audio collection cannot be excluded from audio task" userInfo:nil];
}
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"AUDIO_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"AUDIO_INTENDED_USE", nil);
step.image = [UIImage imageNamed:@"phonewaves" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"AUDIO_TASK_TITLE", nil);
step.text = speechInstruction ? : ORKLocalizedString(@"AUDIO_INTRO_TEXT", nil);
step.detailText = ORKLocalizedString(@"AUDIO_CALL_TO_ACTION", nil);
step.image = [UIImage imageNamed:@"phonesoundwaves" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.stepDuration = 5.0;
step.title = ORKLocalizedString(@"AUDIO_TASK_TITLE", nil);
// Collect audio during the countdown step too, to provide a baseline.
step.recorderConfigurations = @[[[ORKAudioRecorderConfiguration alloc] initWithIdentifier:ORKAudioRecorderIdentifier
recorderSettings:recordingSettings]];
// If checking the sound level then add text indicating that's what is happening
if (checkAudioLevel) {
step.text = ORKLocalizedString(@"AUDIO_LEVEL_CHECK_LABEL", nil);
}
ORKStepArrayAddStep(steps, step);
}
if (checkAudioLevel) {
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKAudioTooLoudStepIdentifier];
step.title = ORKLocalizedString(@"AUDIO_TASK_TITLE", nil);
step.text = ORKLocalizedString(@"AUDIO_TOO_LOUD_MESSAGE", nil);
step.detailText = ORKLocalizedString(@"AUDIO_TOO_LOUD_ACTION_NEXT", nil);
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKAudioStep *step = [[ORKAudioStep alloc] initWithIdentifier:ORKAudioStepIdentifier];
step.title = ORKLocalizedString(@"AUDIO_TASK_TITLE", nil);
step.text = shortSpeechInstruction ? : ORKLocalizedString(@"AUDIO_INSTRUCTION", nil);
step.recorderConfigurations = @[[[ORKAudioRecorderConfiguration alloc] initWithIdentifier:ORKAudioRecorderIdentifier
recorderSettings:recordingSettings]];
step.stepDuration = duration;
step.shouldContinueOnFinish = YES;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKNavigableOrderedTask *task = [[ORKNavigableOrderedTask alloc] initWithIdentifier:identifier steps:steps];
if (checkAudioLevel) {
// Add rules to check for audio and fail, looping back to the countdown step if required
ORKAudioLevelNavigationRule *audioRule = [[ORKAudioLevelNavigationRule alloc] initWithAudioLevelStepIdentifier:ORKCountdownStepIdentifier destinationStepIdentifier:ORKAudioStepIdentifier recordingSettings:recordingSettings];
ORKDirectStepNavigationRule *loopRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:ORKCountdownStepIdentifier];
[task setNavigationRule:audioRule forTriggerStepIdentifier:ORKCountdownStepIdentifier];
[task setNavigationRule:loopRule forTriggerStepIdentifier:ORKAudioTooLoudStepIdentifier];
}
return task;
}
#pragma mark - fitnessCheckTask
NSString *const ORKFitnessWalkStepIdentifier = @"fitness.walk";
NSString *const ORKFitnessRestStepIdentifier = @"fitness.rest";
+ (ORKOrderedTask *)fitnessCheckTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(NSString *)intendedUseDescription
walkDuration:(NSTimeInterval)walkDuration
restDuration:(NSTimeInterval)restDuration
options:(ORKPredefinedTaskOption)options {
NSDateComponentsFormatter *formatter = [self textTimeFormatter];
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"FITNESS_TASK_TITLE", nil);
step.text = intendedUseDescription ? : [NSString localizedStringWithFormat:ORKLocalizedString(@"FITNESS_INTRO_TEXT_FORMAT", nil), [formatter stringFromTimeInterval:walkDuration]];
step.image = [UIImage imageNamed:@"heartbeat" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"FITNESS_TASK_TITLE", nil);
step.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"FITNESS_INTRO_2_TEXT_FORMAT", nil), [formatter stringFromTimeInterval:walkDuration], [formatter stringFromTimeInterval:restDuration]];
step.image = [UIImage imageNamed:@"walkingman" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.title = ORKLocalizedString(@"FITNESS_TASK_TITLE", nil);
step.stepDuration = 5.0;
ORKStepArrayAddStep(steps, step);
}
{
if (walkDuration > 0) {
ORKFitnessStep *fitnessStep = [[ORKFitnessStep alloc] initWithIdentifier:ORKFitnessWalkStepIdentifier];
fitnessStep.stepDuration = walkDuration;
fitnessStep.title = ORKLocalizedString(@"FITNESS_TASK_TITLE", nil);
fitnessStep.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"FITNESS_WALK_INSTRUCTION_FORMAT", nil), [formatter stringFromTimeInterval:walkDuration]];
fitnessStep.spokenInstruction = fitnessStep.text;
fitnessStep.recorderConfigurations = [self makeRecorderConfigurationsWithOptions:options];
fitnessStep.shouldContinueOnFinish = YES;
fitnessStep.optional = NO;
fitnessStep.shouldStartTimerAutomatically = YES;
fitnessStep.shouldTintImages = YES;
fitnessStep.image = [UIImage imageNamed:@"walkingman" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
fitnessStep.imageContentMode = UIViewContentModeCenter;
fitnessStep.shouldVibrateOnStart = YES;
fitnessStep.shouldPlaySoundOnStart = YES;
ORKStepArrayAddStep(steps, fitnessStep);
}
if (restDuration > 0) {
ORKFitnessStep *stillStep = [[ORKFitnessStep alloc] initWithIdentifier:ORKFitnessRestStepIdentifier];
stillStep.stepDuration = restDuration;
stillStep.title = ORKLocalizedString(@"FITNESS_TASK_TITLE", nil);
stillStep.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"FITNESS_SIT_INSTRUCTION_FORMAT", nil), [formatter stringFromTimeInterval:restDuration]];
stillStep.spokenInstruction = stillStep.text;
stillStep.recorderConfigurations = [self makeRecorderConfigurationsWithOptions:options];
stillStep.shouldContinueOnFinish = YES;
stillStep.optional = NO;
stillStep.shouldStartTimerAutomatically = YES;
stillStep.shouldTintImages = YES;
stillStep.image = [UIImage imageNamed:@"sittingman" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
stillStep.imageContentMode = UIViewContentModeCenter;
stillStep.shouldVibrateOnStart = YES;
stillStep.shouldPlaySoundOnStart = YES;
stillStep.shouldPlaySoundOnFinish = YES;
stillStep.shouldVibrateOnFinish = YES;
ORKStepArrayAddStep(steps, stillStep);
}
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - sixMinuteWalk
NSString *const ORKSixMinuteWalkStepIdentifier = @"6mwt";
NSString *const ORKSixMinuteWalkShortnessOfBreathIdentifier = @"6mwt.shortnessOfBreath";
NSString *const ORKSixMinuteWalkFatigueIdentifier = @"6mwt.fatigue";
+ (ORKOrderedTask *)sixMinuteWalkTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(NSString *)intendedUseDescription
options:(ORKPredefinedTaskOption)options {
NSTimeInterval walkDuration = 360; // 6 minutes
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
// Explanation Step
ORKInstructionStep *explainStep = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
explainStep.iconImage = [UIImage systemImageNamed:@"figure.walk"];
explainStep.shouldAutomaticallyAdjustImageTintColor = YES;
explainStep.title = ORKLocalizedString(@"6MWT_TASK_TITLE", nil);
explainStep.text = intendedUseDescription ? : ORKLocalizedString(@"6MWT_INTRO", nil);
explainStep.bodyItems = @[
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INTRO_DETAILS", nil)
detailText:nil
image:nil
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleText],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INTRO_DETAIL_TIME", nil)
detailText:nil
image:[UIImage systemImageNamed:@"stopwatch"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INTRO_DETAIL_WATCH", nil)
detailText:nil
image:[UIImage systemImageNamed:@"applewatch"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INTRO_DETAIL_CLOTHING", nil)
detailText:nil
image:[UIImage systemImageNamed:@"figure.wave"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INTRO_DETAIL_LOCATION", nil)
detailText:nil
image:[UIImage systemImageNamed:@"location"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage]
];
ORKStepArrayAddStep(steps, explainStep);
// Instructions Step
ORKInstructionStep *instructStep = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
instructStep.iconImage = [UIImage systemImageNamed:@"figure.walk"];
instructStep.title = ORKLocalizedString(@"6MWT_INSTRUCTIONS_TITLE", nil);
instructStep.bodyItems = @[
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INSTRUCTIONS_1", nil)
detailText:nil
image:[UIImage systemImageNamed:@"1.circle"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INSTRUCTIONS_2", nil)
detailText:nil
image:[UIImage systemImageNamed:@"2.circle"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INSTRUCTIONS_3", nil)
detailText:nil
image:[UIImage systemImageNamed:@"3.circle"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"6MWT_INSTRUCTIONS_4", nil)
detailText:nil
image:[UIImage systemImageNamed:@"4.circle"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
];
ORKStepArrayAddStep(steps, instructStep);
}
// Fitness Step
ORKFitnessStep *fitnessStep = [[ORKFitnessStep alloc] initWithIdentifier:ORKSixMinuteWalkStepIdentifier];
fitnessStep.stepDuration = walkDuration;
fitnessStep.title = ORKLocalizedString(@"6MWT_TEST_IN_PROGRESS", nil);
fitnessStep.text = ORKLocalizedString(@"6MWT_TEST_IN_PROGRESS_DETAIL", nil);
fitnessStep.spokenInstruction = fitnessStep.text;
fitnessStep.recorderConfigurations = [self makeRecorderConfigurationsWithOptions:options];
fitnessStep.shouldContinueOnFinish = YES;
fitnessStep.optional = NO;
fitnessStep.shouldStartTimerAutomatically = YES;
fitnessStep.shouldVibrateOnStart = YES;
fitnessStep.shouldVibrateOnFinish = YES;
fitnessStep.shouldPlaySoundOnStart = YES;
fitnessStep.shouldPlaySoundOnFinish = YES;
fitnessStep.shouldSpeakRemainingTimeAtHalfway = YES;
fitnessStep.shouldSpeakCountDown = YES;
ORKStepArrayAddStep(steps, fitnessStep);
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
// Follow Up Question Step
ORKFormStep *formStep = [[ORKFormStep alloc] initWithIdentifier:ORKFollowUpQuestions0StepIdentifier];
formStep.title = ORKLocalizedString(@"6MWT_QUESTIONS_TITLE", nil);
formStep.detailText = ORKLocalizedString(@"6MWT_QUESTIONS_DETAIL", nil);
formStep.showsProgress = NO;
formStep.formItems = @[
[[ORKFormItem alloc] initWithIdentifier:ORKSixMinuteWalkShortnessOfBreathIdentifier
text:ORKLocalizedString(@"6MWT_QUESTIONS_BREATH", nil)
detailText:nil
learnMoreItem:nil
showsProgress:NO
answerFormat:[ORKAnswerFormat
scaleAnswerFormatWithMaximumValue:10
minimumValue:1
defaultValue:5
step:1
vertical:NO
maximumValueDescription:ORKLocalizedString(@"6MWT_HIGH_SCORE", nil)
minimumValueDescription:ORKLocalizedString(@"6MWT_LOW_SCORE", nil)]
tagText:nil
optional:NO],
[[ORKFormItem alloc] initWithIdentifier:ORKSixMinuteWalkFatigueIdentifier
text:ORKLocalizedString(@"6MWT_QUESTIONS_FATIGUE", nil)
detailText:nil
learnMoreItem:nil
showsProgress:NO
answerFormat:[ORKAnswerFormat
scaleAnswerFormatWithMaximumValue:10
minimumValue:1
defaultValue:5
step:1
vertical:NO
maximumValueDescription:ORKLocalizedString(@"6MWT_HIGH_SCORE", nil)
minimumValueDescription:ORKLocalizedString(@"6MWT_LOW_SCORE", nil)]
tagText:nil
optional:NO]
];
ORKStepArrayAddStep(steps, formStep);
// Completion Step
ORKInstructionStep *completionStep = [self makeCompletionStep];
ORKStepArrayAddStep(steps, completionStep);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - tecusehCubeTask
NSString *const ORKTecumsehCubeStepIdentifier = @"tecumseh";
+ (ORKOrderedTask *)tecumsehCubeTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
audioBundleIdentifier:(NSString *)audioBundleIdentifier
audioResourceName:(NSString *)audioResourceName
audioFileExtension:(nullable NSString*)audioFileExtension
options:(ORKPredefinedTaskOption)options {
NSTimeInterval stepDuration = 180; // 3 minutes
NSTimeInterval restDuration = 180; // 3 minutes
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
// Explanation Step
ORKInstructionStep *explainStep = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
explainStep.iconImage = [UIImage systemImageNamed:@"cube"];
explainStep.title = ORKLocalizedString(@"TC_TASK_TITLE", nil);
explainStep.text = intendedUseDescription ? : ORKLocalizedString(@"TC_INTRO", nil);
explainStep.shouldAutomaticallyAdjustImageTintColor = YES;
explainStep.bodyItems = @[
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"TC_INTRO_DETAILS", nil)
detailText:nil
image:nil
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleText],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"TC_INTRO_DETAIL_TIME", nil)
detailText:nil
image:[UIImage systemImageNamed:@"stopwatch"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"TC_INTRO_DETAIL_WATCH", nil)
detailText:nil
image:[UIImage systemImageNamed:@"applewatch"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"TC_INTRO_DETAIL_DANGER", nil)
detailText:nil
image:[UIImage systemImageNamed:@"exclamationmark.triangle"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage]
];
ORKStepArrayAddStep(steps, explainStep);
// Instructions Step
ORKInstructionStep *instructStep = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
instructStep.iconImage = [UIImage systemImageNamed:@"cube"];
instructStep.title = ORKLocalizedString(@"TC_INSTRUCTIONS_TITLE", nil);
instructStep.shouldAutomaticallyAdjustImageTintColor = YES;
instructStep.bodyItems = @[
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"TC_INSTRUCTIONS_1", nil)
detailText:nil
image:[UIImage systemImageNamed:@"1.circle"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"TC_INSTRUCTIONS_2", nil)
detailText:nil
image:[UIImage systemImageNamed:@"2.circle"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"TC_INSTRUCTIONS_3", nil)
detailText:nil
image:[UIImage systemImageNamed:@"3.circle"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage]
];
ORKStepArrayAddStep(steps, instructStep);
}
// Fitness Step
ORKBundleAsset *audio = [[ORKBundleAsset alloc] initWithName:audioResourceName
bundleIdentifier:audioBundleIdentifier
fileExtension:audioFileExtension];
ORKAudioFitnessStep *cubeStep = [[ORKAudioFitnessStep alloc] initWithIdentifier:identifier
audioAsset:audio
vocalCues:nil];
cubeStep.stepDuration = stepDuration;
cubeStep.title = ORKLocalizedString(@"TC_TEST_IN_PROGRESS", nil);
cubeStep.text = ORKLocalizedString(@"TC_TEST_IN_PROGRESS_DETAIL", nil);
cubeStep.spokenInstruction = cubeStep.text;
cubeStep.recorderConfigurations = [self makeRecorderConfigurationsWithOptions:options];
cubeStep.shouldContinueOnFinish = YES;
cubeStep.optional = NO;
cubeStep.shouldStartTimerAutomatically = YES;
cubeStep.shouldVibrateOnStart = YES;
cubeStep.shouldVibrateOnFinish = YES;
cubeStep.shouldPlaySoundOnStart = YES;
cubeStep.shouldPlaySoundOnFinish = YES;
cubeStep.shouldSpeakRemainingTimeAtHalfway = YES;
cubeStep.shouldSpeakCountDown = YES;
ORKStepArrayAddStep(steps, cubeStep);
// Rest Step
ORKFitnessStep *stillStep = [[ORKFitnessStep alloc] initWithIdentifier:ORKFitnessRestStepIdentifier];
stillStep.stepDuration = restDuration;
stillStep.title = ORKLocalizedString(@"TC_REST_IN_PROGRESS", nil);
stillStep.text = ORKLocalizedString(@"TC_REST_IN_PROGRESS_DETAIL", nil);
stillStep.spokenInstruction = stillStep.text;
stillStep.recorderConfigurations = [self makeRecorderConfigurationsWithOptions:options];
stillStep.shouldContinueOnFinish = YES;
stillStep.optional = NO;
stillStep.shouldStartTimerAutomatically = YES;
stillStep.shouldVibrateOnStart = YES;
stillStep.shouldVibrateOnFinish = YES;
stillStep.shouldPlaySoundOnStart = YES;
stillStep.shouldPlaySoundOnFinish = YES;
stillStep.shouldSpeakRemainingTimeAtHalfway = YES;
stillStep.shouldSpeakCountDown = YES;
ORKStepArrayAddStep(steps, stillStep);
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *completionStep = [self makeCompletionStep];
ORKStepArrayAddStep(steps, completionStep);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - shortWalkTask
NSString *const ORKShortWalkOutboundStepIdentifier = @"walking.outbound";
NSString *const ORKShortWalkReturnStepIdentifier = @"walking.return";
NSString *const ORKShortWalkRestStepIdentifier = @"walking.rest";
+ (ORKOrderedTask *)shortWalkTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(NSString *)intendedUseDescription
numberOfStepsPerLeg:(NSInteger)numberOfStepsPerLeg
restDuration:(NSTimeInterval)restDuration
options:(ORKPredefinedTaskOption)options {
NSDateComponentsFormatter *formatter = [self textTimeFormatter];
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"WALK_INTRO_TEXT", nil);
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
step.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"WALK_INTRO_2_TEXT_%ld", nil),numberOfStepsPerLeg];
step.detailText = ORKLocalizedString(@"WALK_INTRO_2_DETAIL", nil);
step.image = [UIImage imageNamed:@"pocket" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
step.stepDuration = 5.0;
ORKStepArrayAddStep(steps, step);
}
{
{
NSMutableArray *recorderConfigurations = [NSMutableArray array];
if (!(ORKPredefinedTaskOptionExcludePedometer & options)) {
[recorderConfigurations addObject:[[ORKPedometerRecorderConfiguration alloc] initWithIdentifier:ORKPedometerRecorderIdentifier]];
}
if (!(ORKPredefinedTaskOptionExcludeAccelerometer & options)) {
[recorderConfigurations addObject:[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:ORKAccelerometerRecorderIdentifier
frequency:100]];
}
if (!(ORKPredefinedTaskOptionExcludeDeviceMotion & options)) {
[recorderConfigurations addObject:[[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier
frequency:100]];
}
ORKWalkingTaskStep *walkingStep = [[ORKWalkingTaskStep alloc] initWithIdentifier:ORKShortWalkOutboundStepIdentifier];
walkingStep.numberOfStepsPerLeg = numberOfStepsPerLeg;
walkingStep.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
walkingStep.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"WALK_OUTBOUND_INSTRUCTION_FORMAT", nil), (long long)numberOfStepsPerLeg];
walkingStep.spokenInstruction = walkingStep.text;
walkingStep.recorderConfigurations = recorderConfigurations;
walkingStep.shouldContinueOnFinish = YES;
walkingStep.optional = NO;
walkingStep.shouldStartTimerAutomatically = YES;
walkingStep.stepDuration = numberOfStepsPerLeg * 1.5; // fallback duration in case no step count
walkingStep.shouldVibrateOnStart = YES;
walkingStep.shouldPlaySoundOnStart = YES;
ORKStepArrayAddStep(steps, walkingStep);
}
{
NSMutableArray *recorderConfigurations = [NSMutableArray array];
if (!(ORKPredefinedTaskOptionExcludePedometer & options)) {
[recorderConfigurations addObject:[[ORKPedometerRecorderConfiguration alloc] initWithIdentifier:ORKPedometerRecorderIdentifier]];
}
if (!(ORKPredefinedTaskOptionExcludeAccelerometer & options)) {
[recorderConfigurations addObject:[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:ORKAccelerometerRecorderIdentifier
frequency:100]];
}
if (!(ORKPredefinedTaskOptionExcludeDeviceMotion & options)) {
[recorderConfigurations addObject:[[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier
frequency:100]];
}
ORKWalkingTaskStep *walkingStep = [[ORKWalkingTaskStep alloc] initWithIdentifier:ORKShortWalkReturnStepIdentifier];
walkingStep.numberOfStepsPerLeg = numberOfStepsPerLeg;
walkingStep.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
walkingStep.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"WALK_RETURN_INSTRUCTION_FORMAT", nil), (long long)numberOfStepsPerLeg];
walkingStep.spokenInstruction = walkingStep.text;
walkingStep.recorderConfigurations = recorderConfigurations;
walkingStep.shouldContinueOnFinish = YES;
walkingStep.shouldStartTimerAutomatically = YES;
walkingStep.optional = NO;
walkingStep.stepDuration = numberOfStepsPerLeg * 1.5; // fallback duration in case no step count
walkingStep.shouldVibrateOnStart = YES;
walkingStep.shouldPlaySoundOnStart = YES;
ORKStepArrayAddStep(steps, walkingStep);
}
if (restDuration > 0) {
NSMutableArray *recorderConfigurations = [NSMutableArray array];
if (!(ORKPredefinedTaskOptionExcludeAccelerometer & options)) {
[recorderConfigurations addObject:[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:ORKAccelerometerRecorderIdentifier
frequency:100]];
}
if (!(ORKPredefinedTaskOptionExcludeDeviceMotion & options)) {
[recorderConfigurations addObject:[[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier
frequency:100]];
}
ORKFitnessStep *activeStep = [[ORKFitnessStep alloc] initWithIdentifier:ORKShortWalkRestStepIdentifier];
activeStep.recorderConfigurations = recorderConfigurations;
NSString *durationString = [formatter stringFromTimeInterval:restDuration];
activeStep.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
activeStep.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"WALK_STAND_INSTRUCTION_FORMAT", nil), durationString];
activeStep.spokenInstruction = [NSString localizedStringWithFormat:ORKLocalizedString(@"WALK_STAND_VOICE_INSTRUCTION_FORMAT", nil), durationString];
activeStep.shouldStartTimerAutomatically = YES;
activeStep.stepDuration = restDuration;
activeStep.shouldContinueOnFinish = YES;
activeStep.optional = NO;
activeStep.shouldVibrateOnStart = YES;
activeStep.shouldPlaySoundOnStart = YES;
activeStep.shouldVibrateOnFinish = YES;
activeStep.shouldPlaySoundOnFinish = YES;
ORKStepArrayAddStep(steps, activeStep);
}
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - walkBackAndForthTask
+ (ORKOrderedTask *)walkBackAndForthTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(NSString *)intendedUseDescription
walkDuration:(NSTimeInterval)walkDuration
restDuration:(NSTimeInterval)restDuration
options:(ORKPredefinedTaskOption)options {
NSDateComponentsFormatter *formatter = [self textTimeFormatter];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"WALK_INTRO_TEXT", nil);
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
step.text = ORKLocalizedString(@"WALK_INTRO_2_TEXT_BACK_AND_FORTH_INSTRUCTION", nil);
step.detailText = ORKLocalizedString(@"WALK_INTRO_2_DETAIL_BACK_AND_FORTH_INSTRUCTION", nil);
step.image = [UIImage imageNamed:@"pocket" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
step.stepDuration = 5.0;
ORKStepArrayAddStep(steps, step);
}
{
{
NSMutableArray *recorderConfigurations = [NSMutableArray array];
if (!(ORKPredefinedTaskOptionExcludePedometer & options)) {
[recorderConfigurations addObject:[[ORKPedometerRecorderConfiguration alloc] initWithIdentifier:ORKPedometerRecorderIdentifier]];
}
if (!(ORKPredefinedTaskOptionExcludeAccelerometer & options)) {
[recorderConfigurations addObject:[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:ORKAccelerometerRecorderIdentifier
frequency:100]];
}
if (!(ORKPredefinedTaskOptionExcludeDeviceMotion & options)) {
[recorderConfigurations addObject:[[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier
frequency:100]];
}
ORKWalkingTaskStep *walkingStep = [[ORKWalkingTaskStep alloc] initWithIdentifier:ORKShortWalkOutboundStepIdentifier];
walkingStep.numberOfStepsPerLeg = 1000; // Set the number of steps very high so it is ignored
NSString *walkingDurationString = [formatter stringFromTimeInterval:walkDuration];
walkingStep.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
walkingStep.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"WALK_BACK_AND_FORTH_INSTRUCTION_FORMAT", nil), walkingDurationString];
walkingStep.spokenInstruction = walkingStep.text;
walkingStep.recorderConfigurations = recorderConfigurations;
walkingStep.shouldContinueOnFinish = YES;
walkingStep.optional = NO;
walkingStep.shouldStartTimerAutomatically = YES;
walkingStep.stepDuration = walkDuration; // Set the walking duration to the step duration
walkingStep.shouldVibrateOnStart = YES;
walkingStep.shouldPlaySoundOnStart = YES;
walkingStep.shouldSpeakRemainingTimeAtHalfway = (walkDuration > 20);
ORKStepArrayAddStep(steps, walkingStep);
}
if (restDuration > 0) {
NSMutableArray *recorderConfigurations = [NSMutableArray array];
if (!(ORKPredefinedTaskOptionExcludeAccelerometer & options)) {
[recorderConfigurations addObject:[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:ORKAccelerometerRecorderIdentifier
frequency:100]];
}
if (!(ORKPredefinedTaskOptionExcludeDeviceMotion & options)) {
[recorderConfigurations addObject:[[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier
frequency:100]];
}
ORKFitnessStep *activeStep = [[ORKFitnessStep alloc] initWithIdentifier:ORKShortWalkRestStepIdentifier];
activeStep.recorderConfigurations = recorderConfigurations;
NSString *durationString = [formatter stringFromTimeInterval:restDuration];
activeStep.title = ORKLocalizedString(@"WALK_TASK_TITLE", nil);
activeStep.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"WALK_BACK_AND_FORTH_STAND_INSTRUCTION_FORMAT", nil), durationString];
activeStep.spokenInstruction = activeStep.text;
activeStep.shouldStartTimerAutomatically = YES;
activeStep.stepDuration = restDuration;
activeStep.shouldContinueOnFinish = YES;
activeStep.optional = NO;
activeStep.shouldVibrateOnStart = YES;
activeStep.shouldPlaySoundOnStart = YES;
activeStep.shouldVibrateOnFinish = YES;
activeStep.shouldPlaySoundOnFinish = YES;
activeStep.finishedSpokenInstruction = ORKLocalizedString(@"WALK_BACK_AND_FORTH_FINISHED_VOICE", nil);
activeStep.shouldSpeakRemainingTimeAtHalfway = (restDuration > 20);
ORKStepArrayAddStep(steps, activeStep);
}
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - kneeRangeOfMotionTask
NSString *const ORKKneeRangeOfMotionStepIdentifier = @"knee.range.of.motion";
+ (ORKOrderedTask *)kneeRangeOfMotionTaskWithIdentifier:(NSString *)identifier
limbOption:(ORKPredefinedTaskLimbOption)limbOption
intendedUseDescription:(NSString *)intendedUseDescription
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
NSString *limbType = ORKLocalizedString(@"LIMB_RIGHT", nil);
UIImage *kneeStartImage = [UIImage imageNamed:@"knee_start_right" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *kneeMaximumImage = [UIImage imageNamed:@"knee_maximum_right" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
if (limbOption == ORKPredefinedTaskLimbOptionLeft) {
limbType = ORKLocalizedString(@"LIMB_LEFT", nil);
kneeStartImage = [UIImage imageNamed:@"knee_start_left" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
kneeMaximumImage = [UIImage imageNamed:@"knee_maximum_left" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
}
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
ORKInstructionStep *instructionStep = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
instructionStep.shouldAutomaticallyAdjustImageTintColor = YES;
instructionStep.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
instructionStep.text = intendedUseDescription;
instructionStep.shouldTintImages = YES;
instructionStep.iconImage = kneeStartImage;
instructionStep.imageContentMode = UIViewContentModeCenter;
instructionStep.bodyItems = @[
[[ORKBodyItem alloc] initWithText:
([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])?
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TEXT_INSTRUCTION_0_LEFT", nil) :
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TEXT_INSTRUCTION_0_RIGHT", nil)
detailText:nil
image:[UIImage systemImageNamed:@"1.circle.fill"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:
([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])?
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TEXT_INSTRUCTION_1_LEFT", nil) :
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TEXT_INSTRUCTION_1_RIGHT", nil)
detailText:nil
image:[UIImage systemImageNamed:@"2.circle.fill"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:
([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])?
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TEXT_INSTRUCTION_2_LEFT", nil) :
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TEXT_INSTRUCTION_2_RIGHT", nil)
detailText:nil
image:[UIImage systemImageNamed:@"3.circle.fill"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
[[ORKBodyItem alloc] initWithText:
([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])?
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TEXT_INSTRUCTION_3_LEFT", nil) :
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TEXT_INSTRUCTION_3_RIGHT", nil)
detailText:nil
image:[UIImage systemImageNamed:@"4.circle.fill"]
learnMoreItem:nil
bodyItemStyle:ORKBodyItemStyleImage],
];
ORKStepArrayAddStep(steps, instructionStep);
}
NSString *instructionText = ([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])? ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TOUCH_ANYWHERE_STEP_INSTRUCTION_LEFT", nil) : ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_TOUCH_ANYWHERE_STEP_INSTRUCTION_RIGHT", nil);
ORKTouchAnywhereStep *touchAnywhereStep = [[ORKTouchAnywhereStep alloc] initWithIdentifier:ORKTouchAnywhereStepIdentifier instructionText:instructionText];
touchAnywhereStep.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
touchAnywhereStep.image = kneeMaximumImage;
touchAnywhereStep.imageContentMode = UIViewContentModeCenter;
ORKStepArrayAddStep(steps, touchAnywhereStep);
touchAnywhereStep.spokenInstruction = touchAnywhereStep.text;
ORKDeviceMotionRecorderConfiguration *deviceMotionRecorderConfig = [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier frequency:100];
ORKRangeOfMotionStep *kneeRangeOfMotionStep = [[ORKRangeOfMotionStep alloc] initWithIdentifier:ORKKneeRangeOfMotionStepIdentifier limbOption:limbOption];
kneeRangeOfMotionStep.image = kneeStartImage;
kneeRangeOfMotionStep.imageContentMode = UIViewContentModeCenter;
kneeRangeOfMotionStep.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
kneeRangeOfMotionStep.text = ([limbType isEqualToString: ORKLocalizedString(@"LIMB_LEFT", nil)])? ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_SPOKEN_INSTRUCTION_LEFT", nil) :
ORKLocalizedString(@"KNEE_RANGE_OF_MOTION_SPOKEN_INSTRUCTION_RIGHT", nil);
kneeRangeOfMotionStep.spokenInstruction = kneeRangeOfMotionStep.text;
kneeRangeOfMotionStep.recorderConfigurations = @[deviceMotionRecorderConfig];
kneeRangeOfMotionStep.optional = NO;
ORKStepArrayAddStep(steps, kneeRangeOfMotionStep);
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKCompletionStep *completionStep = [self makeCompletionStep];
ORKStepArrayAddStep(steps, completionStep);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - shoulderRangeOfMotionTask
NSString *const ORKShoulderRangeOfMotionStepIdentifier = @"shoulder.range.of.motion";
+ (ORKOrderedTask *)shoulderRangeOfMotionTaskWithIdentifier:(NSString *)identifier
limbOption:(ORKPredefinedTaskLimbOption)limbOption
intendedUseDescription:(NSString *)intendedUseDescription
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
NSString *limbType = ORKLocalizedString(@"LIMB_RIGHT", nil);
UIImage *shoulderStartImage = [UIImage imageNamed:@"shoulder_start_right" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
UIImage *shoulderMaximumImage = [UIImage imageNamed:@"shoulder_maximum_right" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
if (limbOption == ORKPredefinedTaskLimbOptionLeft) {
limbType = ORKLocalizedString(@"LIMB_LEFT", nil);
shoulderStartImage = [UIImage imageNamed:@"shoulder_start_left" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
shoulderMaximumImage = [UIImage imageNamed:@"shoulder_maximum_left" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
}
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
ORKInstructionStep *instructionStep0 = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
instructionStep0.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
instructionStep0.text = intendedUseDescription;
instructionStep0.detailText = ([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])? ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TEXT_INSTRUCTION_0_LEFT", nil) : ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TEXT_INSTRUCTION_0_RIGHT", nil);
instructionStep0.shouldTintImages = YES;
instructionStep0.shouldAutomaticallyAdjustImageTintColor = YES;
instructionStep0.imageContentMode = UIViewContentModeCenter;
ORKStepArrayAddStep(steps, instructionStep0);
ORKInstructionStep *instructionStep1 = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
instructionStep1.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
instructionStep1.text = ([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])? ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TEXT_INSTRUCTION_1_LEFT", nil) : ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TEXT_INSTRUCTION_1_RIGHT", nil);
instructionStep1.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, instructionStep1);
ORKInstructionStep *instructionStep2 = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction2StepIdentifier];
instructionStep2.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
instructionStep2.text = ([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])? ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TEXT_INSTRUCTION_2_LEFT", nil) : ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TEXT_INSTRUCTION_2_RIGHT", nil);
instructionStep2.image = shoulderStartImage;
instructionStep2.imageContentMode = UIViewContentModeCenter;
instructionStep2.shouldTintImages = YES;
instructionStep2.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, instructionStep2);
ORKInstructionStep *instructionStep3 = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction3StepIdentifier];
instructionStep3.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
instructionStep3.text = ([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])? ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TEXT_INSTRUCTION_3_LEFT", nil) : ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TEXT_INSTRUCTION_3_RIGHT", nil);
instructionStep3.image = shoulderMaximumImage;
instructionStep3.imageContentMode = UIViewContentModeCenter;
instructionStep3.shouldTintImages = YES;
instructionStep3.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, instructionStep3);
}
NSString *instructionText = ([limbType isEqualToString:ORKLocalizedString(@"LIMB_LEFT", nil)])? ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TOUCH_ANYWHERE_STEP_INSTRUCTION_LEFT", nil) : ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_TOUCH_ANYWHERE_STEP_INSTRUCTION_RIGHT", nil);
ORKTouchAnywhereStep *touchAnywhereStep = [[ORKTouchAnywhereStep alloc] initWithIdentifier:ORKTouchAnywhereStepIdentifier instructionText:instructionText];
touchAnywhereStep.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
ORKStepArrayAddStep(steps, touchAnywhereStep);
touchAnywhereStep.spokenInstruction = touchAnywhereStep.title;
ORKDeviceMotionRecorderConfiguration *deviceMotionRecorderConfig = [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier frequency:100];
ORKShoulderRangeOfMotionStep *shoulderRangeOfMotionStep = [[ORKShoulderRangeOfMotionStep alloc] initWithIdentifier:ORKShoulderRangeOfMotionStepIdentifier limbOption:limbOption];
shoulderRangeOfMotionStep.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
shoulderRangeOfMotionStep.text = ([limbType isEqualToString: ORKLocalizedString(@"LIMB_LEFT", nil)])? ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_SPOKEN_INSTRUCTION_LEFT", nil) :
ORKLocalizedString(@"SHOULDER_RANGE_OF_MOTION_SPOKEN_INSTRUCTION_RIGHT", nil);
shoulderRangeOfMotionStep.spokenInstruction = shoulderRangeOfMotionStep.text;
shoulderRangeOfMotionStep.recorderConfigurations = @[deviceMotionRecorderConfig];
shoulderRangeOfMotionStep.optional = NO;
ORKStepArrayAddStep(steps, shoulderRangeOfMotionStep);
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKCompletionStep *completionStep = [self makeCompletionStep];
completionStep.title = ORKLocalizedString(@"RANGE_OF_MOTION_TITLE", nil);
ORKStepArrayAddStep(steps, completionStep);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - spatialSpanMemoryTask
NSString *const ORKSpatialSpanMemoryStepIdentifier = @"cognitive.memory.spatialspan";
+ (ORKOrderedTask *)spatialSpanMemoryTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(NSString *)intendedUseDescription
initialSpan:(NSInteger)initialSpan
minimumSpan:(NSInteger)minimumSpan
maximumSpan:(NSInteger)maximumSpan
playSpeed:(NSTimeInterval)playSpeed
maximumTests:(NSInteger)maximumTests
maximumConsecutiveFailures:(NSInteger)maximumConsecutiveFailures
customTargetImage:(UIImage *)customTargetImage
customTargetPluralName:(NSString *)customTargetPluralName
requireReversal:(BOOL)requireReversal
options:(ORKPredefinedTaskOption)options {
NSString *targetPluralName = customTargetPluralName ? : ORKLocalizedString(@"SPATIAL_SPAN_MEMORY_TARGET_PLURAL", nil);
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"SPATIAL_SPAN_MEMORY_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = [NSString localizedStringWithFormat:ORKLocalizedString(@"SPATIAL_SPAN_MEMORY_INTRO_TEXT_%@", nil),targetPluralName];
step.image = [UIImage imageNamed:@"memory" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"SPATIAL_SPAN_MEMORY_TITLE", nil);
step.text = [NSString localizedStringWithFormat:requireReversal ? ORKLocalizedString(@"SPATIAL_SPAN_MEMORY_INTRO_2_TEXT_REVERSE_%@%@", nil) : ORKLocalizedString(@"SPATIAL_SPAN_MEMORY_INTRO_2_TEXT_%@%@", nil), targetPluralName, targetPluralName];
step.detailText = ORKLocalizedString(@"SPATIAL_SPAN_MEMORY_CALL_TO_ACTION", nil);
if (!customTargetImage) {
step.image = [UIImage imageNamed:@"memory-second-screen" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
} else {
step.image = customTargetImage;
}
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKSpatialSpanMemoryStep *step = [[ORKSpatialSpanMemoryStep alloc] initWithIdentifier:ORKSpatialSpanMemoryStepIdentifier];
step.title = ORKLocalizedString(@"SPATIAL_SPAN_MEMORY_TITLE", nil);
step.text = nil;
step.initialSpan = initialSpan;
step.minimumSpan = minimumSpan;
step.maximumSpan = maximumSpan;
step.playSpeed = playSpeed;
step.maximumTests = maximumTests;
step.maximumConsecutiveFailures = maximumConsecutiveFailures;
step.customTargetImage = customTargetImage;
step.customTargetPluralName = customTargetPluralName;
step.requireReversal = requireReversal;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - speechRecognitionTask
NSString *const ORKSpeechRecognitionStepIdentifier = @"speech.recognition";
+ (ORKOrderedTask *)speechRecognitionTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
speechRecognizerLocale:(ORKSpeechRecognizerLocale)speechRecognizerLocale
speechRecognitionImage:(nullable UIImage *)speechRecognitionImage
speechRecognitionText:(nullable NSString *)speechRecognitionText
shouldHideTranscript:(BOOL)shouldHideTranscript
allowsEdittingTranscript:(BOOL)allowsEdittingTranscript
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"SPEECH_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"SPEECH_RECOGNITION_INTRO_TEXT", nil);
step.image = [UIImage imageNamed:@"phonewaves" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.shouldTintImages = YES;
step.imageContentMode = UIViewContentModeCenter;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"SPEECH_TASK_TITLE", nil);
step.text = ORKLocalizedString(@"SPEECH_RECOGNITION_INTRO_2_TEXT", nil);
step.detailText = ORKLocalizedString(@"SPEECH_RECOGNITION_CALL_TO_ACTION", nil);
step.image = [UIImage imageNamed:@"phonewavesspeech" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
ORKSpeechRecognitionStep *step = [[ORKSpeechRecognitionStep alloc] initWithIdentifier: ORKSpeechRecognitionStepIdentifier image:speechRecognitionImage text:speechRecognitionText];
ORKStreamingAudioRecorderConfiguration *config = [[ORKStreamingAudioRecorderConfiguration alloc] initWithIdentifier: ORKStreamingAudioRecorderIdentifier];
step.title = ORKLocalizedString(@"SPEECH_TASK_TITLE", nil);
step.shouldHideTranscript = shouldHideTranscript;
step.recorderConfigurations = @[config];
step.speechRecognizerLocale = speechRecognizerLocale;
step.shouldContinueOnFinish = NO;
ORKStepArrayAddStep(steps, step);
if (allowsEdittingTranscript) {
ORKTextAnswerFormat *answerFormat = [ORKTextAnswerFormat new];
answerFormat.spellCheckingType = UITextSpellCheckingTypeNo;
answerFormat.autocorrectionType = UITextAutocorrectionTypeNo;
answerFormat.multipleLines = YES;
answerFormat.maximumLength = 280;
ORKQuestionStep *editTranscriptStep = [ORKQuestionStep questionStepWithIdentifier:ORKEditSpeechTranscript0StepIdentifier
title:ORKLocalizedString(@"SPEECH_RECOGNITION_QUESTION_TITLE", nil)
question:nil
answer:answerFormat];
editTranscriptStep.text = ORKLocalizedString(@"SPEECH_RECOGNITION_QUESTION_TEXT", nil);
ORKStepArrayAddStep(steps, editTranscriptStep);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *completionStep = [self makeCompletionStep];
ORKStepArrayAddStep(steps, completionStep);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - speechInNoiseTask
NSString *const ORKSpeechInNoiseStep0Identifier = @"speech.in.noise0";
NSString *const ORKSpeechInNoiseStep1Identifier = @"speech.in.noise1";
NSString *const ORKSpeechInNoiseStep2Identifier = @"speech.in.noise2";
+ (ORKOrderedTask *)speechInNoiseTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"SPEECH_IN_NOISE_TITLE", nil);
step.detailText = intendedUseDescription;
step.text = ORKLocalizedString(@"SPEECH_IN_NOISE_INTRO_TEXT", nil);
step.image = [UIImage imageNamed:@"speechInNoise" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"SPEECH_IN_NOISE_TITLE", nil);
step.detailText = ORKLocalizedString(@"SPEECH_IN_NOISE_DETAIL_TEXT", nil);
step.image = [UIImage imageNamed:@"speechInNoise" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
// SNR ranging from 18 dB to 0 dB with a 3 dB step
NSMutableArray *gainValues = [NSMutableArray new];
[gainValues addObject:[NSNumber numberWithDouble:0.18]];
[gainValues addObject:[NSNumber numberWithDouble:0.25]];
[gainValues addObject:[NSNumber numberWithDouble:0.36]];
[gainValues addObject:[NSNumber numberWithDouble:0.51]];
[gainValues addObject:[NSNumber numberWithDouble:0.73]];
[gainValues addObject:[NSNumber numberWithDouble:1.03]];
[gainValues addObject:[NSNumber numberWithDouble:1.46]];
{
ORKSpeechInNoiseStep *step = [[ORKSpeechInNoiseStep alloc] initWithIdentifier:ORKSpeechInNoiseStep1Identifier];
step.speechFileNameWithExtension = @"Sentence1.wav";
step.gainAppliedToNoise = [gainValues[0] doubleValue];
step.title = ORKLocalizedString(@"SPEECH_IN_NOISE_STEP_TITLE", nil);
step.text = ORKLocalizedString(@"SPEECH_IN_NOISE_STEP_TEXT", nil);
ORKStepArrayAddStep(steps, step);
}
{
ORKSpeechRecognitionStep *step = [[ORKSpeechRecognitionStep alloc] initWithIdentifier: ORKSpeechInNoiseStep2Identifier image:nil text:nil];
ORKStreamingAudioRecorderConfiguration *config = [[ORKStreamingAudioRecorderConfiguration alloc] initWithIdentifier: ORKStreamingAudioRecorderIdentifier];
step.title = ORKLocalizedString(@"SPEECH_IN_NOISE_SPEAK_TITLE", nil);
step.text = ORKLocalizedString(@"SPEECH_IN_NOISE_SPEAK_TEXT", nil);
step.shouldHideTranscript = YES;
step.recorderConfigurations = @[config];
step.speechRecognizerLocale = ORKSpeechRecognizerLocaleEnglishUS;
step.shouldContinueOnFinish = NO;
step.optional = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKTextAnswerFormat *answerFormat = [ORKTextAnswerFormat new];
answerFormat.spellCheckingType = UITextSpellCheckingTypeNo;
answerFormat.autocorrectionType = UITextAutocorrectionTypeNo;
answerFormat.multipleLines = YES;
answerFormat.maximumLength = 280;
ORKQuestionStep *editTranscriptStep = [ORKQuestionStep questionStepWithIdentifier:ORKEditSpeechTranscript0StepIdentifier
title:ORKLocalizedString(@"SPEECH_RECOGNITION_QUESTION_TITLE", nil)
question:nil
answer:answerFormat];
editTranscriptStep.text = ORKLocalizedString(@"SPEECH_RECOGNITION_QUESTION_TEXT", nil);
ORKStepArrayAddStep(steps, editTranscriptStep);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - stroopTask
NSString *const ORKStroopStepIdentifier = @"stroop";
+ (ORKOrderedTask *)stroopTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
numberOfAttempts:(NSInteger)numberOfAttempts
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"STROOP_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"STROOP_TASK_INTRO1_DETAIL_TEXT", nil);
step.image = [UIImage imageNamed:@"phonestrooplabel" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"STROOP_TASK_TITLE", nil);
step.detailText = ORKLocalizedString(@"STROOP_TASK_INTRO2_DETAIL_TEXT", nil);
step.image = [UIImage imageNamed:@"phonestroopbutton" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.title = ORKLocalizedString(@"STROOP_TASK_TITLE", nil);
step.stepDuration = 5.0;
ORKStepArrayAddStep(steps, step);
}
{
ORKStroopStep *step = [[ORKStroopStep alloc] initWithIdentifier:ORKStroopStepIdentifier];
step.title = ORKLocalizedString(@"STROOP_TASK_TITLE", nil);
step.text = ORKLocalizedString(@"STROOP_TASK_STEP_TEXT", nil);
step.spokenInstruction = step.text;
step.numberOfAttempts = numberOfAttempts;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - toneAudiometryTask
NSString *const ORKToneAudiometryPracticeStepIdentifier = @"tone.audiometry.practice";
NSString *const ORKToneAudiometryStepIdentifier = @"tone.audiometry";
+ (ORKOrderedTask *)toneAudiometryTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
speechInstruction:(nullable NSString *)speechInstruction
shortSpeechInstruction:(nullable NSString *)shortSpeechInstruction
toneDuration:(NSTimeInterval)toneDuration
options:(ORKPredefinedTaskOption)options {
if (options & ORKPredefinedTaskOptionExcludeAudio) {
@throw [NSException exceptionWithName:NSGenericException reason:@"Audio collection cannot be excluded from audio task" userInfo:nil];
}
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"TONE_AUDIOMETRY_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"TONE_AUDIOMETRY_INTENDED_USE", nil);
step.image = [UIImage imageNamed:@"phonewaves_inverted" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"TONE_AUDIOMETRY_TASK_TITLE", nil);
step.text = speechInstruction ? : ORKLocalizedString(@"TONE_AUDIOMETRY_INTRO_TEXT", nil);
step.detailText = ORKLocalizedString(@"TONE_AUDIOMETRY_CALL_TO_ACTION", nil);
step.image = [UIImage imageNamed:@"phonefrequencywaves" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
NSString *instructionText = shortSpeechInstruction ? : ORKLocalizedString(@"TONE_AUDIOMETRY_INSTRUCTION", nil);
{
ORKToneAudiometryStep *step = [[ORKToneAudiometryStep alloc] initWithIdentifier:ORKToneAudiometryPracticeStepIdentifier];
step.title = ORKLocalizedString(@"TONE_AUDIOMETRY_TASK_TITLE", nil);
NSString *prepText = speechInstruction ? : ORKLocalizedString(@"TONE_AUDIOMETRY_PREP_TEXT", nil);
if (UIAccessibilityIsVoiceOverRunning()) {
prepText = [NSString stringWithFormat:ORKLocalizedString(@"AX_TONE_AUDIOMETRY_PREP_TEXT_VOICEOVER", nil), prepText, instructionText];
}
step.text = prepText;
step.toneDuration = CGFLOAT_MAX;
step.practiceStep = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.title = ORKLocalizedString(@"TONE_AUDIOMETRY_TASK_TITLE", nil);
step.stepDuration = 5.0;
ORKStepArrayAddStep(steps, step);
}
{
ORKToneAudiometryStep *step = [[ORKToneAudiometryStep alloc] initWithIdentifier:ORKToneAudiometryStepIdentifier];
step.title = ORKLocalizedString(@"TONE_AUDIOMETRY_TASK_TITLE", nil);
step.text = instructionText;
step.toneDuration = toneDuration;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - dBHLToneAudiometryTask
NSString *const ORKdBHLToneAudiometryStep1Identifier = @"dBHL1.tone.audiometry";
NSString *const ORKdBHLToneAudiometryStep2Identifier = @"dBHL2.tone.audiometry";
+ (ORKNavigableOrderedTask *)dBHLToneAudiometryTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
options:(ORKPredefinedTaskOption)options {
if (options & ORKPredefinedTaskOptionExcludeAudio) {
@throw [NSException exceptionWithName:NSGenericException reason:@"Audio collection cannot be excluded from audio task" userInfo:nil];
}
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_INTRO_TITLE", nil);
step.detailText = ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_INTRO_TEXT_2", nil);
step.image = [UIImage imageNamed:@"audiometry" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKBodyItem * item1 = [[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_BODY_ITEM_TEXT_1", nil) detailText:nil image:[UIImage systemImageNamed:@"ear"] learnMoreItem:nil bodyItemStyle:ORKBodyItemStyleImage];
ORKBodyItem * item2 = [[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_BODY_ITEM_TEXT_2", nil) detailText:nil image:[UIImage systemImageNamed:@"hand.draw.fill"] learnMoreItem:nil bodyItemStyle:ORKBodyItemStyleImage];
ORKBodyItem * item3 = [[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_BODY_ITEM_TEXT_3", nil) detailText:nil image:[UIImage systemImageNamed:@"volume.2.fill"] learnMoreItem:nil bodyItemStyle:ORKBodyItemStyleImage];
ORKBodyItem * item4 = [[ORKBodyItem alloc] initWithHorizontalRule];
ORKBodyItem * item5 = [[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_BODY_ITEM_TEXT_4", nil) detailText:nil image:[UIImage systemImageNamed:@"stopwatch"] learnMoreItem:nil bodyItemStyle:ORKBodyItemStyleImage];
item5.useSecondaryColor = YES;
ORKBodyItem * item6 = [[ORKBodyItem alloc] initWithText:ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_BODY_ITEM_TEXT_5", nil) detailText:nil image:[UIImage systemImageNamed:@"moon.fill"] learnMoreItem:nil bodyItemStyle:ORKBodyItemStyleImage];
item6.useSecondaryColor = YES;
step.bodyItems = @[item1, item2, item3, item4, item5, item6];
ORKStepArrayAddStep(steps, step);
}
}
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_TASK_TITLE", nil);
step.text = ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_INTRO_TEXT", nil);
if (UIAccessibilityIsVoiceOverRunning()) {
step.text = [NSString stringWithFormat:ORKLocalizedString(@"AX_dBHL_TONE_AUDIOMETRY_INTRO_TEXT", nil), step.text];
}
step.image = [UIImage imageNamed:@"audiometry" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKEnvironmentSPLMeterStep *step = [[ORKEnvironmentSPLMeterStep alloc] initWithIdentifier:@"splMeter"];
step.requiredContiguousSamples = 5;
step.thresholdValue = 45;
step.title = ORKLocalizedString(@"ENVIRONMENTSPL_TITLE_2", nil);
step.text = ORKLocalizedString(@"ENVIRONMENTSPL_INTRO_TEXT_2", nil);
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction2StepIdentifier];
step.title = ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_STEP_TITLE_RIGHT_EAR", nil);
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKdBHLToneAudiometryStep *step = [[ORKdBHLToneAudiometryStep alloc] initWithIdentifier:ORKdBHLToneAudiometryStep1Identifier];
step.title = ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_TASK_TITLE_2", nil);
step.stepDuration = CGFLOAT_MAX;
// manually adding the headphone type here for testing purposes within ORKCatalog
step.headphoneType = ORKHeadphoneTypeIdentifierAirPodsGen1;
step.earPreference = ORKAudioChannelRight;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction3StepIdentifier];
step.title = ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_STEP_TITLE_LEFT_EAR", nil);
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKdBHLToneAudiometryStep *step = [[ORKdBHLToneAudiometryStep alloc] initWithIdentifier:ORKdBHLToneAudiometryStep2Identifier];
step.title = ORKLocalizedString(@"dBHL_TONE_AUDIOMETRY_TASK_TITLE_2", nil);
step.stepDuration = CGFLOAT_MAX;
step.earPreference = ORKAudioChannelLeft;
// manually adding the headphone type here for testing purposes within ORKCatalog
step.headphoneType = ORKHeadphoneTypeIdentifierAirPodsGen1;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKNavigableOrderedTask *task = [[ORKNavigableOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - towerOfHanoiTask
NSString *const ORKTowerOfHanoiStepIdentifier = @"towerOfHanoi";
+ (ORKOrderedTask *)towerOfHanoiTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
numberOfDisks:(NSUInteger)numberOfDisks
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"TOWER_OF_HANOI_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"TOWER_OF_HANOI_TASK_INTENDED_USE", nil);
step.image = [UIImage imageNamed:@"phone-tower-of-hanoi" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"TOWER_OF_HANOI_TASK_TITLE", nil);
step.text = ORKLocalizedString(@"TOWER_OF_HANOI_TASK_INTRO_TEXT", nil);
step.detailText = ORKLocalizedString(@"TOWER_OF_HANOI_TASK_TASK_CALL_TO_ACTION", nil);
step.image = [UIImage imageNamed:@"tower-of-hanoi-second-screen" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
ORKTowerOfHanoiStep *towerOfHanoiStep = [[ORKTowerOfHanoiStep alloc]initWithIdentifier:ORKTowerOfHanoiStepIdentifier];
towerOfHanoiStep.title = ORKLocalizedString(@"TOWER_OF_HANOI_TASK_TITLE", nil);
towerOfHanoiStep.numberOfDisks = numberOfDisks;
ORKStepArrayAddStep(steps, towerOfHanoiStep);
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc]initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - reactionTimeTask
NSString *const ORKReactionTimeStepIdentifier = @"reactionTime";
+ (ORKOrderedTask *)reactionTimeTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
maximumStimulusInterval:(NSTimeInterval)maximumStimulusInterval
minimumStimulusInterval:(NSTimeInterval)minimumStimulusInterval
thresholdAcceleration:(double)thresholdAcceleration
numberOfAttempts:(int)numberOfAttempts
timeout:(NSTimeInterval)timeout
successSound:(UInt32)successSoundID
timeoutSound:(UInt32)timeoutSoundID
failureSound:(UInt32)failureSoundID
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"REACTION_TIME_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"REACTION_TIME_TASK_INTENDED_USE", nil);
step.image = [UIImage imageNamed:@"phoneshake" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"REACTION_TIME_TASK_TITLE", nil);
step.text = [NSString localizedStringWithFormat: ORKLocalizedString(@"REACTION_TIME_TASK_INTRO_TEXT_FORMAT", nil), numberOfAttempts];
step.detailText = ORKLocalizedString(@"REACTION_TIME_TASK_CALL_TO_ACTION", nil);
step.image = [UIImage imageNamed:@"phoneshakecircle" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
ORKReactionTimeStep *step = [[ORKReactionTimeStep alloc] initWithIdentifier:ORKReactionTimeStepIdentifier];
step.title = ORKLocalizedString(@"REACTION_TIME_TASK_TITLE", nil);
step.maximumStimulusInterval = maximumStimulusInterval;
step.minimumStimulusInterval = minimumStimulusInterval;
step.thresholdAcceleration = thresholdAcceleration;
step.numberOfAttempts = numberOfAttempts;
step.timeout = timeout;
step.successSound = successSoundID;
step.timeoutSound = timeoutSoundID;
step.failureSound = failureSoundID;
step.recorderConfigurations = @[ [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier frequency: 100]];
ORKStepArrayAddStep(steps, step);
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *completionStep = [self makeCompletionStep];
ORKStepArrayAddStep(steps, completionStep);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - normalizedReactionTimeTask
NSString *const ORKNormalizedReactionTimeStepIdentifier = @"normalizedReactionTime";
+ (ORKOrderedTask *)normalizedReactionTimeTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
maximumStimulusInterval:(NSTimeInterval)maximumStimulusInterval
minimumStimulusInterval:(NSTimeInterval)minimumStimulusInterval
thresholdAcceleration:(double)thresholdAcceleration
numberOfAttempts:(int)numberOfAttempts
timeout:(NSTimeInterval)timeout
successSound:(UInt32)successSoundID
timeoutSound:(UInt32)timeoutSoundID
failureSound:(UInt32)failureSoundID
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"REACTION_TIME_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"REACTION_TIME_TASK_INTENDED_USE", nil);
step.image = [UIImage imageNamed:@"phoneshake" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"REACTION_TIME_TASK_TITLE", nil);
step.text = [NSString localizedStringWithFormat: ORKLocalizedString(@"REACTION_TIME_TASK_INTRO_TEXT_FORMAT", nil), numberOfAttempts];
step.detailText = ORKLocalizedString(@"REACTION_TIME_TASK_CALL_TO_ACTION", nil);
step.image = [UIImage imageNamed:@"phoneshakecircle" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
ORKNormalizedReactionTimeStep *step = [[ORKNormalizedReactionTimeStep alloc] initWithIdentifier:ORKReactionTimeStepIdentifier];
step.title = ORKLocalizedString(@"REACTION_TIME_TASK_TITLE", nil);
step.maximumStimulusInterval = maximumStimulusInterval;
step.minimumStimulusInterval = minimumStimulusInterval;
step.thresholdAcceleration = thresholdAcceleration;
step.numberOfAttempts = numberOfAttempts;
step.timeout = timeout;
step.successSound = successSoundID;
step.timeoutSound = timeoutSoundID;
step.failureSound = failureSoundID;
step.recorderConfigurations = @[ [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier frequency: 100]];
ORKStepArrayAddStep(steps, step);
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *completionStep = [self makeCompletionStep];
ORKStepArrayAddStep(steps, completionStep);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - timedWalkTask
NSString *const ORKTimedWalkFormStepIdentifier = @"timed.walk.form";
NSString *const ORKTimedWalkFormAFOStepIdentifier = @"timed.walk.form.afo";
NSString *const ORKTimedWalkFormAssistanceStepIdentifier = @"timed.walk.form.assistance";
NSString *const ORKTimedWalkTrial1StepIdentifier = @"timed.walk.trial1";
NSString *const ORKTimedWalkTurnAroundStepIdentifier = @"timed.walk.turn.around";
NSString *const ORKTimedWalkTrial2StepIdentifier = @"timed.walk.trial2";
+ (ORKOrderedTask *)timedWalkTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
distanceInMeters:(double)distanceInMeters
timeLimit:(NSTimeInterval)timeLimit
turnAroundTimeLimit:(NSTimeInterval)turnAroundTimeLimit
includeAssistiveDeviceForm:(BOOL)includeAssistiveDeviceForm
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
NSLengthFormatter *lengthFormatter = [NSLengthFormatter new];
lengthFormatter.numberFormatter.maximumFractionDigits = 1;
lengthFormatter.numberFormatter.maximumSignificantDigits = 3;
NSString *formattedLength = [lengthFormatter stringFromMeters:distanceInMeters];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"TIMED_WALK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"TIMED_WALK_INTRO_DETAIL", nil);
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
if (includeAssistiveDeviceForm) {
ORKFormStep *step = [[ORKFormStep alloc] initWithIdentifier:ORKTimedWalkFormStepIdentifier
title:ORKLocalizedString(@"TIMED_WALK_FORM_TITLE", nil)
text:ORKLocalizedString(@"TIMED_WALK_FORM_TEXT", nil)];
ORKAnswerFormat *answerFormat1 = [ORKAnswerFormat booleanAnswerFormat];
ORKFormItem *formItem1 = [[ORKFormItem alloc] initWithIdentifier:ORKTimedWalkFormAFOStepIdentifier
text:ORKLocalizedString(@"TIMED_WALK_QUESTION_TEXT", nil)
answerFormat:answerFormat1];
formItem1.optional = NO;
NSArray *textChoices = @[ [ORKTextChoice choiceWithText:ORKLocalizedString(@"TIMED_WALK_QUESTION_2_CHOICE", nil) value:@"TIMED_WALK_QUESTION_2_CHOICE"],
[ORKTextChoice choiceWithText:ORKLocalizedString(@"TIMED_WALK_QUESTION_2_CHOICE_2", nil) value:@"TIMED_WALK_QUESTION_2_CHOICE_2"],
[ORKTextChoice choiceWithText:ORKLocalizedString(@"TIMED_WALK_QUESTION_2_CHOICE_3", nil) value:@"TIMED_WALK_QUESTION_2_CHOICE_3"],
[ORKTextChoice choiceWithText:ORKLocalizedString(@"TIMED_WALK_QUESTION_2_CHOICE_4", nil) value:@"TIMED_WALK_QUESTION_2_CHOICE_4"],
[ORKTextChoice choiceWithText:ORKLocalizedString(@"TIMED_WALK_QUESTION_2_CHOICE_5", nil) value:@"TIMED_WALK_QUESTION_2_CHOICE_5"],
[ORKTextChoice choiceWithText:ORKLocalizedString(@"TIMED_WALK_QUESTION_2_CHOICE_6", nil) value:@"TIMED_WALK_QUESTION_2_CHOICE_6"] ];
ORKAnswerFormat *answerFormat2 = [ORKAnswerFormat valuePickerAnswerFormatWithTextChoices:textChoices];
ORKFormItem *formItem2 = [[ORKFormItem alloc] initWithSectionTitle:ORKLocalizedString(@"TIMED_WALK_QUESTION_2_TITLE", nil) detailText:nil learnMoreItem:nil showsProgress:YES];
ORKFormItem *formItem3 = [[ORKFormItem alloc] initWithIdentifier:ORKTimedWalkFormAssistanceStepIdentifier
text:nil
answerFormat:answerFormat2];
formItem3.placeholder = ORKLocalizedString(@"TIMED_WALK_QUESTION_2_TEXT", nil);
formItem3.optional = NO;
step.formItems = @[formItem1, formItem2, formItem3];
step.optional = NO;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"TIMED_WALK_TITLE", nil);
step.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"TIMED_WALK_INTRO_2_TEXT_%@", nil), formattedLength];
step.detailText = ORKLocalizedString(@"TIMED_WALK_INTRO_2_DETAIL", nil);
step.image = [UIImage imageNamed:@"timer" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.title = ORKLocalizedString(@"TIMED_WALK_TITLE", nil);
step.stepDuration = 5.0;
ORKStepArrayAddStep(steps, step);
}
{
NSMutableArray *recorderConfigurations = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludePedometer)) {
[recorderConfigurations addObject:[[ORKPedometerRecorderConfiguration alloc] initWithIdentifier:ORKPedometerRecorderIdentifier]];
}
if (!(options & ORKPredefinedTaskOptionExcludeAccelerometer)) {
[recorderConfigurations addObject:[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:ORKAccelerometerRecorderIdentifier
frequency:100]];
}
if (!(options & ORKPredefinedTaskOptionExcludeDeviceMotion)) {
[recorderConfigurations addObject:[[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:ORKDeviceMotionRecorderIdentifier
frequency:100]];
}
#if ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION
if (! (options & ORKPredefinedTaskOptionExcludeLocation)) {
[recorderConfigurations addObject:[[ORKLocationRecorderConfiguration alloc] initWithIdentifier:ORKLocationRecorderIdentifier]];
}
#endif
{
ORKTimedWalkStep *step = [[ORKTimedWalkStep alloc] initWithIdentifier:ORKTimedWalkTrial1StepIdentifier];
step.title = ORKLocalizedString(@"TIMED_WALK_TITLE", nil);
step.text = [[[NSString alloc] initWithFormat:ORKLocalizedString(@"TIMED_WALK_INSTRUCTION_%@", nil), formattedLength] stringByAppendingString:[@"\n" stringByAppendingString:ORKLocalizedString(@"TIMED_WALK_INSTRUCTION_TEXT", nil)]];
step.spokenInstruction = step.text;
step.recorderConfigurations = recorderConfigurations;
step.distanceInMeters = distanceInMeters;
step.shouldTintImages = YES;
step.image = [UIImage imageNamed:@"timed-walkingman-outbound" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.stepDuration = timeLimit == 0 ? CGFLOAT_MAX : timeLimit;
ORKStepArrayAddStep(steps, step);
}
{
if (turnAroundTimeLimit > 0) {
ORKTimedWalkStep *step = [[ORKTimedWalkStep alloc] initWithIdentifier:ORKTimedWalkTurnAroundStepIdentifier];
step.title = ORKLocalizedString(@"TIMED_WALK_TITLE", nil);
step.text = [ORKLocalizedString(@"TIMED_WALK_INSTRUCTION_TURN", nil) stringByAppendingString:[@"\n" stringByAppendingString:ORKLocalizedString(@"TIMED_WALK_INSTRUCTION_TEXT", nil)]];
step.spokenInstruction = step.text;
step.recorderConfigurations = recorderConfigurations;
step.distanceInMeters = 1;
step.shouldTintImages = YES;
step.image = [UIImage imageNamed:@"turnaround" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.stepDuration = turnAroundTimeLimit == 0 ? CGFLOAT_MAX : turnAroundTimeLimit;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKTimedWalkStep *step = [[ORKTimedWalkStep alloc] initWithIdentifier:ORKTimedWalkTrial2StepIdentifier];
step.title = ORKLocalizedString(@"TIMED_WALK_TITLE", nil);
step.text = [[[NSString alloc] initWithFormat:ORKLocalizedString(@"TIMED_WALK_INSTRUCTION_2", nil), formattedLength] stringByAppendingString:[@"\n" stringByAppendingString:ORKLocalizedString(@"TIMED_WALK_INSTRUCTION_TEXT", nil)]];
step.spokenInstruction = step.text;
step.recorderConfigurations = recorderConfigurations;
step.distanceInMeters = distanceInMeters;
step.shouldTintImages = YES;
step.image = [UIImage imageNamed:@"timed-walkingman-return" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.stepDuration = timeLimit == 0 ? CGFLOAT_MAX : timeLimit;
ORKStepArrayAddStep(steps, step);
}
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
#pragma mark - PSATTask
NSString *const ORKPSATStepIdentifier = @"psat";
+ (ORKOrderedTask *)PSATTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
presentationMode:(ORKPSATPresentationMode)presentationMode
interStimulusInterval:(NSTimeInterval)interStimulusInterval
stimulusDuration:(NSTimeInterval)stimulusDuration
seriesLength:(NSInteger)seriesLength
options:(ORKPredefinedTaskOption)options {
NSMutableArray *steps = [NSMutableArray array];
NSString *versionTitle = @"";
NSString *versionDetailText = @"";
if (presentationMode == ORKPSATPresentationModeAuditory) {
versionTitle = ORKLocalizedString(@"PASAT_TITLE", nil);
versionDetailText = ORKLocalizedString(@"PASAT_INTRO_TEXT", nil);
} else if (presentationMode == ORKPSATPresentationModeVisual) {
versionTitle = ORKLocalizedString(@"PVSAT_TITLE", nil);
versionDetailText = ORKLocalizedString(@"PVSAT_INTRO_TEXT", nil);
} else {
versionTitle = ORKLocalizedString(@"PAVSAT_TITLE", nil);
versionDetailText = ORKLocalizedString(@"PAVSAT_INTRO_TEXT", nil);
}
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = versionTitle;
step.detailText = versionDetailText;
step.text = intendedUseDescription;
step.image = [UIImage imageNamed:@"psatDice" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = versionTitle;
NSDateComponentsFormatter *secondsFormatter = [NSDateComponentsFormatter new];
secondsFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyleSpellOut;
secondsFormatter.allowedUnits = NSCalendarUnitSecond;
secondsFormatter.formattingContext = NSFormattingContextDynamic;
secondsFormatter.maximumUnitCount = 1;
NSString *seconds = [secondsFormatter stringFromTimeInterval:interStimulusInterval];
step.text = [NSString localizedStringWithFormat:ORKLocalizedString(@"PSAT_INTRO_TEXT_2_%@", nil), seconds];
step.detailText = ORKLocalizedString(@"PSAT_CALL_TO_ACTION", nil);
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.stepDuration = 5.0;
step.title = versionTitle;
ORKStepArrayAddStep(steps, step);
}
{
ORKPSATStep *step = [[ORKPSATStep alloc] initWithIdentifier:ORKPSATStepIdentifier];
step.title = versionTitle;
step.text = ORKLocalizedString(@"PSAT_INITIAL_INSTRUCTION", nil);
step.stepDuration = (seriesLength + 1) * interStimulusInterval;
step.presentationMode = presentationMode;
step.interStimulusInterval = interStimulusInterval;
step.stimulusDuration = stimulusDuration;
step.seriesLength = seriesLength;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:[steps copy]];
return task;
}
#pragma mark - tremorTestTask
NSString *const ORKTremorTestInLapStepIdentifier = @"tremor.handInLap";
NSString *const ORKTremorTestExtendArmStepIdentifier = @"tremor.handAtShoulderLength";
NSString *const ORKTremorTestBendArmStepIdentifier = @"tremor.handAtShoulderLengthWithElbowBent";
NSString *const ORKTremorTestTouchNoseStepIdentifier = @"tremor.handToNose";
NSString *const ORKTremorTestTurnWristStepIdentifier = @"tremor.handQueenWave";
+ (NSString *)stepIdentifier:(NSString *)stepIdentifier withHandIdentifier:(NSString *)handIdentifier {
return [NSString stringWithFormat:@"%@.%@", stepIdentifier, handIdentifier];
}
+ (NSMutableArray *)stepsForOneHandTremorTestTaskWithIdentifier:(NSString *)identifier
activeStepDuration:(NSTimeInterval)activeStepDuration
activeTaskOptions:(ORKTremorActiveTaskOption)activeTaskOptions
lastHand:(BOOL)lastHand
leftHand:(BOOL)leftHand
handIdentifier:(NSString *)handIdentifier
introDetailText:(NSString *)detailText
options:(ORKPredefinedTaskOption)options {
NSMutableArray<ORKStep *> *steps = [NSMutableArray array];
NSString *stepFinishedInstruction = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_FINISHED_INSTRUCTION", nil);
BOOL rightHand = !leftHand && ![handIdentifier isEqualToString:ORKActiveTaskMostAffectedHandIdentifier];
{
NSString *stepIdentifier = [self stepIdentifier:ORKInstruction1StepIdentifier withHandIdentifier:handIdentifier];
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
if ([identifier isEqualToString:ORKActiveTaskMostAffectedHandIdentifier]) {
step.detailText = ORKLocalizedString(@"TREMOR_TEST_INTRO_2_DEFAULT_TEXT", nil);
step.text = detailText;
} else {
if (leftHand) {
step.detailText = ORKLocalizedString(@"TREMOR_TEST_INTRO_2_LEFT_HAND_TEXT", nil);
} else {
step.detailText = ORKLocalizedString(@"TREMOR_TEST_INTRO_2_RIGHT_HAND_TEXT", nil);
}
}
NSString *imageName = leftHand ? @"tremortestLeft" : @"tremortestRight";
step.image = [UIImage imageNamed:imageName inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
// TODO: Awaiting newer assets.
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
if (!(activeTaskOptions & ORKTremorActiveTaskOptionExcludeHandInLap)) {
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
NSString *stepIdentifier = [self stepIdentifier:ORKInstruction2StepIdentifier withHandIdentifier:handIdentifier];
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_IN_LAP_INTRO", nil);
step.detailText = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_INTRO_TEXT", nil);
step.image = [UIImage imageNamed:@"tremortest3a" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
// TODO: Awaiting newer assets.
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.auxiliaryImage = [UIImage imageNamed:@"tremortest3b" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
if (leftHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_IN_LAP_INTRO_LEFT", nil);
step.image = [step.image ork_flippedImage:UIImageOrientationUpMirrored];
step.auxiliaryImage = [step.auxiliaryImage ork_flippedImage:UIImageOrientationUpMirrored];
} else if (rightHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_IN_LAP_INTRO_RIGHT", nil);
}
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
NSString *stepIdentifier = [self stepIdentifier:ORKCountdown1StepIdentifier withHandIdentifier:handIdentifier];
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
ORKStepArrayAddStep(steps, step);
}
{
NSString *titleFormat = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_IN_LAP_INSTRUCTION_%ld", nil);
NSString *stepIdentifier = [self stepIdentifier:ORKTremorTestInLapStepIdentifier withHandIdentifier:handIdentifier];
ORKActiveStep *step = [[ORKActiveStep alloc] initWithIdentifier:stepIdentifier];
step.recorderConfigurations = @[[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:@"ac1_acc" frequency:100.0], [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:@"ac1_motion" frequency:100.0]];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = [NSString localizedStringWithFormat:titleFormat, (long)activeStepDuration];
step.spokenInstruction = step.text;
step.finishedSpokenInstruction = stepFinishedInstruction;
step.stepDuration = activeStepDuration;
step.shouldPlaySoundOnStart = YES;
step.shouldVibrateOnStart = YES;
step.shouldPlaySoundOnFinish = YES;
step.shouldVibrateOnFinish = YES;
step.shouldContinueOnFinish = NO;
step.shouldStartTimerAutomatically = YES;
ORKStepArrayAddStep(steps, step);
}
}
if (!(activeTaskOptions & ORKTremorActiveTaskOptionExcludeHandAtShoulderHeight)) {
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
NSString *stepIdentifier = [self stepIdentifier:ORKInstruction4StepIdentifier withHandIdentifier:handIdentifier];
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_EXTEND_ARM_INTRO", nil);
step.detailText = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_INTRO_TEXT", nil);
step.image = [UIImage imageNamed:@"tremortest4a" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
// TODO: Awaiting newer assets.
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.auxiliaryImage = [UIImage imageNamed:@"tremortest4b" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
if (leftHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_EXTEND_ARM_INTRO_LEFT", nil);
step.image = [step.image ork_flippedImage:UIImageOrientationUpMirrored];
step.auxiliaryImage = [step.auxiliaryImage ork_flippedImage:UIImageOrientationUpMirrored];
} else if (rightHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_EXTEND_ARM_INTRO_RIGHT", nil);
}
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
NSString *stepIdentifier = [self stepIdentifier:ORKCountdown2StepIdentifier withHandIdentifier:handIdentifier];
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
ORKStepArrayAddStep(steps, step);
}
{
NSString *titleFormat = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_EXTEND_ARM_INSTRUCTION_%ld", nil);
NSString *stepIdentifier = [self stepIdentifier:ORKTremorTestExtendArmStepIdentifier withHandIdentifier:handIdentifier];
ORKActiveStep *step = [[ORKActiveStep alloc] initWithIdentifier:stepIdentifier];
step.recorderConfigurations = @[[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:@"ac2_acc" frequency:100.0], [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:@"ac2_motion" frequency:100.0]];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = [NSString localizedStringWithFormat:titleFormat, (long)activeStepDuration];
step.spokenInstruction = step.text;
step.finishedSpokenInstruction = stepFinishedInstruction;
step.stepDuration = activeStepDuration;
step.image = [UIImage imageNamed:@"tremortest4a" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
if (leftHand) {
step.image = [step.image ork_flippedImage:UIImageOrientationUpMirrored];
}
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.shouldPlaySoundOnStart = YES;
step.shouldVibrateOnStart = YES;
step.shouldPlaySoundOnFinish = YES;
step.shouldVibrateOnFinish = YES;
step.shouldContinueOnFinish = NO;
step.shouldStartTimerAutomatically = YES;
ORKStepArrayAddStep(steps, step);
}
}
if (!(activeTaskOptions & ORKTremorActiveTaskOptionExcludeHandAtShoulderHeightElbowBent)) {
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
NSString *stepIdentifier = [self stepIdentifier:ORKInstruction5StepIdentifier withHandIdentifier:handIdentifier];
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_BEND_ARM_INTRO", nil);
step.detailText = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_INTRO_TEXT", nil);
step.image = [UIImage imageNamed:@"tremortest5a" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeScaleAspectFit;
step.auxiliaryImage = [UIImage imageNamed:@"tremortest5b" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
if (leftHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_BEND_ARM_INTRO_LEFT", nil);
step.image = [step.image ork_flippedImage:UIImageOrientationUpMirrored];
step.auxiliaryImage = [step.auxiliaryImage ork_flippedImage:UIImageOrientationUpMirrored];
} else if (rightHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_BEND_ARM_INTRO_RIGHT", nil);
}
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
NSString *stepIdentifier = [self stepIdentifier:ORKCountdown3StepIdentifier withHandIdentifier:handIdentifier];
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
ORKStepArrayAddStep(steps, step);
}
{
NSString *titleFormat = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_BEND_ARM_INSTRUCTION_%ld", nil);
NSString *stepIdentifier = [self stepIdentifier:ORKTremorTestBendArmStepIdentifier withHandIdentifier:handIdentifier];
ORKActiveStep *step = [[ORKActiveStep alloc] initWithIdentifier:stepIdentifier];
step.recorderConfigurations = @[[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:@"ac3_acc" frequency:100.0], [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:@"ac3_motion" frequency:100.0]];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = [NSString localizedStringWithFormat:titleFormat, (long)activeStepDuration];
step.spokenInstruction = step.text;
step.finishedSpokenInstruction = stepFinishedInstruction;
step.stepDuration = activeStepDuration;
step.shouldPlaySoundOnStart = YES;
step.shouldVibrateOnStart = YES;
step.shouldPlaySoundOnFinish = YES;
step.shouldVibrateOnFinish = YES;
step.shouldContinueOnFinish = NO;
step.shouldStartTimerAutomatically = YES;
ORKStepArrayAddStep(steps, step);
}
}
if (!(activeTaskOptions & ORKTremorActiveTaskOptionExcludeHandToNose)) {
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
NSString *stepIdentifier = [self stepIdentifier:ORKInstruction6StepIdentifier withHandIdentifier:handIdentifier];
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_TOUCH_NOSE_INTRO", nil);
step.detailText = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_INTRO_TEXT", nil);
step.image = [UIImage imageNamed:@"tremortest6a" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.auxiliaryImage = [UIImage imageNamed:@"tremortest6b" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
if (leftHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_TOUCH_NOSE_INTRO_LEFT", nil);
step.image = [step.image ork_flippedImage:UIImageOrientationUpMirrored];
step.auxiliaryImage = [step.auxiliaryImage ork_flippedImage:UIImageOrientationUpMirrored];
} else if (rightHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_TOUCH_NOSE_INTRO_RIGHT", nil);
}
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
NSString *stepIdentifier = [self stepIdentifier:ORKCountdown4StepIdentifier withHandIdentifier:handIdentifier];
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
ORKStepArrayAddStep(steps, step);
}
{
NSString *titleFormat = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_TOUCH_NOSE_INSTRUCTION_%ld", nil);
NSString *stepIdentifier = [self stepIdentifier:ORKTremorTestTouchNoseStepIdentifier withHandIdentifier:handIdentifier];
ORKActiveStep *step = [[ORKActiveStep alloc] initWithIdentifier:stepIdentifier];
step.recorderConfigurations = @[[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:@"ac4_acc" frequency:100.0], [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:@"ac4_motion" frequency:100.0]];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = [NSString localizedStringWithFormat:titleFormat, (long)activeStepDuration];
step.spokenInstruction = step.text;
step.finishedSpokenInstruction = stepFinishedInstruction;
step.stepDuration = activeStepDuration;
step.shouldPlaySoundOnStart = YES;
step.shouldVibrateOnStart = YES;
step.shouldPlaySoundOnFinish = YES;
step.shouldVibrateOnFinish = YES;
step.shouldContinueOnFinish = NO;
step.shouldStartTimerAutomatically = YES;
ORKStepArrayAddStep(steps, step);
}
}
if (!(activeTaskOptions & ORKTremorActiveTaskOptionExcludeQueenWave)) {
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
NSString *stepIdentifier = [self stepIdentifier:ORKInstruction7StepIdentifier withHandIdentifier:handIdentifier];
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_TURN_WRIST_INTRO", nil);
step.detailText = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_INTRO_TEXT", nil);
step.image = [UIImage imageNamed:@"tremortest7" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
if (leftHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_TURN_WRIST_INTRO_LEFT", nil);
step.image = [step.image ork_flippedImage:UIImageOrientationUpMirrored];
} else if (rightHand) {
step.text = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_TURN_WRIST_INTRO_RIGHT", nil);
}
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
NSString *stepIdentifier = [self stepIdentifier:ORKCountdown5StepIdentifier withHandIdentifier:handIdentifier];
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:stepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
ORKStepArrayAddStep(steps, step);
}
{
NSString *titleFormat = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_TURN_WRIST_INSTRUCTION_%ld", nil);
NSString *stepIdentifier = [self stepIdentifier:ORKTremorTestTurnWristStepIdentifier withHandIdentifier:handIdentifier];
ORKActiveStep *step = [[ORKActiveStep alloc] initWithIdentifier:stepIdentifier];
step.recorderConfigurations = @[[[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:@"ac5_acc" frequency:100.0], [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:@"ac5_motion" frequency:100.0]];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.text = [NSString localizedStringWithFormat:titleFormat, (long)activeStepDuration];
step.spokenInstruction = step.text;
step.finishedSpokenInstruction = stepFinishedInstruction;
step.stepDuration = activeStepDuration;
step.shouldPlaySoundOnStart = YES;
step.shouldVibrateOnStart = YES;
step.shouldPlaySoundOnFinish = YES;
step.shouldVibrateOnFinish = YES;
step.shouldContinueOnFinish = NO;
step.shouldStartTimerAutomatically = YES;
ORKStepArrayAddStep(steps, step);
}
}
// fix the spoken instruction on the last included step, depending on which hand we're on
ORKActiveStep *lastStep = (ORKActiveStep *)[steps lastObject];
if (lastHand) {
lastStep.finishedSpokenInstruction = ORKLocalizedString(@"TREMOR_TEST_COMPLETED_INSTRUCTION", nil);
} else if (leftHand) {
lastStep.finishedSpokenInstruction = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_SWITCH_HANDS_RIGHT_INSTRUCTION", nil);
} else {
lastStep.finishedSpokenInstruction = ORKLocalizedString(@"TREMOR_TEST_ACTIVE_STEP_SWITCH_HANDS_LEFT_INSTRUCTION", nil);
}
return steps;
}
+ (ORKNavigableOrderedTask *)tremorTestTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
activeStepDuration:(NSTimeInterval)activeStepDuration
activeTaskOptions:(ORKTremorActiveTaskOption)activeTaskOptions
handOptions:(ORKPredefinedTaskHandOption)handOptions
options:(ORKPredefinedTaskOption)options {
NSMutableArray<__kindof ORKStep *> *steps = [NSMutableArray array];
// coin toss for which hand first (in case we're doing both)
BOOL leftFirstIfDoingBoth = arc4random_uniform(2) == 1;
BOOL doingBoth = ((handOptions & ORKPredefinedTaskHandOptionLeft) && (handOptions & ORKPredefinedTaskHandOptionRight));
BOOL firstIsLeft = (leftFirstIfDoingBoth && doingBoth) || (!doingBoth && (handOptions & ORKPredefinedTaskHandOptionLeft));
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"TREMOR_TEST_TITLE", nil);
step.detailText = intendedUseDescription;
step.text = ORKLocalizedString(@"TREMOR_TEST_INTRO_1_DETAIL", nil);
step.image = [UIImage imageNamed:@"tremortest1" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
if (firstIsLeft) {
step.image = [step.image ork_flippedImage:UIImageOrientationUpMirrored];
}
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
// Build the string for the detail texts
NSArray<NSString *>*detailStringForNumberOfTasks = @[
ORKLocalizedString(@"TREMOR_TEST_INTRO_2_DETAIL_1_TASK", nil),
ORKLocalizedString(@"TREMOR_TEST_INTRO_2_DETAIL_2_TASK", nil),
ORKLocalizedString(@"TREMOR_TEST_INTRO_2_DETAIL_3_TASK", nil),
ORKLocalizedString(@"TREMOR_TEST_INTRO_2_DETAIL_4_TASK", nil),
ORKLocalizedString(@"TREMOR_TEST_INTRO_2_DETAIL_5_TASK", nil)
];
// start with the count for all the tasks, then subtract one for each excluded task flag
static const NSInteger allTasks = 5; // hold in lap, outstretched arm, elbow bent, repeatedly touching nose, queen wave
NSInteger actualTasksIndex = allTasks - 1;
for (NSInteger i = 0; i < allTasks; ++i) {
if (activeTaskOptions & (1 << i)) {
actualTasksIndex--;
}
}
NSString *detailFormat = doingBoth ? ORKLocalizedString(@"TREMOR_TEST_SKIP_QUESTION_BOTH_HANDS_%@", nil) : ORKLocalizedString(@"TREMOR_TEST_INTRO_2_DETAIL_DEFAULT_%@", nil);
NSString *detailText = [NSString localizedStringWithFormat:detailFormat, detailStringForNumberOfTasks[actualTasksIndex]];
if (doingBoth) {
// If doing both hands then ask the user if they need to skip one of the hands
ORKTextChoice *skipRight = [ORKTextChoice choiceWithText:ORKLocalizedString(@"TREMOR_SKIP_RIGHT_HAND", nil)
value:ORKActiveTaskRightHandIdentifier];
ORKTextChoice *skipLeft = [ORKTextChoice choiceWithText:ORKLocalizedString(@"TREMOR_SKIP_LEFT_HAND", nil)
value:ORKActiveTaskLeftHandIdentifier];
ORKTextChoice *skipNeither = [ORKTextChoice choiceWithText:ORKLocalizedString(@"TREMOR_SKIP_NEITHER", nil)
value:@""];
ORKAnswerFormat *answerFormat = [ORKAnswerFormat choiceAnswerFormatWithStyle:ORKChoiceAnswerStyleSingleChoice
textChoices:@[skipRight, skipLeft, skipNeither]];
ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:ORKActiveTaskSkipHandStepIdentifier
title:ORKLocalizedString(@"TREMOR_TEST_TITLE", nil)
question:detailText
answer:answerFormat];
step.optional = NO;
ORKStepArrayAddStep(steps, step);
}
// right or most-affected hand
NSArray<__kindof ORKStep *> *rightSteps = nil;
if (handOptions == ORKPredefinedTaskHandOptionUnspecified) {
rightSteps = [self stepsForOneHandTremorTestTaskWithIdentifier:identifier
activeStepDuration:activeStepDuration
activeTaskOptions:activeTaskOptions
lastHand:YES
leftHand:NO
handIdentifier:ORKActiveTaskMostAffectedHandIdentifier
introDetailText:detailText
options:options];
} else if (handOptions & ORKPredefinedTaskHandOptionRight) {
rightSteps = [self stepsForOneHandTremorTestTaskWithIdentifier:identifier
activeStepDuration:activeStepDuration
activeTaskOptions:activeTaskOptions
lastHand:firstIsLeft
leftHand:NO
handIdentifier:ORKActiveTaskRightHandIdentifier
introDetailText:nil
options:options];
}
// left hand
NSArray<__kindof ORKStep *> *leftSteps = nil;
if (handOptions & ORKPredefinedTaskHandOptionLeft) {
leftSteps = [self stepsForOneHandTremorTestTaskWithIdentifier:identifier
activeStepDuration:activeStepDuration
activeTaskOptions:activeTaskOptions
lastHand:!firstIsLeft || !(handOptions & ORKPredefinedTaskHandOptionRight)
leftHand:YES
handIdentifier:ORKActiveTaskLeftHandIdentifier
introDetailText:nil
options:options];
}
if (firstIsLeft && leftSteps != nil) {
[steps addObjectsFromArray:leftSteps];
}
if (rightSteps != nil) {
[steps addObjectsFromArray:rightSteps];
}
if (!firstIsLeft && leftSteps != nil) {
[steps addObjectsFromArray:leftSteps];
}
BOOL hasCompletionStep = NO;
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
hasCompletionStep = YES;
ORKCompletionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKNavigableOrderedTask *task = [[ORKNavigableOrderedTask alloc] initWithIdentifier:identifier steps:steps];
if (doingBoth) {
// Setup rules for skipping all the steps in either the left or right hand if called upon to do so.
ORKResultSelector *resultSelector = [ORKResultSelector selectorWithStepIdentifier:ORKActiveTaskSkipHandStepIdentifier
resultIdentifier:ORKActiveTaskSkipHandStepIdentifier];
NSPredicate *predicateRight = [ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector expectedAnswerValue:ORKActiveTaskRightHandIdentifier];
NSPredicate *predicateLeft = [ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector expectedAnswerValue:ORKActiveTaskLeftHandIdentifier];
// Setup rule for skipping first hand
NSString *secondHandIdentifier = firstIsLeft ? [[rightSteps firstObject] identifier] : [[leftSteps firstObject] identifier];
NSPredicate *firstPredicate = firstIsLeft ? predicateLeft : predicateRight;
ORKStepNavigationRule *skipFirst = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[firstPredicate]
destinationStepIdentifiers:@[secondHandIdentifier]];
[task setNavigationRule:skipFirst forTriggerStepIdentifier:ORKActiveTaskSkipHandStepIdentifier];
// Setup rule for skipping the second hand
NSString *triggerIdentifier = firstIsLeft ? [[leftSteps lastObject] identifier] : [[rightSteps lastObject] identifier];
NSString *conclusionIdentifier = hasCompletionStep ? [[steps lastObject] identifier] : ORKNullStepIdentifier;
NSPredicate *secondPredicate = firstIsLeft ? predicateRight : predicateLeft;
ORKStepNavigationRule *skipSecond = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[secondPredicate]
destinationStepIdentifiers:@[conclusionIdentifier]];
[task setNavigationRule:skipSecond forTriggerStepIdentifier:triggerIdentifier];
// Setup step modifier to change the finished spoken step if skipping the second hand
NSString *key = NSStringFromSelector(@selector(finishedSpokenInstruction));
NSString *value = ORKLocalizedString(@"TREMOR_TEST_COMPLETED_INSTRUCTION", nil);
ORKStepModifier *stepModifier = [[ORKKeyValueStepModifier alloc] initWithResultPredicate:secondPredicate
keyValueMap:@{key: value}];
[task setStepModifier:stepModifier forStepIdentifier:triggerIdentifier];
}
return task;
}
#pragma mark - trailmakingTask
NSString *const ORKTrailmakingStepIdentifier = @"trailmaking";
+ (ORKOrderedTask *)trailmakingTaskWithIdentifier:(NSString *)identifier
intendedUseDescription:(nullable NSString *)intendedUseDescription
trailmakingInstruction:(nullable NSString *)trailmakingInstruction
trailType:(ORKTrailMakingTypeIdentifier)trailType
options:(ORKPredefinedTaskOption)options {
NSMutableArray<__kindof ORKStep *> *steps = [NSMutableArray array];
if (!(options & ORKPredefinedTaskOptionExcludeInstructions)) {
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction0StepIdentifier];
step.title = ORKLocalizedString(@"TRAILMAKING_TASK_TITLE", nil);
step.text = intendedUseDescription;
step.detailText = ORKLocalizedString(@"TRAILMAKING_INTENDED_USE", nil);
step.image = [UIImage imageNamed:@"trailmaking" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction1StepIdentifier];
step.title = ORKLocalizedString(@"TRAILMAKING_TASK_TITLE", nil);
if ([trailType isEqualToString:ORKTrailMakingTypeIdentifierA]) {
step.detailText = ORKLocalizedString(@"TRAILMAKING_INTENDED_USE2_A", nil);
} else {
step.detailText = ORKLocalizedString(@"TRAILMAKING_INTENDED_USE2_B", nil);
}
step.image = [UIImage imageNamed:@"trailmaking" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
{
ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:ORKInstruction2StepIdentifier];
step.title = ORKLocalizedString(@"TRAILMAKING_TASK_TITLE", nil);
step.text = trailmakingInstruction ? : ORKLocalizedString(@"TRAILMAKING_INTRO_TEXT", nil);
step.detailText = ORKLocalizedString(@"TRAILMAKING_CALL_TO_ACTION", nil);
if (UIAccessibilityIsVoiceOverRunning()) {
step.detailText = [NSString stringWithFormat:ORKLocalizedString(@"AX_TRAILMAKING_CALL_TO_ACTION_VOICEOVER", nil), step.detailText];
}
step.image = [UIImage imageNamed:@"trailmaking" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
step.imageContentMode = UIViewContentModeCenter;
step.shouldTintImages = YES;
step.shouldAutomaticallyAdjustImageTintColor = YES;
ORKStepArrayAddStep(steps, step);
}
}
{
ORKCountdownStep *step = [[ORKCountdownStep alloc] initWithIdentifier:ORKCountdownStepIdentifier];
step.title = ORKLocalizedString(@"TRAILMAKING_TASK_TITLE", nil);
step.stepDuration = 3.0;
ORKStepArrayAddStep(steps, step);
}
{
ORKTrailmakingStep *step = [[ORKTrailmakingStep alloc] initWithIdentifier:ORKTrailmakingStepIdentifier];
step.title = ORKLocalizedString(@"TRAILMAKING_TASK_TITLE", nil);
step.trailType = trailType;
ORKStepArrayAddStep(steps, step);
}
if (!(options & ORKPredefinedTaskOptionExcludeConclusion)) {
ORKInstructionStep *step = [self makeCompletionStep];
ORKStepArrayAddStep(steps, step);
}
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:identifier steps:steps];
return task;
}
@end