Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/attributedstring question step #1408

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 24 additions & 24 deletions ResearchKit.xcodeproj/project.pbxproj
Expand Up @@ -1493,7 +1493,7 @@
86C40B9D1A8D7C5C00081FAC /* ORKOrderedTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKOrderedTask.h; sourceTree = "<group>"; };
86C40B9E1A8D7C5C00081FAC /* ORKOrderedTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ORKOrderedTask.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BA11A8D7C5C00081FAC /* ORKQuestionStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKQuestionStep.h; sourceTree = "<group>"; };
86C40BA21A8D7C5C00081FAC /* ORKQuestionStep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ORKQuestionStep.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BA21A8D7C5C00081FAC /* ORKQuestionStep.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ORKQuestionStep.m; sourceTree = "<group>"; tabWidth = 4; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BA31A8D7C5C00081FAC /* ORKQuestionStep_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKQuestionStep_Internal.h; sourceTree = "<group>"; };
86C40BA41A8D7C5C00081FAC /* ORKQuestionStepViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKQuestionStepViewController.h; sourceTree = "<group>"; };
86C40BA51A8D7C5C00081FAC /* ORKQuestionStepViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ORKQuestionStepViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
Expand Down Expand Up @@ -2339,6 +2339,29 @@
name = "Custom Vision View";
sourceTree = "<group>";
};
51198798245FC31C004FC2C7 /* 3D Model Manager */ = {
isa = PBXGroup;
children = (
51198799245FC33C004FC2C7 /* ORK3DModelManager.h */,
5D26E77724997EA200E53D27 /* ORK3DModelManager_Internal.h */,
5119879A245FC33C004FC2C7 /* ORK3DModelManager.m */,
);
name = "3D Model Manager";
sourceTree = "<group>";
};
511987B624612C95004FC2C7 /* USDZ Model Manager */ = {
isa = PBXGroup;
children = (
51198767245CA50D004FC2C7 /* ORKUSDZModelManagerScene.h */,
51198768245CA50D004FC2C7 /* ORKUSDZModelManagerScene.m */,
5119879D245FE68D004FC2C7 /* ORKUSDZModelManager.h */,
5119879E245FE68D004FC2C7 /* ORKUSDZModelManager.m */,
5166E49D247355D500151C57 /* ORKUSDZModelManagerResult.h */,
5166E49E247355D500151C57 /* ORKUSDZModelManagerResult.m */,
);
name = "USDZ Model Manager";
sourceTree = "<group>";
};
511987C024632E33004FC2C7 /* Request Permissions Step */ = {
isa = PBXGroup;
children = (
Expand All @@ -2364,29 +2387,6 @@
name = "Vision Tasks";
sourceTree = "<group>";
};
51198798245FC31C004FC2C7 /* 3D Model Manager */ = {
isa = PBXGroup;
children = (
51198799245FC33C004FC2C7 /* ORK3DModelManager.h */,
5D26E77724997EA200E53D27 /* ORK3DModelManager_Internal.h */,
5119879A245FC33C004FC2C7 /* ORK3DModelManager.m */,
);
name = "3D Model Manager";
sourceTree = "<group>";
};
511987B624612C95004FC2C7 /* USDZ Model Manager */ = {
isa = PBXGroup;
children = (
51198767245CA50D004FC2C7 /* ORKUSDZModelManagerScene.h */,
51198768245CA50D004FC2C7 /* ORKUSDZModelManagerScene.m */,
5119879D245FE68D004FC2C7 /* ORKUSDZModelManager.h */,
5119879E245FE68D004FC2C7 /* ORKUSDZModelManager.m */,
5166E49D247355D500151C57 /* ORKUSDZModelManagerResult.h */,
5166E49E247355D500151C57 /* ORKUSDZModelManagerResult.m */,
);
name = "USDZ Model Manager";
sourceTree = "<group>";
};
5175144B2459EBD3009E8FFC /* 3D Model */ = {
isa = PBXGroup;
children = (
Expand Down
4 changes: 3 additions & 1 deletion ResearchKit/Common/ORKCustomStepView.h
Expand Up @@ -58,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
Typically, you subclass `ORKQuestionStepCustomView` only when you need to implement a new
answer format for the survey engine.

To ensure that your subclass is allocated the display space it requires, you should implement
To ensure that your subclass is allocated the display space it requires, you should implement
`sizeThatFits:`, or include internal constraints, or report an intrinsic content size.
*/
ORK_CLASS_AVAILABLE
Expand Down Expand Up @@ -86,6 +86,8 @@ ORK_CLASS_AVAILABLE

- (void)useCardViewWithTitle:(NSString *)title detailText:(nullable NSString *)detailText learnMoreView:(nullable ORKLearnMoreView *)learnMoreView progressText:(nullable NSString *)progressText tagText:(nullable NSString *)tagText hasMultipleChoiceFormItem:(BOOL)hasMultipleChoiceFormItem;

- (void)useCardViewWithAttributedTitle:(NSAttributedString *)attributedTitle detailText:(nullable NSString *)detailText learnMoreView:(nullable ORKLearnMoreView *)learnMoreView progressText:(nullable NSString *)progressText tagText:(nullable NSString *)tagText hasMultipleChoiceFormItem:(BOOL)hasMultipleChoiceFormItem;

@end

NS_ASSUME_NONNULL_END
22 changes: 22 additions & 0 deletions ResearchKit/Common/ORKCustomStepView.m
Expand Up @@ -77,6 +77,7 @@ @implementation ORKQuestionStepCellHolderView {
BOOL _useCardView;
NSArray<NSLayoutConstraint *> *_containerConstraints;
NSString *_title;
NSAttributedString *_attributedTitle;
}

- (instancetype)init {
Expand Down Expand Up @@ -113,6 +114,18 @@ - (void)setupHeaderViewWithTitle:(NSString *)title detailText:(nullable NSString
}
}

- (void)setupHeaderViewWithAttributedTitle:(NSAttributedString *)attributedTitle detailText:(nullable NSString *)detailText learnMoreView:(nullable ORKLearnMoreView *)learnMoreView progressText:(nullable NSString *)progressText hasMultipleChoiceFormItem:(BOOL)hasMultipleChoiceFormItem {
if (!_cardHeaderView) {
_cardHeaderView = [[ORKSurveyCardHeaderView alloc]initWithAttributedTitle:attributedTitle detailText:detailText learnMoreView:learnMoreView progressText:progressText tagText:nil showBorder:NO hasMultipleChoiceItem:hasMultipleChoiceFormItem];
}
_cardHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_cardHeaderView];
if (!attributedTitle) {
[_cardHeaderView removeFromSuperview];
_cardHeaderView = nil;
}
}

- (void)tapAction {
[_cell becomeFirstResponder];
}
Expand Down Expand Up @@ -142,6 +155,15 @@ - (void)useCardViewWithTitle:(NSString *)title detailText:(NSString *)detailText
[self setupConstraints];
}

-(void)useCardViewWithAttributedTitle:(NSAttributedString *)attributedTitle detailText:(NSString *)detailText learnMoreView:(ORKLearnMoreView *)learnMoreView progressText:(NSString *)progressText tagText:(NSString *)tagText hasMultipleChoiceFormItem:(BOOL)hasMultipleChoiceFormItem {
_attributedTitle = attributedTitle;
_useCardView = YES;
_leftRightMargin = 0.0;
[self setBackgroundColor:[UIColor clearColor]];
[self setupHeaderViewWithAttributedTitle:attributedTitle detailText:detailText learnMoreView:learnMoreView progressText:progressText hasMultipleChoiceFormItem:hasMultipleChoiceFormItem];
[self setupConstraints];
}

- (void)setupConstraints {

if (_containerConstraints) {
Expand Down
22 changes: 21 additions & 1 deletion ResearchKit/Common/ORKQuestionStep.h
Expand Up @@ -70,9 +70,22 @@ ORK_CLASS_AVAILABLE
*/
+ (instancetype)questionStepWithIdentifier:(NSString *)identifier
title:(nullable NSString *)title
question:(nullable NSString *)question
question:(nullable NSString *)question
answer:(nullable ORKAnswerFormat *)answerFormat;

/**
Returns a new question step that includes the specified identifier, title, question, and answer format.

@param identifier The identifier of the step (a step identifier should be unique within the task).
@param attributedTitle A localized attributed string that represents the primary text of the question.
@param attributedQuestion A localized attributed string that represents the question as a text.
@param answerFormat The format in which the answer is expected.
*/
+ (instancetype)questionStepWithIdentifier:(NSString *)identifier
attributedTitle:(nullable NSAttributedString *)attributedTitle
attributedQuestion:(nullable NSAttributedString *)attributedQuestion
answer:(nullable ORKAnswerFormat *)answerFormat;

/**
Returns a new question step that includes the specified identifier, title, question, answer, and learnMoreItem format.

Expand Down Expand Up @@ -104,6 +117,13 @@ ORK_CLASS_AVAILABLE
*/
@property (nonatomic, strong, nullable) NSString *question;

/**
The attributed question for the step.

Different from the step title.
*/
@property (nonatomic, strong, nullable) NSAttributedString *attributedQuestion;

/**
The question type. (read-only)

Expand Down
24 changes: 22 additions & 2 deletions ResearchKit/Common/ORKQuestionStep.m
Expand Up @@ -48,7 +48,7 @@ + (Class)stepViewControllerClass {

+ (instancetype)questionStepWithIdentifier:(NSString *)identifier
title:(nullable NSString *)title
question:(nullable NSString *)question
question:(nullable NSString *)question
answer:(nullable ORKAnswerFormat *)answerFormat {

ORKQuestionStep *step = [[ORKQuestionStep alloc] initWithIdentifier:identifier];
Expand All @@ -59,6 +59,19 @@ + (instancetype)questionStepWithIdentifier:(NSString *)identifier
return step;
}

+ (instancetype)questionStepWithIdentifier:(NSString *)identifier
attributedTitle:(nullable NSAttributedString *)attributedTitle
attributedQuestion:(nullable NSAttributedString *)attributedQuestion
answer:(nullable ORKAnswerFormat *)answerFormat {

ORKQuestionStep *step = [[ORKQuestionStep alloc] initWithIdentifier:identifier];
step.attributedTitle = attributedTitle;
step.attributedQuestion = attributedQuestion;
step.answerFormat = answerFormat;
step.tagText = nil;
return step;
}

+ (instancetype)questionStepWithIdentifier:(NSString *)identifier
title:(nullable NSString *)title
question:(nullable NSString *)question
Expand Down Expand Up @@ -104,6 +117,7 @@ - (instancetype)copyWithZone:(NSZone *)zone {
questionStep.answerFormat = [self.answerFormat copy];
questionStep.placeholder = [self.placeholder copy];
questionStep.learnMoreItem = [self.learnMoreItem copy];
questionStep.attributedQuestion = [self.attributedQuestion copy];
questionStep.question = [self.question copy];
questionStep.tagText = [self.tagText copy];
return questionStep;
Expand All @@ -121,13 +135,17 @@ - (BOOL)isEqual:(id)object {
}

- (NSUInteger)hash {
return super.hash ^ self.answerFormat.hash ^ self.question.hash ^ self.questionType ^ self.placeholder.hash ^ (_useCardView ? 0xf : 0x0) ^ self.learnMoreItem.hash ^ self.tagText.hash;
return super.hash ^ self.answerFormat.hash ^ self.question.hash ^ self.attributedQuestion.hash ^ self.questionType ^ self.placeholder.hash ^ (_useCardView ? 0xf : 0x0) ^ self.learnMoreItem.hash ^ self.tagText.hash;
}

- (void)setQuestion:(NSString *)question {
_question = question;
}

- (void)setAttributedQuestion:(NSAttributedString *)attributedQuestion {
_attributedQuestion = attributedQuestion;
}

- (ORKQuestionType)questionType {
ORKAnswerFormat *impliedFormat = [self impliedAnswerFormat];
return impliedFormat.questionType;
Expand All @@ -143,6 +161,7 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder {
ORK_DECODE_OBJ_CLASS(aDecoder, answerFormat, ORKAnswerFormat);
ORK_DECODE_OBJ_CLASS(aDecoder, placeholder, NSString);
ORK_DECODE_OBJ_CLASS(aDecoder, question, NSString);
ORK_DECODE_OBJ_CLASS(aDecoder, attributedQuestion, NSAttributedString);
ORK_DECODE_OBJ_CLASS(aDecoder, learnMoreItem, ORKLearnMoreItem);
ORK_DECODE_BOOL(aDecoder, useCardView);
ORK_DECODE_OBJ_CLASS(aDecoder, tagText, NSString);
Expand All @@ -156,6 +175,7 @@ - (void)encodeWithCoder:(NSCoder *)aCoder {
ORK_ENCODE_OBJ(aCoder, answerFormat);
ORK_ENCODE_OBJ(aCoder, placeholder);
ORK_ENCODE_OBJ(aCoder, question);
ORK_ENCODE_OBJ(aCoder, attributedQuestion);
ORK_ENCODE_OBJ(aCoder, learnMoreItem);
ORK_ENCODE_BOOL(aCoder, useCardView);
ORK_ENCODE_OBJ(aCoder, tagText);
Expand Down
8 changes: 8 additions & 0 deletions ResearchKit/Common/ORKQuestionStepView.m
Expand Up @@ -51,6 +51,8 @@ - (void)setQuestionCustomView:(ORKQuestionStepCustomView *)questionCustomView {
- (void)setQuestionStep:(ORKQuestionStep *)step {
_questionStep = step;
self.stepTitle = step.title;
self.stepAttributedTitle = step.attributedTitle;
self.stepAttributedText = step.attributedText;
self.stepTopContentImage = step.image;
self.stepTopContentImageContentMode = step.imageContentMode;
self.titleIconImage = step.iconImage;
Expand All @@ -66,4 +68,10 @@ - (void)setCustomHeaderTitle:(nullable NSString *)text {
}
}

- (void)setCustomHeaderAttributedTitle:(nullable NSAttributedString *)text {
if (text) {
self.stepAttributedTitle = text;
}
}

@end
23 changes: 18 additions & 5 deletions ResearchKit/Common/ORKQuestionStepViewController.m
Expand Up @@ -193,6 +193,8 @@ - (void)stepDidChange {
_headerView.stepTopContentImage = self.step.image;
_headerView.titleIconImage = self.step.iconImage;
_headerView.stepTitle = self.step.title;
_headerView.stepAttributedTitle = self.step.attributedTitle;
_headerView.stepAttributedText = self.step.attributedText;
_headerView.stepText = self.step.text;
// TODO:- we are currently not setting detailText to _headerView because we are restricting detailText to be displayed only inside ORKSurveyCardHeaderView, might wanna rethink this later. Please use the text property on ORKQuestionStep for adding extra information.
_headerView.stepHeaderTextAlignment = self.step.headerTextAlignment;
Expand Down Expand Up @@ -278,8 +280,13 @@ - (void)stepDidChange {
if (self.questionStep.impliedAnswerFormat != nil && self.questionStep.impliedAnswerFormat.questionType == ORKQuestionTypeMultipleChoice) {
hasMultipleChoiceFormItem = YES;
}

[_cellHolderView useCardViewWithTitle:self.questionStep.question detailText:self.step.detailText learnMoreView:learnMoreView progressText:sectionProgressText tagText:self.questionStep.tagText hasMultipleChoiceFormItem:hasMultipleChoiceFormItem];

if (self.questionStep.attributedQuestion != nil) {
[_cellHolderView useCardViewWithAttributedTitle:self.questionStep.attributedQuestion detailText:self.step.detailText learnMoreView:learnMoreView progressText:sectionProgressText tagText:self.questionStep.tagText hasMultipleChoiceFormItem:hasMultipleChoiceFormItem];
} else {

[_cellHolderView useCardViewWithTitle:self.questionStep.question detailText:self.step.detailText learnMoreView:learnMoreView progressText:sectionProgressText tagText:self.questionStep.tagText hasMultipleChoiceFormItem:hasMultipleChoiceFormItem];
}
}
_questionView.questionCustomView = _cellHolderView;
}
Expand Down Expand Up @@ -681,7 +688,7 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

if ([self questionStep].useCardView && [self questionStep].question) {
if ([self questionStep].useCardView && ([self questionStep].question || [self questionStep].attributedQuestion)) {
ORKLearnMoreView *learnMoreView;
NSString *sectionProgressText = nil;
BOOL hasMultipleChoiceFormItem = NO;
Expand All @@ -703,8 +710,14 @@ - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger
if (self.questionStep.impliedAnswerFormat != nil && self.questionStep.impliedAnswerFormat.questionType == ORKQuestionTypeMultipleChoice) {
hasMultipleChoiceFormItem = YES;
}

if (self.questionStep.attributedQuestion != nil) {
return [[ORKSurveyCardHeaderView alloc] initWithAttributedTitle:self.questionStep.attributedQuestion detailText:self.questionStep.detailText learnMoreView:learnMoreView progressText:sectionProgressText tagText:self.questionStep.tagText showBorder:NO hasMultipleChoiceItem:hasMultipleChoiceFormItem];
} else {
return [[ORKSurveyCardHeaderView alloc] initWithTitle:self.questionStep.question detailText:self.questionStep.detailText learnMoreView:learnMoreView progressText:sectionProgressText tagText:self.questionStep.tagText showBorder:NO hasMultipleChoiceItem:hasMultipleChoiceFormItem];
}

return [[ORKSurveyCardHeaderView alloc] initWithTitle:self.questionStep.question detailText:self.questionStep.detailText learnMoreView:learnMoreView progressText:sectionProgressText tagText:self.questionStep.tagText showBorder:NO hasMultipleChoiceItem:hasMultipleChoiceFormItem];

}
return nil;
}
Expand Down Expand Up @@ -764,7 +777,7 @@ - (ORKSurveyAnswerCell *)answerCellForTableView:(UITableView *)tableView {

ORKSurveyAnswerCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

if (cell == nil) {
if (cell == nil) {
cell = [[class alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier step:[self questionStep] answer:self.answer delegate:self];
}

Expand Down
19 changes: 17 additions & 2 deletions ResearchKit/Common/ORKStep.h
Expand Up @@ -106,7 +106,7 @@ ORK_CLASS_AVAILABLE

The identifier is reproduced in the results of a step. In fact, the only way to link a result
(an `ORKStepResult` object) to the step that generated it is to look at the value of
`identifier`. To accurately identify step results, you need to ensure that step identifiers
`identifier`. To accurately identify step results, you need to ensure that step identifiers
are unique within each task.

In some cases, it can be useful to link the step identifier to a unique identifier in a
Expand Down Expand Up @@ -144,6 +144,11 @@ ORK_CLASS_AVAILABLE
*/
@property (nonatomic, copy, nullable) NSString *title;

/**
The primary text to display for the step in a localized attributed string.
*/
@property (nonatomic, copy, nullable) NSAttributedString *attributedTitle;

/**
Additional text to display for the step in a localized string.

Expand All @@ -154,6 +159,16 @@ ORK_CLASS_AVAILABLE

@property (nonatomic, copy, nullable) NSString *text;

/**
Additional text to display for the step in a localized attributed string.

The additional text is displayed in a smaller font below `title`. If you need to display a
long question, it can work well to keep the title short and put the additional content in
the `text` property.
*/

@property (nonatomic, copy, nullable) NSAttributedString *attributedText;

/**
Additional detailed explanation for the instruction.

Expand Down Expand Up @@ -296,7 +311,7 @@ Whether to show progress for this step when it is presented. The default is YES.
using the `-stepViewControllerClass` method and initializing that instance by calling `initWithIdentifier:result:`
on the provided `ORKStepViewController` class instance.

Override this method if you need to customize the behavior before presenting the step or if
Override this method if you need to customize the behavior before presenting the step or if
the view controller is presented using a nib or storyboard.

@param result The result associated with this step
Expand Down