From af0e942dd4b16cd8f632a80149d1a0fa1ce8e8ba Mon Sep 17 00:00:00 2001 From: Pascal Pfiffner Date: Mon, 11 May 2015 17:48:32 -0400 Subject: [PATCH] Start `APCConsentManager` to modularize consenting cf. ResearchKit/AppCore#41 --- .../APCAppCore.xcodeproj/project.pbxproj | 8 + APCAppCore/APCAppCore/APCAppCore.h | 1 + .../APCAppCore/Consent/APCConsentManager.h | 63 ++++++ .../APCAppCore/Consent/APCConsentManager.m | 184 ++++++++++++++++++ .../Library/Categories/NSError+Bridge.m | 1 + .../APCAppCore/Startup/APCAppDelegate.h | 5 +- .../APCAppCore/Startup/APCAppDelegate.m | 5 + .../Profile/APCProfileViewController.m | 33 ++-- 8 files changed, 283 insertions(+), 17 deletions(-) create mode 100644 APCAppCore/APCAppCore/Consent/APCConsentManager.h create mode 100644 APCAppCore/APCAppCore/Consent/APCConsentManager.m diff --git a/APCAppCore/APCAppCore.xcodeproj/project.pbxproj b/APCAppCore/APCAppCore.xcodeproj/project.pbxproj index dadb029b..443a5dbd 100644 --- a/APCAppCore/APCAppCore.xcodeproj/project.pbxproj +++ b/APCAppCore/APCAppCore.xcodeproj/project.pbxproj @@ -326,6 +326,8 @@ EE028FE41AF94B36001C8251 /* APCKeychainStore+Passcode.m in Sources */ = {isa = PBXBuildFile; fileRef = EE028FE21AF94B36001C8251 /* APCKeychainStore+Passcode.m */; }; EE4B95251AF82BA6000097C7 /* NSError+Bridge.h in Headers */ = {isa = PBXBuildFile; fileRef = EE4B95231AF82BA6000097C7 /* NSError+Bridge.h */; }; EE4B95261AF82BA6000097C7 /* NSError+Bridge.m in Sources */ = {isa = PBXBuildFile; fileRef = EE4B95241AF82BA6000097C7 /* NSError+Bridge.m */; }; + EEC608AC1B0157680028BEB2 /* APCConsentManager.h in Headers */ = {isa = PBXBuildFile; fileRef = EEC608AA1B0157680028BEB2 /* APCConsentManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EEC608AD1B0157680028BEB2 /* APCConsentManager.m in Sources */ = {isa = PBXBuildFile; fileRef = EEC608AB1B0157680028BEB2 /* APCConsentManager.m */; }; F50738C01A682E12004CF100 /* APCDateRange.h in Headers */ = {isa = PBXBuildFile; fileRef = F50738BE1A682E12004CF100 /* APCDateRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; F50738C11A682E12004CF100 /* APCDateRange.m in Sources */ = {isa = PBXBuildFile; fileRef = F50738BF1A682E12004CF100 /* APCDateRange.m */; }; F5306CCD1A8BE7F600732E60 /* ORKQuestionResult+APCHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = F5306CCB1A8BE7F600732E60 /* ORKQuestionResult+APCHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1013,6 +1015,8 @@ EE028FE21AF94B36001C8251 /* APCKeychainStore+Passcode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "APCKeychainStore+Passcode.m"; sourceTree = ""; }; EE4B95231AF82BA6000097C7 /* NSError+Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+Bridge.h"; sourceTree = ""; }; EE4B95241AF82BA6000097C7 /* NSError+Bridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+Bridge.m"; sourceTree = ""; }; + EEC608AA1B0157680028BEB2 /* APCConsentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APCConsentManager.h; sourceTree = ""; }; + EEC608AB1B0157680028BEB2 /* APCConsentManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APCConsentManager.m; sourceTree = ""; }; F50738BE1A682E12004CF100 /* APCDateRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APCDateRange.h; sourceTree = ""; }; F50738BF1A682E12004CF100 /* APCDateRange.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APCDateRange.m; sourceTree = ""; }; F5179B2919D09128001DCCB7 /* APCAppCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = APCAppCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1743,6 +1747,8 @@ 7B6C8CAC1AA26ECE0007B560 /* Consent */ = { isa = PBXGroup; children = ( + EEC608AA1B0157680028BEB2 /* APCConsentManager.h */, + EEC608AB1B0157680028BEB2 /* APCConsentManager.m */, 7B6C8CB31AA26ECE0007B560 /* APCConsentTask.h */, 7B6C8CB41AA26ECE0007B560 /* APCConsentTask.m */, 7B6C8CB11AA26ECE0007B560 /* APCConsentQuestion.h */, @@ -3157,6 +3163,7 @@ 08970F121A8D407600EA46C3 /* APCFoodInsight.h in Headers */, 7B6C8CB71AA26ECE0007B560 /* APCConsentBooleanQuestion.h in Headers */, 5B827B4C1A80A39900C685A3 /* APCDashboardMoreInfoViewController.h in Headers */, + EEC608AC1B0157680028BEB2 /* APCConsentManager.h in Headers */, 369E27FA1A96B7A200D35DFA /* APCMedicationUltraSimpleSelfInflator.h in Headers */, CFBD289A1AA4408800F49161 /* APCMedicationNameTableViewCell.h in Headers */, 369E280C1A96B7A200D35DFA /* APCMedTrackerPrescription+Helper.h in Headers */, @@ -3485,6 +3492,7 @@ F5B948051A73272C0034C522 /* APCPointSelector.m in Sources */, F5F12AAD1A2F78490015982C /* APCSignUpGeneralInfoViewController.m in Sources */, F5B948151A73272C0034C522 /* APCScoring.m in Sources */, + EEC608AD1B0157680028BEB2 /* APCConsentManager.m in Sources */, F5B947B81A73272C0034C522 /* APCStepProgressBar+Appearance.m in Sources */, CFFDEDFB1A95734000B25581 /* APCSetupTableViewCell.m in Sources */, 7B8C20141AA3AB8600BFEFDA /* APCTheme.m in Sources */, diff --git a/APCAppCore/APCAppCore/APCAppCore.h b/APCAppCore/APCAppCore/APCAppCore.h index aba8f9df..261db57a 100644 --- a/APCAppCore/APCAppCore/APCAppCore.h +++ b/APCAppCore/APCAppCore/APCAppCore.h @@ -61,6 +61,7 @@ FOUNDATION_EXPORT const unsigned char APCAppCoreVersionString[]; #import // Tasks +#import #import #import #import diff --git a/APCAppCore/APCAppCore/Consent/APCConsentManager.h b/APCAppCore/APCAppCore/Consent/APCConsentManager.h new file mode 100644 index 00000000..fa498f9b --- /dev/null +++ b/APCAppCore/APCAppCore/Consent/APCConsentManager.h @@ -0,0 +1,63 @@ +// +// APCConsentManager.h +// APCAppCore +// +// Copyright (c) 2015, Apple, Inc. All rights reserved. +// Copyright (c) 2015, Boston Children's Hospital. All rights reserved. +// +// 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 + +@class APCConsentManager; + + +/** + * Protocol to be implemented by the app delegate. + */ +@protocol APCConsentManagerDelegate + +@required +/// The app's consent manager +- (APCConsentManager *)consentManager; + +@end + + +/** + * The app holds on to an instance of this class to handle consent related tasks. + */ +@interface APCConsentManager : NSObject + +/** The name of the JSON file, not including the .json extension, of the consent configuration file in the app bundle. */ +- (NSString *)configurationFileName; + +/** Return the consent sections, as defined in `fileName`.json. */ +- (NSArray *)consentSectionsAndHtmlContent:(NSString **)htmlContent; + +@end diff --git a/APCAppCore/APCAppCore/Consent/APCConsentManager.m b/APCAppCore/APCAppCore/Consent/APCConsentManager.m new file mode 100644 index 00000000..4159299b --- /dev/null +++ b/APCAppCore/APCAppCore/Consent/APCConsentManager.m @@ -0,0 +1,184 @@ +// +// APCConsentManager.m +// APCAppCore +// +// Copyright (c) 2015, Apple, Inc. All rights reserved. +// Copyright (c) 2015, Boston Children's Hospital. All rights reserved. +// +// 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 "APCConsentManager.h" +#import + + +@implementation APCConsentManager + + +- (NSString *)configurationFileName +{ + return @"APHConsentSection"; // Keeping "APH" to not break backwards compatibility, should be "APC" +} + +- (NSArray *)consentSectionsAndHtmlContent:(NSString **)htmlContent +{ + ORKConsentSectionType(^toSectionType)(NSString*) = ^(NSString* sectionTypeName) { + ORKConsentSectionType sectionType = ORKConsentSectionTypeCustom; + + if ([sectionTypeName isEqualToString:@"overview"]) { + sectionType = ORKConsentSectionTypeOverview; + } else if ([sectionTypeName isEqualToString:@"privacy"]) { + sectionType = ORKConsentSectionTypePrivacy; + } else if ([sectionTypeName isEqualToString:@"dataGathering"]) { + sectionType = ORKConsentSectionTypeDataGathering; + } else if ([sectionTypeName isEqualToString:@"dataUse"]) { + sectionType = ORKConsentSectionTypeDataUse; + } else if ([sectionTypeName isEqualToString:@"timeCommitment"]) { + sectionType = ORKConsentSectionTypeTimeCommitment; + } else if ([sectionTypeName isEqualToString:@"studySurvey"]) { + sectionType = ORKConsentSectionTypeStudySurvey; + } else if ([sectionTypeName isEqualToString:@"studyTasks"]) { + sectionType = ORKConsentSectionTypeStudyTasks; + } else if ([sectionTypeName isEqualToString:@"withdrawing"]) { + sectionType = ORKConsentSectionTypeWithdrawing; + } else if ([sectionTypeName isEqualToString:@"custom"]) { + sectionType = ORKConsentSectionTypeCustom; + } else if ([sectionTypeName isEqualToString:@"onlyInDocument"]) { + sectionType = ORKConsentSectionTypeOnlyInDocument; + } + + return sectionType; + }; + + NSString *kDocumentHtml = @"htmlDocument"; + NSString *kConsentSections = @"sections"; + NSString *kSectionType = @"sectionType"; + NSString *kSectionTitle = @"sectionTitle"; + NSString *kSectionFormalTitle = @"sectionFormalTitle"; + NSString *kSectionSummary = @"sectionSummary"; + NSString *kSectionContent = @"sectionContent"; + NSString *kSectionHtmlContent = @"sectionHtmlContent"; + NSString *kSectionImage = @"sectionImage"; + NSString *kSectionAnimationUrl = @"sectionAnimationUrl"; + + NSString *resource = [[NSBundle bundleForClass:[self class]] pathForResource:[self configurationFileName] ofType:@"json"]; + NSAssert(resource, @"Unable to locate file \"%@.json\" with Consent Section data in bundle, as defined in `configurationFileName`", [self configurationFileName]); + + NSData *consentSectionData = [NSData dataWithContentsOfFile:resource]; + NSAssert(consentSectionData, @"Unable to create NSData with Consent Section data"); + + NSError *error = nil; + NSDictionary *consentParameters = [NSJSONSerialization JSONObjectWithData:consentSectionData options:NSJSONReadingMutableContainers error:&error]; + NSAssert(consentParameters, @"badly formed Consent Section data - error", error); + + NSString *documentHtmlContent = consentParameters[kDocumentHtml]; + NSAssert(documentHtmlContent == nil || documentHtmlContent && [documentHtmlContent isKindOfClass:[NSString class]], @"Improper Document HTML Content type"); + + if (documentHtmlContent != nil && htmlContent != nil) { + NSString *path = [[NSBundle mainBundle] pathForResource:documentHtmlContent ofType:@"html" inDirectory:@"HTMLContent"]; + NSAssert(path != nil, @"Unable to locate HTML file: %@", documentHtmlContent); + + NSError *error = nil; + NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; + + NSAssert(content != nil, @"Unable to load content of file \"%@\": %@", path, error); + + *htmlContent = content; + } + + NSArray *parametersConsentSections = consentParameters[kConsentSections]; + NSAssert(parametersConsentSections != nil && [parametersConsentSections isKindOfClass:[NSArray class]], @"Badly formed Consent Section data"); + + NSMutableArray *consentSections = [NSMutableArray arrayWithCapacity:parametersConsentSections.count]; + + for (NSDictionary *section in parametersConsentSections) { + // Custom types do not have predefined title, summary, content, or animation + NSAssert([section isKindOfClass:[NSDictionary class]], @"Improper section type"); + + NSString *typeName = section[kSectionType]; + NSAssert(typeName != nil && [typeName isKindOfClass:[NSString class]], @"Missing Section Type or improper type"); + + ORKConsentSectionType sectionType = toSectionType(typeName); + + NSString *title = section[kSectionTitle]; + NSString *formalTitle = section[kSectionFormalTitle]; + NSString *summary = section[kSectionSummary]; + NSString *content = section[kSectionContent]; + NSString *htmlContent = section[kSectionHtmlContent]; + NSString *image = section[kSectionImage]; + NSString *animationUrl = section[kSectionAnimationUrl]; + + NSAssert(title == nil || title != nil && [title isKindOfClass:[NSString class]], @"Missing Section Title or improper type"); + NSAssert(formalTitle == nil || formalTitle != nil && [formalTitle isKindOfClass:[NSString class]], @"Missing Section Formal title or improper type"); + NSAssert(summary == nil || summary != nil && [summary isKindOfClass:[NSString class]], @"Missing Section Summary or improper type"); + NSAssert(content == nil || content != nil && [content isKindOfClass:[NSString class]], @"Missing Section Content or improper type"); + NSAssert(htmlContent == nil || htmlContent != nil && [htmlContent isKindOfClass:[NSString class]], @"Missing Section HTML Content or improper type"); + NSAssert(image == nil || image != nil && [image isKindOfClass:[NSString class]], @"Missing Section Image or improper typte"); + NSAssert(animationUrl == nil || animationUrl != nil && [animationUrl isKindOfClass:[NSString class]], @"Missing Animation URL or improper type"); + + ORKConsentSection *section = [[ORKConsentSection alloc] initWithType:sectionType]; + section.title = title; + section.formalTitle = formalTitle; + section.summary = summary; + section.content = content; + + if (htmlContent != nil) { + NSString *path = [[NSBundle mainBundle] pathForResource:htmlContent ofType:@"html" inDirectory:@"HTMLContent"]; + NSAssert(path, @"Unable to locate HTML file: %@", htmlContent); + + NSError *error = nil; + NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; + + NSAssert(content, @"Unable to load content of file \"%@\": %@", path, error); + section.htmlContent = content; + } + if (image != nil) { + section.customImage = [UIImage imageNamed:image]; + NSAssert(section.customImage != nil, @"Unable to load image: %@", image); + } + if (animationUrl != nil) { + NSString *nameWithScaleFactor = animationUrl; + if ([[UIScreen mainScreen] scale] >= 3) { + nameWithScaleFactor = [nameWithScaleFactor stringByAppendingString:@"@3x"]; + } else { + nameWithScaleFactor = [nameWithScaleFactor stringByAppendingString:@"@2x"]; + } + NSURL *url = [[NSBundle mainBundle] URLForResource:nameWithScaleFactor withExtension:@"m4v"]; + NSError *error = nil; + + NSAssert([url checkResourceIsReachableAndReturnError:&error], @"Animation file--%@--not reachable: %@", animationUrl, error); + section.customAnimationURL = url; + } + + [consentSections addObject:section]; + } + + return consentSections; +} + + +@end diff --git a/APCAppCore/APCAppCore/Library/Categories/NSError+Bridge.m b/APCAppCore/APCAppCore/Library/Categories/NSError+Bridge.m index 73938a53..89e01c6d 100644 --- a/APCAppCore/APCAppCore/Library/Categories/NSError+Bridge.m +++ b/APCAppCore/APCAppCore/Library/Categories/NSError+Bridge.m @@ -32,6 +32,7 @@ // #import "NSError+Bridge.h" +#import "APCLog.h" #import static NSString *kSageMessageKey = @"message"; diff --git a/APCAppCore/APCAppCore/Startup/APCAppDelegate.h b/APCAppCore/APCAppCore/Startup/APCAppDelegate.h index 6547aedc..e398c237 100644 --- a/APCAppCore/APCAppCore/Startup/APCAppDelegate.h +++ b/APCAppCore/APCAppCore/Startup/APCAppDelegate.h @@ -36,13 +36,14 @@ #import "APCOnboarding.h" #import "APCPasscodeViewController.h" #import "APCProfileViewController.h" +#import "APCConsentManager.h" #import "APCConsentTask.h" extern NSUInteger const kTheEntireDataModelOfTheApp; @class APCDataSubstrate, APCDataMonitor, APCScheduler, APCOnboarding, APCPasscodeViewController, APCTasksReminderManager, APCPassiveDataCollector, APCFitnessAllocation; -@interface APCAppDelegate : UIResponder +@interface APCAppDelegate : UIResponder @property (nonatomic, strong) APCFitnessAllocation *sevenDayFitnessAllocationData; @property (strong, nonatomic) UITabBarController *tabster; @@ -89,7 +90,6 @@ extern NSUInteger const kTheEntireDataModelOfTheApp; - (void) setUpInitializationOptions; - (void) setUpAppAppearance; - (void) registerCatastrophicStartupError: (NSError *) error; -- (void) configureObserverQueries; //For User in Subclasses - (void) signedInNotification:(NSNotification *)notification; @@ -110,7 +110,6 @@ extern NSUInteger const kTheEntireDataModelOfTheApp; - (void)showPasscodeIfNecessary; - (ORKTaskViewController *)consentViewController; -- (NSMutableArray*)consentSectionsAndHtmlContent:(NSString**)htmlContent; - (void)instantiateOnboardingForType:(APCOnboardingTaskType)type; diff --git a/APCAppCore/APCAppCore/Startup/APCAppDelegate.m b/APCAppCore/APCAppCore/Startup/APCAppDelegate.m index 9921afe9..f636526b 100644 --- a/APCAppCore/APCAppCore/Startup/APCAppDelegate.m +++ b/APCAppCore/APCAppCore/Startup/APCAppDelegate.m @@ -645,6 +645,11 @@ - (NSArray *)reviewConsentActions return nil; } +- (APCConsentManager *)consentManager +{ + return [APCConsentManager new]; +} + // The block of text for the All Set - (NSArray *)allSetTextBlocks { diff --git a/APCAppCore/APCAppCore/UI/TabBarControllers/Profile/APCProfileViewController.m b/APCAppCore/APCAppCore/UI/TabBarControllers/Profile/APCProfileViewController.m index 9a0c78a0..0dd53c3c 100644 --- a/APCAppCore/APCAppCore/UI/TabBarControllers/Profile/APCProfileViewController.m +++ b/APCAppCore/APCAppCore/UI/TabBarControllers/Profile/APCProfileViewController.m @@ -43,7 +43,8 @@ #import "APCSettingsViewController.h" #import "APCSpinnerViewController.h" #import "APCTableViewItem.h" -#import "APCAppDelegate.h" +#import "APCConsentManager.h" +#import "APCTasksReminderManager.h" #import "APCUserInfoConstants.h" #import "APCDataSubstrate.h" #import "APCConstants.h" @@ -63,6 +64,11 @@ #import +// the following dependencies should be removed when refactoring +#import "APCAppDelegate.h" +#import "APCUser+Bridge.h" +#import + static CGFloat const kSectionHeaderHeight = 40.f; static CGFloat const kStudyDetailsViewHeightConstant = 48.f; static CGFloat const kPickerCellHeight = 164.0f; @@ -1588,24 +1594,23 @@ - (void)reviewConsent - (void)showConsentSlides { - APCAppDelegate * appDelegate = (APCAppDelegate*) [UIApplication sharedApplication].delegate; - - NSArray* sections = [appDelegate consentSectionsAndHtmlContent:nil]; - ORKConsentDocument* consent = [[ORKConsentDocument alloc] init]; - ORKConsentSignature* signature = [ORKConsentSignature signatureForPersonWithTitle:NSLocalizedString(@"Participant", nil) - dateFormatString:nil - identifier:@"participant"]; + APCConsentManager *manager = [(APCAppDelegate *)[UIApplication sharedApplication].delegate consentManager]; + NSArray *sections = [manager consentSectionsAndHtmlContent:nil]; - consent.title = NSLocalizedString(@"Consent", nil); - consent.signaturePageTitle = NSLocalizedString(@"Consent", nil); + ORKConsentDocument *consent = [[ORKConsentDocument alloc] init]; + consent.title = NSLocalizedString(@"Consent", nil); + consent.signaturePageTitle = NSLocalizedString(@"Consent", nil); consent.signaturePageContent = NSLocalizedString(@"I agree to participate in this research Study.", nil); - consent.sections = sections; + consent.sections = sections; + ORKConsentSignature *signature = [ORKConsentSignature signatureForPersonWithTitle:NSLocalizedString(@"Participant", nil) + dateFormatString:nil + identifier:@"participant"]; [consent addSignature:signature]; - ORKVisualConsentStep* step = [[ORKVisualConsentStep alloc] initWithIdentifier:@"visual" document:consent]; - ORKOrderedTask* task = [[ORKOrderedTask alloc] initWithIdentifier:@"consent" steps:@[step]]; - ORKTaskViewController* consentVC = [[ORKTaskViewController alloc] initWithTask:task taskRunUUID:[NSUUID UUID]]; + ORKVisualConsentStep *step = [[ORKVisualConsentStep alloc] initWithIdentifier:@"visual" document:consent]; + ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:@"consent" steps:@[step]]; + ORKTaskViewController *consentVC = [[ORKTaskViewController alloc] initWithTask:task taskRunUUID:[NSUUID UUID]]; consentVC.navigationBar.topItem.title = NSLocalizedString(@"Consent", nil); consentVC.delegate = self;