Compare commits

...

642 Commits

Author SHA1 Message Date
Yuan Zhu fa5214c4bc Update ResearchKit.podspec
To 1.1.2
2015-06-09 18:35:52 -07:00
Yuan Zhu 84ad0d4072 Fix two warnings in release build. 2015-06-09 18:31:52 -07:00
Yuan Zhu 9ed835007f Update ResearchKit.podspec
To 1.1.1
2015-06-09 18:15:44 -07:00
jwe-apple 67bc2884bb Merge pull request #286 from jwe-apple/translations-1.1
Localization update for ResearchKit 1.1
2015-06-08 16:49:28 -07:00
John Earl 3b3280bdda Review fix 2015-06-08 16:46:02 -07:00
John Earl 4fcb4b8cb6 Project file update 2015-06-08 16:42:24 -07:00
John Earl 7d7a25f77c Localization update for ResearchKit 1.1
Updates ResearchKit translations for new features for 1.1.
Incorporates some bug fixes to existing translations too, and
ensures that ORKTest app can be used for testing all the localizations.
2015-06-08 14:35:17 -07:00
jwe-apple 64f51aaa3c Merge pull request #285 from jwe-apple/speech
Fix speech rate on iOS 8.3 and earlier
2015-06-08 14:21:09 -07:00
jwe-apple f9b7b57e3a Merge pull request #284 from jwe-apple/viet
Vietnamese is a family name first language
2015-06-08 14:20:09 -07:00
John Earl 8155c96d61 Vietnamese is a family name first language
Add Vietnamese to the list of such languages for consent review.
2015-06-08 14:16:00 -07:00
John Earl af6a62483a Fix speech rate on iOS 8.3 and earlier
Patch earlier this week adjusted the speech rate to use the default speech
rate. This is too fast a rate on iOS 8.3 and earlier.
2015-06-08 14:14:26 -07:00
jwe-apple e88ed5d551 Merge pull request #272 from brucehappy/convergence_issue_242
Image Capture Step optional support
2015-06-07 20:32:31 -07:00
Bruce Duncan cfeb443255 Move all manipulation of the continue and skip buttons to an update function called by the functions that affect them. 2015-06-07 18:46:03 -04:00
Bruce Duncan 9813ddc17e Do not allow the continue button to be used when set during an error state. This can happen in the simulator where there is no camera. 2015-06-06 03:46:37 -04:00
Bruce Duncan fa37135471 Prevent the file from being rewritten on initialization from a valid result. Clean up handleError slightly. 2015-06-06 03:37:56 -04:00
Bruce Duncan 90f4cc472a Removed if statement in capturePressed as only the "then" can now occur 2015-06-06 02:58:57 -04:00
Bruce Duncan c3254ecc46 Update the continue button if its not currently set to the capture button 2015-06-05 21:18:20 -04:00
Bruce Duncan 68623b97c2 Added support for optional. Fixed layout problem (thanks to @YuanZhu-apple #269). Reworked saving of continue and skip buttons. Made the ORKCatalog image capture step non-optional. 2015-06-05 19:59:04 -04:00
Bruce Duncan ad707bf2a3 Merge branch 'issue_242' into convergence_issue_242 2015-06-05 18:21:14 -04:00
jwe-apple f9e5a898a2 Merge pull request #271 from YuanZhu-apple/convergence
In FormItemCell, lower a heightConstraint's priority
2015-06-05 14:58:55 -07:00
Yuan Zhu eef997cc1b In FormItemCell, lower a heightConstraint's priority to avoid conflicts with system supplied UIView-Encapsulated-Layout-Height constraint. 2015-06-05 13:11:36 -07:00
jwe-apple 4fac6c1c08 Merge pull request #268 from YuanZhu-apple/convergence
"Learn More" modal views: replace "Cancel" with "Done"  (Fix for #266)
2015-06-05 10:24:05 -07:00
Yuan Zhu 781d95ab88 Change the method name as well. 2015-06-04 22:00:23 -07:00
Yuan Zhu 69c5c63e7b "Learn More" modal views: replace "Cancel" with "Done" (Fix for #266) 2015-06-04 20:14:56 -07:00
jwe-apple f36a059306 Merge pull request #267 from rsanchezsaez/rsanchezsaez-imagecapturefix
Fix image capture view constraints updating after rotation
2015-06-03 18:24:12 -07:00
Ricardo Sánchez-Sáez 2593b7ae99 ORKImageCaptureView: fix constraints not being updated after a rotation 2015-06-03 22:34:05 +01:00
jwe-apple 512bed7505 Merge pull request #264 from brucehappy/fix_pr_262
Fix for compile error in #262
2015-06-03 00:08:02 -07:00
Bruce Duncan 91e8a9a370 Fixed renamed identifier reference 2015-06-03 02:58:07 -04:00
Bruce Duncan fd330506f2 Fix for #242 Experiencing an error will now completely shut down the image capture step, including removing the continue and skip buttons, and resulting in only error text shown in the view. 2015-06-03 02:50:50 -04:00
Yuan Zhu 600c8f0898 Merge pull request #262 from jwe-apple/test2
Fix tests and rename Device Motion Reaction Time to Reaction Time
2015-06-02 23:28:39 -07:00
John Earl 17219a81a2 Review changes. 2015-06-02 23:10:49 -07:00
John Earl c7a0f893a4 Add missing files 2015-06-02 19:01:15 -07:00
John Earl fbe97c7c53 Fix tests and rename Device Motion Reaction Time to Reaction Time
Makes all tests pass in both ORKTest and ResearchKit.
Fixes test failures introduced in #252.

Also fixes #257, renaming to ORKReactionTime...
2015-06-02 18:57:46 -07:00
jwe-apple 1f9ea2351c Merge pull request #258 from rsanchezsaez/jwe-nsurlserialization
ORKURLForRelativePath(): use NSURL methods instead of CFURL's
2015-06-02 18:17:47 -07:00
Ricardo Sánchez-Sáez 99db33cbc4 ORKURLForRelativePath(): use NSURL methods instead of CFURL's
Also: minor variable renames and whitespace conforming.
2015-06-02 22:12:55 +01:00
John Earl 1c52f9421b Minor fix (thanks @rsanchezsaez) 2015-06-02 12:28:11 -07:00
jwe-apple 2ff60bfc91 Merge pull request #252 from jwe-apple/nsurl-serialization
Exception when saving and restoring image capture step.
2015-06-02 12:25:54 -07:00
jwe-apple 784b9c266c Merge pull request #255 from rsanchezsaez/rsanchezsaez-imagecapture
Update image capture task images in ORKCatalog
2015-06-02 12:24:59 -07:00
jwe-apple 87d9a720c8 Merge pull request #254 from jwe-apple/consented
Add explicit consent review indication
2015-06-02 12:24:16 -07:00
John Earl 07005babf4 Review fix 2015-06-02 12:24:09 -07:00
jwe-apple 6a877cf70a Merge pull request #253 from jwe-apple/formstep
Issue #245: enable multiple section headers
2015-06-02 12:22:41 -07:00
John Earl 4358bd903f Review fixes. 2015-06-02 12:22:04 -07:00
jwe-apple f711545f8f Merge pull request #251 from jwe-apple/reaction-timeout
Reaction time task does not time out in sim
2015-06-02 11:53:53 -07:00
John Earl 591ee60003 Add conditional to address review feedback 2015-06-02 11:53:39 -07:00
jwe-apple 34d2fec94e Merge pull request #250 from jwe-apple/keyboard-hide
Keyboard does not hide when tapping on margins on iPad
2015-06-02 11:51:27 -07:00
jwe-apple 41e239fa2e Merge pull request #249 from jwe-apple/speechrate
Speech rate should use default speech rate
2015-06-02 11:51:12 -07:00
jwe-apple c05f998007 Merge pull request #248 from jwe-apple/textlayout
Fix unexpected text truncation
2015-06-02 11:50:05 -07:00
John Earl 0559b095af Review fix: align with contract of return type 2015-06-02 11:49:24 -07:00
Ricardo Sánchez-Sáez 8d95cf9c19 ORKCatalog: update image capture task images
Also, fix small issue in ORKImageCaptureCameraPreviewView.
2015-06-02 10:55:18 +01:00
John Earl 94333e65da Add explicit consent review indication
Adds a `consented` property to ORKConsentSignatureResult. This property
is true if the consent has been explicitly agreed by the user, and false
otherwise.

Added ORKESerializer support and verified unit tests pass.
2015-06-02 00:27:05 -07:00
John Earl 6c9312ffd8 Issue #245: enable multiple section headers
If multiple section headers are requested, they will now all display.
As a side effect, this also fixes #245.
2015-06-02 00:17:19 -07:00
John Earl 9e498684b2 Exception when saving and restoring image capture step.
If the app is terminated while on an image capture step, and restarted
by build and run from Xcode, an exception would occur while restoring.

This is a symptom of serializing NSURL's directly, rather than serializing
either a relative path or bookmark data. This matters because the path can
change after a reinstall or restore from backup.

Here we make two changes. First, the output directory in task and step
view controller is serialized as bookmark data rather than directly as a URL.
Secondly, for results serialization, NSURL references are stored as paths
relative to the NSHomeDirectory (i.e. the root of the writable sandbox).
2015-06-01 23:55:03 -07:00
John Earl 43359003ca Reaction time task does not time out in sim
The reaction time task was untestable in the simulator. Here, we add
support for both timing out the task in the simulator, and for using the
shake gesture in the simulator.
2015-06-01 22:54:36 -07:00
jwe-apple 8c2b897a8e Merge pull request #246 from rsanchezsaez/rsanchezsaez-imagecapture
Improvements to image capture active step
2015-06-01 22:37:40 -07:00
John Earl 61a67a4e26 Keyboard does not hide when tapping on margins on iPad
Steps to reproduce:
- Build and deploy ORKTest to iPad sim
- Miniform -> Weight
- Tap on weight, Keyboard appears
- Tap on side of screen

Actual result:
- Keyboard does not hide

Expected result:
- Keyboard should hide.

Fix: allow parent view to specify a different tap off scope for the tap off
gesture recognizer by exposing a tapOffView property on ORKTableContainerView.

This has no API impact, since ORKTableContainerView is internal to the framework.
2015-06-01 22:31:09 -07:00
John Earl 0f22145f37 Speech rate should use default speech rate
Using a speech rate relative to the maximum speech rate is error
prone.
2015-06-01 22:12:18 -07:00
John Earl 1bd8764245 Fix unexpected text truncation
In certain scenarios, the interaction of auto layout and the selection of
the preferredMaxLayoutWidth could result in text being abnormally
truncated.

This fix lets the labels in the headerview be full width, by reducing the
content hugging priority.

This is slightly less efficient from a rendering perspective but makes
the autolayout calculation more stable.
2015-06-01 21:49:33 -07:00
jwe-apple a6aa2fbab7 Merge pull request #247 from jwe-apple/timepicker2
Fix picker layout centering in certain conditions.
2015-06-01 21:25:48 -07:00
John Earl 43bd4897cd Fix picker layout centering in certain conditions.
The constraints implementation change updates to correct behavior, but did
not affect the actual bug.
2015-06-01 21:24:07 -07:00
Ricardo Sánchez-Sáez ce52ed22cc ORKImageCaptureStepViewController: log additional error on image write failure 2015-06-02 00:54:07 +01:00
Ricardo Sánchez-Sáez cac4c8bbeb ORKImageCaptureCameraPreviewView: add fade in/out animation to template image 2015-06-02 00:49:39 +01:00
Ricardo Sánchez-Sáez 54c3374f93 ORKImageCaptureCameraPreviewView: make template image to insets from actual video frame instead of superview frame
Compare running on iPad vs iPhone 6 to see the difference.
Also: use plain UIImageView instead of ORKTintedImageView for captureImageView.
2015-06-01 23:49:06 +01:00
Ricardo Sánchez-Sáez 34d80c8842 ORKImageCaptureView: use ORKBackgroundColor instead of hardcoded white color 2015-06-01 23:39:13 +01:00
Ricardo Sánchez-Sáez 25dec24ebf ORKTest: replace image capture example image 2015-06-01 23:29:54 +01:00
jwe-apple 58b512172d Merge pull request #239 from jwe-apple/imagecapture2
Issue #234 - Fix rotation behavior on iPad.
2015-05-31 15:55:09 -07:00
jwe-apple 3c49a02b1c Merge pull request #238 from jwe-apple/issue-236
Only attempt to create outputDirectory if it is non-nil
2015-05-31 15:52:57 -07:00
jwe-apple df31766f16 Merge pull request #240 from rsanchezsaez/rsanchezsaez-reactiontime
Reaction time task: fix issues
2015-05-31 15:52:41 -07:00
Ricardo Sánchez-Sáez bbfd809e84 ResultTableViewProviders: fix crash because ORKDeviceMotionReactionTimeResult's timestamp was selectable
Also corrects the selectable attribute of some non-selectable rows and removes unneeded code.
2015-05-31 13:34:27 +01:00
Ricardo Sánchez-Sáez 2eee55747a Reaction time task: fix issue which caused the failure animation not to show if shaking device before blue dot appeared
Also: avoid launching the failure animation twice if shaking the device while timeout failure animation was shown.
2015-05-31 12:59:55 +01:00
John Earl 06d1a23032 Issue #224 - Fix rotation behavior on iPad.
Existing listened for device orientation notifications, rather than status bar orientation.
Status bar orientation is the right one to listen for.
2015-05-30 23:22:11 -07:00
John Earl e458ec5845 Only attempt to create outputDirectory if it is non-nil 2015-05-30 20:16:18 -07:00
jwe-apple 2bb1eed6f4 Merge pull request #232 from rsanchezsaez/rsanchezsaez-reactiontime
Device motion reaction time code improvements
2015-05-30 20:01:31 -07:00
jwe-apple f66aead4da Merge pull request #237 from rsanchezsaez/rsanchezsaez-toneaudiometry
Tone audiometry: stop playing sound on step suspend
2015-05-30 19:59:36 -07:00
Ricardo Sánchez-Sáez 614b1d7080 ORKToneAudiometryPracticeStepViewController: stop playing tone on suspend, and restart on resume 2015-05-30 11:23:41 +01:00
Ricardo Sánchez-Sáez 8649fa8223 ORKDeviceMotionReactionTimeStep: add minimumStimulusInterval and timeout validation
Adds corresponding unit tests.
2015-05-30 11:05:37 +01:00
Ricardo Sánchez-Sáez fb939304b9 ORKDeviceMotionReactionTime: various code improvements (fixes error in step copy method)
Also:
- Refactor and simplify constraint code.
- Conform to whitespace conventions.
- Replace true/false usage by YES/NO.
- Use SystemSoundID instead of UInt32.
2015-05-29 14:40:29 +01:00
jwe-apple 3e23cd4b8b Merge pull request #229 from rsanchezsaez/rsanchezsaez-headerdocs
Fix overviews' example code warnings by using fenced code blocks
2015-05-27 10:52:15 -07:00
Ricardo Sánchez-Sáez f8632a371d Fix HeaderDoc markdown template warnings by using fenced code blocks
It needs appledoc v2.2.1 (build 1334), which can be found here: https://github.com/tomaz/appledoc/pull/535
2015-05-26 23:29:25 +01:00
jwe-apple 097ff8dd63 Merge pull request #227 from jwe-apple/accessibility
Accessibility updates.
2015-05-26 13:30:00 -07:00
John Earl 22696a6d38 Accessibility updates.
- Annotates the image capture view in an image capture step as an image.
- Adds the slider range description labels to the VoiceOver range description.
2015-05-26 13:28:55 -07:00
John Earl 81acc7bbd9 Issue #222 - Bump versions to 1.1 2015-05-26 13:17:55 -07:00
jwe-apple 98980500ec Merge pull request #225 from rsanchezsaez/rsanchezsaez-scaleconstraints
Fix autolayout warnings after rotation on form with vertical scales
2015-05-26 13:14:33 -07:00
jwe-apple 2ca06c44b2 Merge pull request #226 from rsanchezsaez/rsanchezsaez-headerdocs
Fix some erroneous HeaderDocs @param comments
2015-05-25 23:17:27 -07:00
Ricardo Sánchez-Sáez 06326d7ffe HeaderDocs: fix some erroneous @param comments 2015-05-26 00:55:09 +01:00
Ricardo Sánchez-Sáez bc7ea01397 ORKScaleSliderView: fix autolayout warnings on form with vertical scales rotation (#202)
Also simplifies vertical scale autolayout code.
2015-05-26 00:18:03 +01:00
jwe-apple dbe906e7ec Merge pull request #223 from rsanchezsaez/rsanchezsaez-navigationrules
Step navigation rules: rename 'matchingStepIdentifiers' to 'destinationStepIdentifiers'
2015-05-25 14:05:28 -07:00
jwe-apple bde087d3b3 Merge pull request #217 from rsanchezsaez/rsanchezsaez-visualconsent
Add optional tinted image cache (only enabled for consent step view controller)
2015-05-25 13:55:22 -07:00
Ricardo Sánchez-Sáez c3b353783f Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules 2015-05-25 21:53:53 +01:00
Ricardo Sánchez-Sáez 53bcccdc87 ORKStepNavigationRule: rename 'matchingStepIdentifiers' by 'destinationStepIdentifiers' 2015-05-25 21:53:36 +01:00
jwe-apple 94b644ca6f Merge pull request #221 from ayushgoel/master
Make plist to strings script DRY
2015-05-25 13:47:36 -07:00
Ricardo Sánchez-Sáez d25bdbe953 ORKVisualConsentStepViewController: preload next consent section image only
(Instead of loading the whole view controller.)
2015-05-25 20:07:32 +01:00
Ricardo Sánchez-Sáez 3af24d1828 ORKConsentSection: move image loading from controller to internal property
Also moves ConsentSection+AssetLoading contents to main file.
2015-05-25 19:50:43 +01:00
Ayush Goel 117c84d06a Make plist to strings script DRY
Refactor repeated code to create a function
2015-05-25 10:20:10 +05:30
Ricardo Sánchez-Sáez 180294ce71 ORKTintedImageView: fix error with animated image tinting 2015-05-22 16:10:19 +01:00
Ricardo Sánchez-Sáez 6bc2d35a94 ORKVisualConsentStepViewController & ORKTintedImageView: add optional tinted image view caching (only enabled for consent step view controller) 2015-05-22 02:24:41 +01:00
jwe-apple 1fe84298a0 Merge pull request #216 from rsanchezsaez/rsanchezsaez-visualconsent
ORKEAGLMoviePlayerView: fix incorrect aspect ratio after rotation
2015-05-21 16:29:14 -07:00
Ricardo Sánchez-Sáez 5e6442d3a0 ORKEAGLMoviePlayerView: fix incorrect aspect ratio after rotation
Also:
- Add guards so GL functions aren't called if OpenGL is not setup.
- Delete program and buffers on dealloc.
2015-05-22 00:09:38 +01:00
jwe-apple 8fbcb42170 Merge pull request #212 from rsanchezsaez/rsanchezsaez-visualconsent
Fix visual content warnings and crash
2015-05-21 16:07:01 -07:00
Ricardo Sánchez-Sáez 63272ecbce ORKTintedImageView: return early and deindent method body 2015-05-22 00:00:50 +01:00
Ricardo Sánchez-Sáez ea07a956b2 ORKImageByTintingImage: return early instead of indenting 2015-05-21 23:00:42 +01:00
Ricardo Sánchez-Sáez be0df4d187 ORKTintedImageView: make sure animated images are tinted at proper scale 2015-05-21 22:04:08 +01:00
Ricardo Sánchez-Sáez 07f48c125b Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-visualconsent 2015-05-21 20:59:15 +01:00
jwe-apple b44cc8c072 Merge pull request #214 from jwe-apple/ui-review-2
UI review changeset
2015-05-21 10:11:29 -07:00
John Earl 5cd1562f6f UI review changeset
- Add comments to remind developers to be careful what images they use for image capture steps.
- Update wording for both active tasks
- Add an extra step before countdown for the audiometry active task and be more explicit about headphones
- Adjust color, size, and alignment of supplementary scale labels
- Turn off audio tone generation when inactive
2015-05-21 10:10:27 -07:00
jwe-apple 2240780a5b Merge pull request #209 from jwe-apple/ipad-fixes
Minor iPad layout fixes
2015-05-21 10:08:18 -07:00
jwe-apple 01a2de8934 Merge pull request #210 from jwe-apple/orktest-language
Minor changes to copy in ORKTest
2015-05-21 10:08:07 -07:00
Ricardo Sánchez-Sáez fa966fa682 ORKVerticalContainerView: replace UIImageView by ORKTintedImageView
Tinting of consent images is now done by the ORKTintedView.
2015-05-21 14:49:07 +01:00
Ricardo Sánchez-Sáez 775e7f2520 ORKConsentSceneViewController: go back to using template rendering mode for consent images
It caused tinted consent images not to have the correct custom tint color and scale.
2015-05-21 14:36:58 +01:00
Ricardo Sánchez-Sáez ff50ceb63e ORKTintedImageView: avoid trying to tint a nil image 2015-05-21 14:11:46 +01:00
Ricardo Sánchez-Sáez b7b8b751f6 ORKVisualConsentStepViewController: fix crash when animator completion block was executed after deallocation 2015-05-21 14:09:21 +01:00
Ricardo Sánchez-Sáez fa5bbf3011 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-visualconsent 2015-05-21 13:57:05 +01:00
jwe-apple 952fc8c7ff Merge pull request #211 from jwe-apple/swift-changes
Swift review changes
2015-05-20 23:27:23 -07:00
John Earl e486bdef88 Swift review changes
The ORKCatalog changes for the image capture step have been reviewed for sample
code quality. A few minor changes ensue, mainly to simplify the syntax.
2015-05-20 23:24:49 -07:00
Ricardo Sánchez-Sáez 5047401252 ORKTest: add "Toggle Tint Color" button 2015-05-21 02:01:25 +01:00
John Earl 26dd857f0a Minor changes to copy in ORKTest
The ORKTest copy is not part of the framework, not particularly
user visible, but it's nice to keep it consistent.
2015-05-20 14:34:21 -07:00
John Earl 404e46f84b Minor iPad layout fixes
- Clip question step tableview to bounds to avoid visible artifact on
  consent sharing step.

- Make consent sharing step present its "learn more" content in a form sheet.
2015-05-20 14:26:53 -07:00
John Earl 17679ff56e Merge branch 'issue_1' of https://github.com/brucehappy/ResearchKit 2015-05-20 13:20:44 -07:00
jwe-apple b6b5f0accc Merge pull request #151 from rsanchezsaez/rsanchezsaez-navigationrules
Add navigable ordered task and step navigation rules
2015-05-20 13:06:57 -07:00
Ricardo Sánchez-Sáez 6ce52bad33 Move ORKNullStepIdentifier to ORKStepNavigationRule and add HeaderDoc comment
Also: add explicit test in ORKNavigableOrderedTask; make ORKResultPredicateTaskIdentifierVariableName safer by prefixing string value by ORK.
2015-05-20 11:23:27 +01:00
Ricardo Sánchez-Sáez 8bf354e741 ORKNavigableOrderedTask & ORKStep: add ORKNullStepIdentifier, to be used in step navigation rules when you want to end the ongoing task 2015-05-20 02:20:28 +01:00
Ricardo Sánchez-Sáez e725a6514a ORKTest: remove duplicate Reaction Time Task button 2015-05-20 02:04:54 +01:00
Ricardo Sánchez-Sáez bd4bf8ec38 Fix 'dizziness' typo 2015-05-20 01:06:55 +01:00
jwe-apple 0736e68401 Merge pull request #201 from jwe-apple/fix-identifiers
Fix identifier uniqueness issues
2015-05-19 14:50:26 -07:00
Ricardo Sánchez-Sáez f85ed88df3 ORKDirectStepNavigationRule: allow 'destinationStep' nullability
A direct step navigation rule with a nil destination step identifier can be used to finish the ongoing task early.
Also adds corresponding Unit Tests.
2015-05-19 21:43:05 +01:00
Bruce Duncan b6f4dbc345 Make sure that translatesAutoresizingMaskIntoConstraints is set to NO on init of the sub views, as well as self, both on init and if the constraints are updated. 2015-05-19 04:58:11 -04:00
Ricardo Sánchez-Sáez 853103ef1c Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-05-19 09:28:18 +01:00
Ricardo Sánchez-Sáez 622af54829 ORKResultPredicate: use ORK_EXTERN for ORKResultPredicateTaskIdentifierVariableName
Also renames ORKTaskIdentifierResultPredicateVariableName to ORKResultPredicateTaskIdentifierVariableName.
2015-05-19 09:24:07 +01:00
John Earl 52f3d906a4 Fix ORKTest unit tests 2015-05-19 00:19:23 -07:00
John Earl 72217721cd Fix identifier uniqueness issues
1) Form items can have no identifier if they are just placeholders
for section headers in the table view. We should ignore the nil
identifiers for the purpose of the uniqueness check.

2) In ORKTest, the scale questions task had a non-unique step
identifier in it.
2015-05-19 00:02:03 -07:00
Bruce Duncan cde2e256f6 spacing 2015-05-19 01:39:14 -04:00
Bruce Duncan 05355b639c Changed the way ORKTintedImageView works, such that its shouldApplyTint will never override the renderingMode of the image provided to it. Updated the ORKCatalog and ORKTest image capture tasks to set the image renderingMode on the instruction steps to AlwaysTemplate to get them to tint. 2015-05-19 01:29:19 -04:00
Bruce Duncan 0842a0abb1 Renamed continuePressed to capturePressed for clarity. Added BOOLs to prevent processing capture or retake presses until the called delegate returns. 2015-05-19 00:31:49 -04:00
Bruce Duncan 6cdd9b81b6 Comment spacing and wrong word 2015-05-19 00:01:48 -04:00
Bruce Duncan f3c0bce4ff Fixed comment typo, and changed "the settings" to "Settings" 2015-05-18 23:02:48 -04:00
Bruce Duncan 54de137765 Inlined floatContinueView and fixed comment typo 2015-05-18 23:00:55 -04:00
Bruce Duncan b3bae6eebd Changed orientationChange to orientationDidChange 2015-05-18 22:57:38 -04:00
Bruce Duncan d2f6e1f0d0 Renamed hideTemplateImage to templateImageHidden, and getter to isTemplateImageHidden 2015-05-18 22:45:35 -04:00
Bruce Duncan ecce58e5a1 Reworked the check for overriding the continue button action 2015-05-18 22:33:12 -04:00
Bruce Duncan 40062a22a7 Reordered and relabeled the image capture step/task identifiers. 2015-05-18 20:49:54 -04:00
Bruce Duncan 9d47a69ccd Per @jwe-apple , handle the case of the continue button having its action change after it was first intercepted. 2015-05-18 20:46:06 -04:00
Ricardo Sánchez-Sáez 0ef6913118 ORKResultPredicate: make 'taskIdentifier' argument nullable
If you pass 'nil', the obtained result predicate will have a $TASK_IDENTIFIER substitution variable which will be replaced in ORKPredicateStepNavigationRule by the ongoing task identifier.

Also:
- Add convenience methods with no 'taskIdentifier' argument to ORKResultPredicate.
- Update ORKTest sample code to use convenience methods.
- Update Unit Tests to cover both convenience and regular nullable methods.
2015-05-19 00:21:30 +01:00
jwe-apple 66d978b37f Merge pull request #195 from rsanchezsaez/rsanchezsaez-activetaskimages
Add custom images for Tone Audiometry and Reaction Time tasks
2015-05-18 14:00:02 -07:00
jwe-apple 324192edef Merge pull request #190 from mattio/master
Update ORKFormStep API usage in the example snippet
2015-05-18 13:58:24 -07:00
John Earl 1df428f956 Add Apple copyright line (fixup from PR #200) 2015-05-18 13:57:53 -07:00
jwe-apple 6bcffa2368 Merge pull request #200 from alexbasson/fix-reverted-pr-198
Fix reverted pr 198
2015-05-18 13:55:55 -07:00
jwe-apple d9fe0c38bb Merge pull request #191 from rsanchezsaez/rsanchezsaez-doubleseparator
Avoid using magic number in ORKQuestionStepViewController
2015-05-18 13:43:18 -07:00
Ricardo Sánchez-Sáez ec8a764c06 Merge branch 'master' of github.com:rsanchezsaez/ResearchKit into rsanchezsaez-doubleseparator 2015-05-18 12:36:16 +01:00
Ricardo Sánchez-Sáez 291fa77606 Extract ORKScreenMetricMaxDimension (10000.0 magic number) to ORKSkin
Also goes back to using this constant for ORKQuestionStepViewController out of screen cell separator insets.
2015-05-18 12:33:49 +01:00
Ricardo Sánchez-Sáez 58b34e98a1 ORKResultPredicate: use NAN for ORKIgnoreDoubleValue and ORKIgnoreTimeIntervalValue (instead of DBL_MAX)
Also removes some unnecessary casts.
2015-05-18 11:59:55 +01:00
Alex Basson b7b7cd26a4 Add relevant copywrite headers 2015-05-18 06:35:29 -04:00
Ricardo Sánchez-Sáez a6cbe2a5d0 ORKStepNavigationRule appledoc: 'discretionarily' -> 'arbitrarily' 2015-05-18 11:33:16 +01:00
Alex Basson 0ffb0fd90b Revert "Revert "Tests for ORKConsentDocument""
This reverts commit 1529cd3a88.
2015-05-18 06:32:11 -04:00
jwe-apple db346ea955 Merge pull request #199 from ResearchKit/revert-198-tests-for-orkconsentdocument
Revert "Tests for ORKConsentDocument"
2015-05-18 01:13:22 -07:00
jwe-apple 1529cd3a88 Revert "Tests for ORKConsentDocument" 2015-05-18 01:12:59 -07:00
jwe-apple e8bd33b710 Merge pull request #198 from alexbasson/tests-for-orkconsentdocument
Tests for ORKConsentDocument
2015-05-18 01:10:02 -07:00
jwe-apple 339541a0c8 Merge pull request #197 from stownsend/master
_signaturePageContent not copied (fix for issue 196)
2015-05-18 01:02:00 -07:00
stownsend 20ba6f7bf0 Merge pull request #1 from stownsend/stownsend-patch-1
Update to ConsentDocument.m
2015-05-18 12:00:47 +10:00
stownsend dcdc1e6686 Update to ConsentDocument.m
Addressing issue 196, signaturePageContent is not copied on document copy.
2015-05-18 11:58:02 +10:00
Alex Basson e09ae87e63 Add tests for ORKConsentSignatureFormatter 2015-05-17 21:42:17 -04:00
Alex Basson 1958f073db Add tests for ORKConsentSectionFormatter
* reorganize consent-related tests into Consent group
2015-05-17 20:32:45 -04:00
Alex Basson 1cae0db303 Test ORKConsentDocument's makePDFWithCompletionHandler method
* Add ORKConsentSectionFormatter
* Add ORKConsentSignatureFormatter
2015-05-17 20:31:37 -04:00
Ricardo Sánchez-Sáez 4cf953ec0f Add custom images for Tone Audiometry and Reaction Time tasks
Also, rename Reaction Time task in ORKCatalog and ORKTest (was Device Motion Reaction Time).
2015-05-17 20:51:51 +01:00
Bruce Duncan 46f5cf6fd8 Should not be importing the private header from ORKImageCaptureStepViewController.h, just import ORKDefines_Private.h in the .m. 2015-05-17 14:28:14 -04:00
Ricardo Sánchez-Sáez 977dab78dc ORKResultPredicate: re-work predicate to match both task identifier and question result identifier
You can now have question results with the same identifier as long as they are part of different task results. Supplying the desired task identifier with the predicate is now compulsory: use the current task identifier if you want to match the ongoing task; or use any of the task result identifiers if you add extra ones to ORKPredicateStepNavigationRule's 'additionalTaskResults' property.

This change:
- Adds the task identifier argument to all predicate-building methods.
- Allows better reuse of predicate building code.
- Modifies ORKPredicateStepNavigationRule and Unit Tests accordingly. Task results are no longer squashed into a question result array. The new result predicates match the ORKTaskResult tree in its original form.
2015-05-17 16:26:57 +01:00
Alex Basson 0855cabddf Refactor ORKConsentDocument to allow for dependency injection 2015-05-16 22:05:39 -04:00
Ricardo Sánchez-Sáez 38326f25f4 ORKResultPredicate: add ORKIgnoreDoubleValue and ORKIgnoreTimeIntervalValue constants.
You can pass them to 'double' or 'NSTimeInterval' maximumValue argument or minimumValue argument to ignore those. Also adds corresponding Unit Tests.
2015-05-16 20:44:32 +01:00
Ricardo Sánchez-Sáez d97c70dee6 ORKResultPredicate: replace float arguments by double; make time interval question of NSTimeInterval type
Also adds corresponding Unit Tests.
2015-05-16 20:32:06 +01:00
Ricardo Sánchez-Sáez 3545133d51 ORKDirectStepNavigationRule: add 'destinationStepIdentifier' property; ORKPredicateStepNavigationRule: add 'resultPredicates', 'matchingStepIdentifiers' and 'defaultStepIdentifier' properties
Also adds corresponding Unit Tests.
2015-05-16 17:40:51 +01:00
Ricardo Sánchez-Sáez f3f0d5540d ORKNavigableOrderedTask: make sure 'sourceIdentifier' can safely be nil in 'updateStepIdentifierStackWithSourceIdentifier:destinationIdentifier:'
The stack is cleared if 'sourceIdentifier' is nil.
Also: assert destinationIdentifier; fixed typo in sourceIdentifier argument name.
2015-05-16 17:27:07 +01:00
Ricardo Sánchez-Sáez 46d1e57d81 ORKNavigableOrderedTask: add 'navigationRuleForTriggerStepIdentifier:' method
Also fixes typo in 'updateStepIdentifierStackWithSourceIdentifier:' method.
2015-05-16 17:11:39 +01:00
Ricardo Sánchez-Sáez 49e9181001 Remove HeaderDoc comment marker on unavailable new and init methods 2015-05-16 17:00:21 +01:00
Ricardo Sánchez-Sáez e22e1144fb Navigation rules: improve HeaderDoc comments
Also: extract ORKResultPredicate implementation into its own file.
2015-05-16 16:55:43 +01:00
Ricardo Sánchez-Sáez ddb3d459f5 ORKOrderedTask, ORKNavigableOrderedTask, ORKStepNavigationRule, ORKResultPredicate: hard-wrap HeaderDoc comments at column 100 2015-05-16 13:22:52 +01:00
Ricardo Sánchez-Sáez 3c75a76ae2 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	ResearchKitTests/ORKTaskTests.m
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-05-16 12:55:30 +01:00
Ricardo Sánchez-Sáez 14743d1868 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	Testing/ORKTest/ORKTest/MainViewController.m
#	Testing/ORKTest/ORKTest/ORKESerialization.m
2015-05-16 11:35:48 +01:00
Ricardo Sánchez-Sáez 462cf41773 ORKQuestionStepViewController: avoid using magic number 2015-05-16 10:33:32 +01:00
Bruce Duncan 9d1918b361 Added image capture step to ORKCatalog sample. Renamed existing Image table cell to TextImage, and created new Image table cell that shows a UIImageView that respects aspect ratio. Use the new Image table cell when the ORKFileResult points at an image file. As ORKCatalog calls setContinueButtonItem multiple times, changed ORKImageCaptureView to handle it. 2015-05-16 02:30:50 -04:00
Bruce Duncan fac2badb47 Headerdoc added, and nullability marked. 2015-05-15 19:09:27 -04:00
Bruce Duncan 9c17ac09ac Removed shouldUsePercentageBasedTemplateImageInsets property and associated code. Template image insets are assumed to always be percentages. 2015-05-15 18:47:18 -04:00
Bruce Duncan bfaac8ad2f Rework the capture setup such that its clear we are either dealing with a device with no camera, or one that is not giving us permission to use the camera. Update the name of the localized strings to be clearer about the two error cases. 2015-05-15 18:41:18 -04:00
John Earl cb001e2f4e Merge fix for ORKTest 2015-05-15 14:54:05 -07:00
John Earl c7a91a19a9 Merge branch 'coxy1989-coxy-reactionTime' 2015-05-15 14:28:33 -07:00
John Earl 164a7a4415 Merge fix 2015-05-15 14:27:14 -07:00
John Earl df71c79fe5 Merge branch 'coxy-reactionTime' of https://github.com/coxy1989/ResearchKit into coxy1989-coxy-reactionTime 2015-05-15 14:24:48 -07:00
Mattio Valentino 88a2b86d3f Update ORKFormStep API usage in the example snippet 2015-05-15 16:54:29 -04:00
jwe-apple 93b5df5541 Merge pull request #185 from scelis/signature-multi-touch
Fix various multitouch issues in ORKSignatureView
2015-05-15 13:04:44 -07:00
jwe-apple 492ce201f1 Merge pull request #182 from rsanchezsaez/rsanchezsaez-visualconsent
Visual consent view controller cleanup and optimization
2015-05-15 13:04:04 -07:00
jwe-apple d8c2bc8b55 Merge pull request #179 from rsanchezsaez/garnett-identifiervalidation
Complete unique identifier validation for task steps and form step items
2015-05-15 13:01:00 -07:00
jwe-apple 8481b66de4 Merge pull request #189 from rsanchezsaez/rsanchezsaez-mergeconflicts
ORKTest: Fix remaining scale merge conflict
2015-05-15 12:38:32 -07:00
Ricardo Sánchez-Sáez 3462909cd7 ORKVisualConsentStepViewController: add debug log message if either semaphore wait times out 2015-05-15 20:22:46 +01:00
Ricardo Sánchez-Sáez 16477efe6a ORKTest: Fix remaining scale merge conflict 2015-05-15 20:15:19 +01:00
Ricardo Sánchez-Sáez 4fa8de266c ORKVisualConsentStepController: add comments explaining semaphore usage 2015-05-15 20:10:49 +01:00
Ricardo Sánchez-Sáez 38b6310d10 Extract ORKNavigableOrderedTask and ORKResultPredicate into their own files 2015-05-15 19:46:17 +01:00
jwe-apple 7d833c8262 Merge pull request #188 from rsanchezsaez/rsanchezsaez-doubleseparator
Fix double bottom separator in boolean and text choice questions
2015-05-15 10:59:02 -07:00
jwe-apple 14aa32074e Merge pull request #187 from rsanchezsaez/rsanchezsaez-mergeconflicts
Resolve tone audiometry merge conflicts
2015-05-15 10:58:11 -07:00
Ricardo Sánchez-Sáez 67fee928e0 ORKESerialization: remove debug log 2015-05-15 18:05:19 +01:00
Ricardo Sánchez-Sáez 94db7d392c ORKQuestionStepViewController: fix double bottom separator 2015-05-15 02:44:36 +01:00
Ricardo Sánchez-Sáez 38135994ab Resolve previous tone audiometry merge conflicts 2015-05-15 02:40:15 +01:00
Ricardo Sánchez-Sáez 23246cbcbb Resolve previous tone audiometry merge conflicts 2015-05-15 02:00:12 +01:00
Ricardo Sánchez-Sáez 267ff6e563 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-visualconsent 2015-05-15 01:59:07 +01:00
Ricardo Sánchez-Sáez d7fe76008a ORKConsentSceneView: load tinted image using 'ORKImageByTintingImage()' instead of 'imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate'
This greatly improves next step loading performance on ORKVisualConsentStepViewController.
2015-05-15 01:58:03 +01:00
John Earl 4a494bda70 Merge branch 'shazino-tone-audiometry' 2015-05-14 17:21:40 -07:00
John Earl c50120d64f Merge branch 'tone-audiometry' of https://github.com/shazino/ResearchKit into shazino-tone-audiometry 2015-05-14 17:21:11 -07:00
John Earl d2cf8eba0a Merge branch 'CareEvolution-ORKScaleSliderView' 2015-05-14 17:13:50 -07:00
John Earl e0ca725a42 Merge branch 'ORKScaleSliderView' of https://github.com/CareEvolution/ResearchKit into CareEvolution-ORKScaleSliderView 2015-05-14 17:13:38 -07:00
John Earl ce735a1835 Merge branch 'CareEvolution-NSNumberFormatterForScaleAnswerFormats' 2015-05-14 17:01:46 -07:00
John Earl fb316bb744 Merge branch 'NSNumberFormatterForScaleAnswerFormats' of https://github.com/CareEvolution/ResearchKit into CareEvolution-NSNumberFormatterForScaleAnswerFormats 2015-05-14 17:01:30 -07:00
Ricardo Sánchez-Sáez cc9f194a2d ORKVisualConsentStepViewController: restore semaphore with 5-second timeout (guard against the animator not finishing)
Also add completion block to 'showViewController:forward:animated:completion:'.
2015-05-15 00:03:56 +01:00
Ricardo Sánchez-Sáez c787d2a134 ORKVisualConsentTransitionAnimator: make sure current player stops on 'finish' 2015-05-15 00:01:29 +01:00
Ricardo Sánchez-Sáez 536d28f6d9 ORKEAGLMoviePlayerView: cleanup and avoid some redundant OpenGL calls
(Optimizations are very minor, as OpenGL is not the bottleneck.)
2015-05-14 22:13:04 +01:00
jwe-apple f20d81ee3f Merge pull request #184 from scelis/signature-dots
Allow users to add a dot to the signature view
2015-05-14 09:51:58 -07:00
Sebastian Celis 0518fd777d Ignore all extra touches in the signature view.
This commit fixes a couple of issues with extra touches in the signature
view:

* Adding a second touch while signing would cause the path to jump to
  the second touch, which is probably not what the user wanted.
* Once two touches were applied to the signature view, if both touches
  ended simultaneously, gestureTouchesEnded: would return before calling
  signatureViewDidEditImage: on the delegate. This could get the UI into
  an odd state where there is a signature in the view but no clear
  button below the view.

By ignoring the extra touches completely, we can also clean up the code
a little and remove the extra touches checks in the various touch event
handlers.
2015-05-14 10:08:33 -05:00
Sebastian Celis 9c1cf6c6bf Allow users to add a dot to the signature view.
Add a small circle to the current signature path in touchesBegan to
properly support dots in the signature view. This provides a nicer
experience to users, allowing them to dot their i's.
2015-05-14 09:59:37 -05:00
Coxy 51dc62a780 spelling errors, licence headers 2015-05-13 22:06:58 +01:00
Coxy fb5a7a3f48 UI improvements 2015-05-13 20:05:53 +01:00
Scott Guelich 3d91a933b9 Add percent support to continuous scales
Also adds a readonly numberFormat property to ORKScaleAnswerFormat and ORKContinuousScaleAnswerFormat that can be overridden by subclasses for currency, etc.
2015-05-13 09:23:35 -07:00
Ricardo Sánchez-Sáez f1e75f2ce7 ORKVisualConsentStepViewController: make sure target view controller image is not hidden when there is no animation 2015-05-13 16:57:15 +01:00
Ricardo Sánchez-Sáez 7dc37149f3 ORKVisualConsentStepViewController: much simpler video animator logic
Does away with the semaphore, providing instead a linear, block-based, logic for the page transition and video transition animation options.
Also fixes a bug in which back button wasn't appearing if showViewController:forward:animated:'s 'animated' was set to NO.
Finally, calls 'updatePageIndex' (which in turn shows/hides the back button) earlier. Back button it's now shown after page transition completes, instead of after video transition animation completes.
2015-05-13 16:46:22 +01:00
Ricardo Sánchez-Sáez c50e88b3c7 ORKVisualConsentAnimationContext: correct observing flag ivar names 2015-05-13 16:39:03 +01:00
Ricardo Sánchez-Sáez 90a1b8407c ORKVisualConsentTransitionAnimator: remove useless dealloc method
The animator is never deallocated unless you first send it 'finish' (the CADisplayLink retains it).
2015-05-13 16:24:16 +01:00
Ricardo Sánchez-Sáez 46990ba807 ORKVisualConsentStepViewController: code cleanup 2015-05-13 12:26:07 +01:00
Ricardo Sánchez-Sáez 6795808555 Merge branch 'master' of github.com:rsanchezsaez/ResearchKit into garnett-identifiervalidation 2015-05-13 10:33:38 +01:00
Ricardo Sánchez-Sáez 3b6262c4fe Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	ResearchKit/Common/ORKHelpers.h
#	ResearchKit/Common/ORKVerticalContainerView.m
#	Testing/ORKTest/ORKTest/MainViewController.m
#	Testing/ORKTest/ORKTest/ORKESerialization.m
2015-05-13 10:33:09 +01:00
Bruce Duncan 9659fbb530 Moved requestedPermissions up into ORKStep from ORKActiveStep. Added a camera permission. Requested the permission from the image capture step. Added missing reference to the image capture step template image in the JSON serialization test. 2015-05-13 04:28:29 -04:00
Bruce Duncan 3b45807b87 Cleaned up imports and protocols (left over from early version) 2015-05-13 02:44:47 -04:00
jwe-apple 8ff919dc79 Merge pull request #181 from rsanchezsaez/rsanchezsaez-cleanup
HeaderDoc comment and whitespace cleanup
2015-05-12 17:39:30 -07:00
Ricardo Sánchez-Sáez df3883988b Another pass at whitespace homogenization
- Recorder subclasses were never checked
- Perform additional whitespace checks:
    - Remove spaces between statement and ';'
    - Remove spaces after pointer asterisk and variable name
    - Add space between class name and extension parenthesis '()'
2015-05-13 01:13:41 +01:00
Ricardo Sánchez-Sáez 63ce90d4d3 ORKTaskTests: remove ORKT prefix in static variables 2015-05-13 00:24:23 +01:00
Ricardo Sánchez-Sáez 74d403b52d ORKTaskTests: remove ORKT prefix in static variables 2015-05-13 00:18:19 +01:00
Ricardo Sánchez-Sáez 3541f2b253 HeaderDoc format standardization: remove inline '*' characters; separate @param section from @return by newline; remove empty newline before closing comment. 2015-05-13 00:10:58 +01:00
Ricardo Sánchez-Sáez a923c426ed ORKtaskTests: rename 'getTaskSteps:stepIdentifiers:' to 'generateTaskSteps:stepIdentifiers:' 2015-05-12 23:59:02 +01:00
Ricardo Sánchez-Sáez 2c2e5254bc ORKtaskTests: rename 'getTaskSteps:stepIdentifiers:' to 'generateTaskSteps:stepIdentifiers:' 2015-05-12 23:53:14 +01:00
Ricardo Sánchez-Sáez ce28538a36 ORKTask: improve 'validateParameters' HeaderDoc comment 2015-05-12 23:44:35 +01:00
Eric DeLabar 1de5fcc6c2 Fixed Scale Slider autolayout for right-to-left 2015-05-12 14:26:24 -04:00
Eric DeLabar ee90b17351 Fixed typo in localizable strings file 2015-05-12 14:22:50 -04:00
Eric DeLabar f8211adf83 Code style and documentation changes 2015-05-12 14:19:43 -04:00
Coxy f5b440fd1f Code Styling 2015-05-12 14:46:53 +01:00
Coxy 619e9434a9 make suggested changes from PR comments 2015-05-12 14:07:58 +01:00
Bruce Duncan 2e01d033fb Merge branch 'master' into issue_1 2015-05-12 06:14:42 -04:00
Bruce Duncan dab4bcc047 First pass at a full implementation of Issue #1 2015-05-12 06:09:40 -04:00
Ricardo Sánchez-Sáez b68ad7b906 Add ORKTask and ORKFormStep unique identifier validation tests 2015-05-12 11:00:59 +01:00
Ricardo Sánchez-Sáez b7a70253d6 Merge branch 'master' of github.com:rsanchezsaez/ResearchKit into garnett-validation 2015-05-12 10:43:21 +01:00
Ricardo Sánchez-Sáez df04bf8235 ORKOrderedTask & ORKFormStep: unique identifier validation fixes 2015-05-12 10:22:55 +01:00
jwe-apple f56f6312e6 Merge pull request #170 from rsanchezsaez/rsanchezsaez-ipadmetrics
Fix margins in "Learn More" modal view
2015-05-11 18:03:33 -07:00
jwe-apple 912631f4d8 Merge pull request #168 from alexbasson/145-present-consent-in-form-sheet
Present consent "Learn More" content in form sheet
2015-05-11 17:56:16 -07:00
jwe-apple 61e8746cbd Merge pull request #157 from rsanchezsaez/rsanchezsaez-scaledefaultvalue
Fix ORKQuestionStepViewController losing its default value when going back
2015-05-11 17:20:39 -07:00
jwe-apple 51d666f1e8 Merge pull request #175 from rsanchezsaez/rsanchezsaez-constraints
Extract ORKDefineStringKey() (was 'DEF_KEY()') to helpers
2015-05-11 16:15:47 -07:00
Ricardo Sánchez-Sáez 6e8006b094 Extract ORKDefineStringKey() (was 'DEF_KEY()') to helpers 2015-05-11 23:15:41 +01:00
Coxy 5aabe018f0 remove offending line 2015-05-11 19:53:10 +01:00
jwe-apple 62745570c5 Merge pull request #173 from rsanchezsaez/rsanchezsaez-activesteps
ActiveStep fixes
2015-05-11 10:40:57 -07:00
jwe-apple 9a49196cd6 Merge pull request #172 from rsanchezsaez/rsanchezsaez-constraints
Constraints: make sure [super updateConstraints] is always called last
2015-05-11 10:37:07 -07:00
jwe-apple 9603fb8461 Merge pull request #169 from rsanchezsaez/rsanchezsaez-memorygame
Fix memory game layout jitter on iPad
2015-05-11 10:19:35 -07:00
Coxy 38cf7a4541 undo committed project configuration 2015-05-11 10:30:00 +01:00
Ricardo Sánchez-Sáez 78cafb6a52 Fix some erroneous init methods
(Local ivars were being set without checking if super init succeeded.)
2015-05-10 19:42:15 +01:00
Ricardo Sánchez-Sáez 4725b15bcd ORKAudioStep: replace 'duration' property by parent's 'stepDuration'
This mimics ORKCountdownStep, ORKFitnessStep and ORKWalkingTaskStep.
2015-05-10 19:41:29 +01:00
Ricardo Sánchez-Sáez d929de736e ORKFitnessStep, ORKTappingIntervalStep and ORKWalkingTaskStep: set shouldShowDefaultTimer to NO in init method
These three active step types don't support showing the default timer: setting this property to YES produces no effect.
2015-05-10 19:28:55 +01:00
Ricardo Sánchez-Sáez d4b73a8f42 ORKCountdownLabel: fix issue causing ORKActiveStepTimerView to always show 0 as the initial timer value 2015-05-10 18:38:50 +01:00
Ricardo Sánchez-Sáez f0a9e7d443 Constraints: make sure [super updateConstraints] is always called last (#99) 2015-05-10 17:25:59 +01:00
Ricardo Sánchez-Sáez 55198e7dad ORKConsentReviewController: enable bounce in webView 2015-05-10 02:30:18 +01:00
Ricardo Sánchez-Sáez be0c887b85 ORKConsentLearnMoreViewController: add margins to the contained webView
(Margins were removed from the HTML document.)
2015-05-10 02:27:32 +01:00
Ricardo Sánchez-Sáez 9c1bbbbaac ORKSpatialSpanMemoryStepViewController: adjust ORKScreenMetricMinimumStepHeaderHeightForMemoryGame metric to avoid iPad jitter 2015-05-10 00:20:51 +01:00
Ricardo Sánchez-Sáez d1126e228c ORKScaleSlider: fix comment typo 2015-05-10 00:20:22 +01:00
Alex Basson 623e33841f Present consent "Learn More" content in form sheet
Addresses issue #145
2015-05-08 20:14:00 -04:00
jwe-apple 3dedf8c373 Merge pull request #167 from rsanchezsaez/rsanchezsaez-skinfunctions
Standardize ORKSkin metric functions
2015-05-08 16:45:35 -07:00
jwe-apple c42f29fdad Merge pull request #166 from rsanchezsaez/rsanchezsaez-ipadmetrics
Consent review iPad metrics and margins homogenization
2015-05-08 16:43:51 -07:00
Ricardo Sánchez-Sáez 5d47c8e183 ORKSkin: standardize skin function names 2015-05-09 00:38:52 +01:00
Ricardo Sánchez-Sáez a56b351593 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-skinfunctions 2015-05-09 00:37:02 +01:00
Ricardo Sánchez-Sáez fd6e941159 ORKConsentReviewController: move margin from consent document HTML to view controller's webView
Also: handle webView scrollIndicatorInsets.
2015-05-09 00:23:53 +01:00
jwe-apple 115591c032 Merge pull request #164 from CareEvolution/Issue148
Fix for Issue #148 - [iPad] Two finger tapping task vertical spacing improvement
2015-05-08 15:59:25 -07:00
Ricardo Sánchez-Sáez 152557e5e4 ORKConsentReviewController: move constraint setup to 'setupConstraints' method 2015-05-08 23:30:16 +01:00
Ricardo Sánchez-Sáez f16bba3076 ORKConsentReviewController: add iPad horizontal margins 2015-05-08 23:27:26 +01:00
jwe-apple 21427d5795 Merge pull request #165 from rsanchezsaez/rsanchezsaez-constraints
ActiveStepQuantityView & SpatialSpanMemoryContentView constraint code whitespace
2015-05-08 14:43:46 -07:00
Ricardo Sánchez-Sáez 972879a85e ORKActiveStepQuantityView & ORKSpatialSpanMemoryContentView: homogenize constraint code whitespace and alignment 2015-05-08 22:23:38 +01:00
Eric DeLabar ae4af75736 Fix for Issue #148
- Added LAYOUT_DEBUG colors
- On iPad, added more space between title, progress bar, and tap count
2015-05-08 16:29:48 -04:00
Coxy b738688f00 fix NSCoding type warning 2015-05-08 20:59:26 +01:00
Eric DeLabar fc81624880 Added JSON serialization to ORKScaleAnswerFormats and added examples with min and max value labels to the ORKTest project 2015-05-08 14:21:18 -04:00
Eric DeLabar a622726b1b Fixed ORKTest build for changes in PR#162
- Fixed testORKSerialization to exclude the minimum and maximum value description on ORKScaleAnswerFormat.
2015-05-08 13:46:35 -04:00
Eric DeLabar caec12f51c Fixed per code review comments for PR#162 2015-05-08 13:42:22 -04:00
Coxy d090892754 device motion reaction time first attempt 2015-05-08 17:31:05 +01:00
Eric DeLabar e1f54278ca Set content mode to redraw on the ORKScaleSlider so the tick marks scale properly on device rotation 2015-05-08 10:12:12 -04:00
Eric DeLabar 7a26e368e7 Added minimum and maximum description labels to the ORKScaleSlider 2015-05-08 10:12:06 -04:00
Eric DeLabar ec63648083 Fixed autolayout warnings for ORKScaleSliderView 2015-05-08 09:35:30 -04:00
jwe-apple 806c7917d3 Merge pull request #161 from rsanchezsaez/rsanchezsaez-verticalscale
Make ORKSurveyAnswerCellForScale constraints static
2015-05-07 22:54:57 -07:00
jwe-apple 546b965c5b Merge pull request #160 from rsanchezsaez/rsanchezsaez-signaturescroll
Fix unable to draw signature when scrolling is enabled
2015-05-07 22:53:07 -07:00
jwe-apple efb78baf7d Merge pull request #159 from rsanchezsaez/rsanchezsaez-ipadmetrics
Fix signature view metrics
2015-05-07 22:48:43 -07:00
Ricardo Sánchez-Sáez 4cd9bd8122 ORKSurveyAnswerCellForScale: make constraints static (fixes #158) 2015-05-08 03:27:14 +01:00
Ricardo Sánchez-Sáez 37ca7a3704 ORKSignatureGestureRecognizer: prioritize over scrollView's pan gesture recognizer 2015-05-08 02:47:24 +01:00
Ricardo Sánchez-Sáez 236a4026ce ORKSignatureView: add device based width and height
(Avoids rotation issues, as the signature view width is determined by the portrait orientation of the device screen; the height is just a metric.) Also: increase iPad signature view size.
2015-05-08 02:20:14 +01:00
Ricardo Sánchez-Sáez 3e8bf44aea ORKScaleSlider: setNeedsLayout after thumb visibility changes 2015-05-08 00:35:22 +01:00
Ricardo Sánchez-Sáez 978a585cde ORKQuestionStepViewController: do not set stepResult.results if the answer is nil (fixes #135) 2015-05-07 23:16:43 +01:00
Ricardo Sánchez-Sáez aa5219cef6 ORKPredicateStepNavigationRule: rename getLeafResultsWithTaskResult to leafResultsFromTaskResult 2015-05-07 21:16:49 +01:00
Ricardo Sánchez-Sáez c20126a9ef iPad: allow upside down orientation in ORKCatalog and ORKTest 2015-05-07 21:00:39 +01:00
Ricardo Sánchez-Sáez 466dbb98c5 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules-dev
# Conflicts:
#	ResearchKit/Common/ORKVerticalContainerView.m
2015-05-07 19:12:31 +01:00
Ricardo Sánchez-Sáez 9169f9730f ORKPredicateStepNavigationRule: add additionalTaskResults property for cross-task navigation logic
(Including suitable unit tests.)
2015-05-07 19:05:47 +01:00
Ricardo Sánchez-Sáez 94c902d721 ORKNavigableOrderedTask: make stepNavigationRules a copy property 2015-05-07 17:59:02 +01:00
Ricardo Sánchez-Sáez 29c2829df0 ORKResultPredicate: make date method arguments nullable
(With their corresponding unit tests.)
2015-05-07 15:39:52 +01:00
vtourraine 075dc1f7b6 Add specific tone audiometry instruction step 2015-05-07 16:38:54 +02:00
Ricardo Sánchez-Sáez 8b4294f0dd ORKResultPredicate: replace CGFloat values by float; add minimum only and maximum only numeric and scale methods
(With their corresponding unit tests.)
2015-05-07 15:26:21 +01:00
Ricardo Sánchez-Sáez 27397735f4 ORKResultPredicate: added regular expression matching methods
Also: added the corresponding unit tests.
2015-05-07 15:07:54 +01:00
vtourraine e3c596ddb1 Update tone audiometry task with output volume in result 2015-05-07 15:27:15 +02:00
Ricardo Sánchez-Sáez b948c08d8f ORKPredicateStepNavigationRule: rename private initializer 2015-05-07 10:25:47 +01:00
Ricardo Sánchez-Sáez 5dd23fbb54 ORKOrderedTask and ORKStepNavigationRule: fix documentation issues 2015-05-07 01:46:55 +01:00
Ricardo Sánchez-Sáez 9ff7710b14 ORKPredicateStepNavigationRule: fix JSON serialization test failure due to empty array argument check 2015-05-06 23:21:54 +01:00
Ricardo Sánchez-Sáez 40e50fb0e6 ORKNavigableOrderedTask & ORKStepNavigationRule: add header documentation
Also: slight API refactor; add exceptions when trying to pass nil values; add removeNavigationRuleForTriggerStepIdentifier: method (with its unit test).
2015-05-06 22:52:13 +01:00
jwe-apple 5ba33f832d Merge pull request #136 from coxy1989/coxy-issue87_alert
Alert the user when an audioRecorder generates an error
2015-05-06 14:11:37 -07:00
Coxy c34852d677 make suggested change to incorrect condition in ORKAudioContentView 2015-05-06 21:52:21 +01:00
jwe-apple 46bd241ca3 Merge pull request #139 from rsanchezsaez/rsanchezsaez-ipadmetrics
Add iPad custom metrics
2015-05-06 13:40:37 -07:00
Ricardo Sánchez-Sáez b45628d543 ORKTaskTests: split testNavigableOrderedTask into individual test cases 2015-05-06 03:25:15 +01:00
Ricardo Sánchez-Sáez 9ea4786e21 ORKTaskTests: use NS_OPTIONS for bitmask options 2015-05-06 03:24:36 +01:00
Ricardo Sánchez-Sáez 6b03670808 ORKTaskTests: decouple testOrderedTask and testNavigableOrderedTask 2015-05-06 03:11:14 +01:00
Ricardo Sánchez-Sáez d4d874e312 ORKTaskTests: add tests for ORKResultPredicate convenience methods 2015-05-06 02:49:04 +01:00
Ricardo Sánchez-Sáez 6abc57b566 ORKResultPredicate: fix some issues with convenience methods 2015-05-06 02:48:12 +01:00
Ricardo Sánchez-Sáez d5fd81fd50 ORKTaskTests: use blocks for code reuse and legibility
Also moved some code around.
2015-05-06 00:57:04 +01:00
jwe-apple bfdebd914c Merge pull request #140 from rsanchezsaez/rsanchezsaez-observer
Remove unneeded @class forward declaration in ORKObserver
2015-05-05 16:20:24 -07:00
Ricardo Sánchez-Sáez 19fce1ac39 ORKTaskTests: sight improve to naming conventions
Also: fix ORKStepNavigationRule alignment.
2015-05-05 23:56:18 +01:00
Ricardo Sánchez-Sáez 117545160e ORKObserver: remove unneeded @class forward declaration 2015-05-05 23:11:25 +01:00
Ricardo Sánchez-Sáez 703155eb72 Add ORKTaskTests: tests ORKOrderedTask and ORKNavigableOrderedTask (and implicitly ORKPredicateStepNavigationRule and ORKDirectStepNavigationRule) 2015-05-05 23:09:22 +01:00
Ricardo Sánchez-Sáez c86bc22f71 Extract ORKDefineStringKey() ( was DEF_KEY() ) to helpers 2015-05-05 23:08:09 +01:00
Ricardo Sánchez-Sáez 31b792a795 ORKNavigableOrderedTask: support pushing and out of order step 2015-05-05 23:06:26 +01:00
vtourraine 70c8ef2e30 Rename ivars with underscores in audio generator 2015-05-05 09:25:14 +02:00
Ricardo Sánchez-Sáez 833f81296a ORKVerticalContainerView: move back updateConstraintConstants method 2015-05-04 19:01:01 +01:00
Ricardo Sánchez-Sáez bdf032553d Skin: reduce iPad ORKScreenMetricTopToIllustration 2015-05-04 18:44:22 +01:00
Ricardo Sánchez-Sáez 03cb3606c5 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-ipadmetrics
# Conflicts:
#	ResearchKit/Common/ORKSkin.m
2015-05-04 18:38:11 +01:00
jwe-apple 4d5f3307e5 Merge pull request #137 from rsanchezsaez/rsanchezsaez-verticalscale
Vertical scale improvement
2015-05-04 10:23:48 -07:00
Ricardo Sánchez-Sáez 9498cda223 iPad skin: adjust ORKScreenMetricTopToCaptionBaseline and add ORKScreenMetricTopToIllustration (issue #76) 2015-05-04 15:29:59 +01:00
vtourraine b338926f56 Update tone audiometry active task
- Remove 125 Hz test
- Switch to exponential fade-in, to make it linear in perception
2015-05-04 14:53:24 +02:00
Denis Lebedev 75fdaf6b09 Refactor validation: add -validateParameters to ORKTask 2015-05-04 12:44:48 +03:00
Denis Lebedev 2959667c65 Validate ORKFormStep items and ORKOrderedTask for identifier uniquiness 2015-05-04 12:33:54 +03:00
Ricardo Sánchez-Sáez db1f2a9ba5 ORKTest: add example of task archival and restoration (only for the ORKNavigableOrderedTask class) 2015-05-04 01:59:52 +01:00
Ricardo Sánchez-Sáez 1d4d307344 ORKNavigableOrderedTask: print debug warning if a navigation rule leads you to a step with a lower or equal index than the current one 2015-05-04 01:22:53 +01:00
Ricardo Sánchez-Sáez ac399005ba Add ORKResultPredicate class with convenience methods for building result-matching predicates. 2015-05-03 21:33:44 +01:00
Ricardo Sánchez-Sáez 0d45511b15 ORKStepNavigationRule and ORKNavigableOrderedTask: implement NSSecureCoding and NSCopying protocols
TODO: Implement NSPredicate JSON serialization.
2015-05-03 18:24:22 +01:00
Ricardo Sánchez-Sáez 19b5b34cc4 ORKNavigableOrderedTask: allow restoring the task to a particular step 2015-05-03 16:07:04 +01:00
Ricardo Sánchez-Sáez 2e7c58f48a ORKESerialization: fix bug in propFromDict() function 2015-05-03 16:00:26 +01:00
Ricardo Sánchez-Sáez 2a99e7d54f ORKNavigableOrderedTask: use a step identifier stack to handle stepBeforeStep: 2015-05-02 16:15:02 +01:00
Ricardo Sánchez-Sáez 378f5140de Whitespace 2015-05-02 15:30:56 +01:00
Ricardo Sánchez-Sáez 3027038744 StepNavigationTask: cleanup example; hide Learn More button 2015-05-02 15:30:13 +01:00
Ricardo Sánchez-Sáez 09e8b1d494 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-verticalscale 2015-05-02 13:43:43 +01:00
Ricardo Sánchez-Sáez 4881a32004 ORKSkin: add ORKScreenMetricVerticalScaleHorizontalMargin metric
This metric is used to adjust the vertical slider height so the vertical scale question step doesn't scroll by default on a single-line question (iPhone 5 and iPhone 6 screens only; multi-line questions will scroll). Also, replace English localized string "Your question goes here." by "Your question here." so it defaults to a single-line question on an iPhone 5 screen.
2015-05-02 13:39:08 +01:00
jwe-apple 9832cbc91f Merge pull request #130 from rsanchezsaez/rsanchezsaez-launchscreen
LaunchScreen: fix nav bar height and table view content inset
2015-05-01 12:51:24 -07:00
John Earl 5bc04aca3f Clean up bad merge 2015-05-01 11:14:49 -07:00
Ricardo Sánchez-Sáez 6030efaa96 ORKScaleSlider: subtract 5 pixels to vertical height (so the vertical scale question step fits without scrolling on iPhone 6) 2015-05-01 18:26:23 +01:00
Ricardo Sánchez-Sáez 0604f586df ORKStepNavigationRule: initial implementation 2015-05-01 17:04:41 +01:00
Coxy e59576640a alert the user when an audioRecorder generates an error 2015-05-01 13:16:05 +01:00
jwe-apple 3d44ed80c6 Merge pull request #113 from coxy1989/coxy-issue87
Audio predefined task: audio step should not show too loud if outputdir is nil and developer ignored the error
2015-04-30 21:10:06 -07:00
Ricardo Sánchez-Sáez 3378ab16f2 ORKScaleSlider: replace hitTest: by pointInside: (more efficient) 2015-04-30 14:15:09 +01:00
Coxy 8a5b6cc28d merge master 2015-04-29 19:08:03 +01:00
Coxy cc959e266f return early if audioRecorderError is not nil 2015-04-29 18:54:19 +01:00
Coxy 5e222351dc prevent silly UI updates after an audioRecorder has failed 2015-04-29 18:16:51 +01:00
vtourraine cf3ea70f77 Update tone audiometry task
- Add serialization tests
- Refactor constraints setup
- Fix localization typos
2015-04-29 11:17:56 +02:00
Ricardo Sánchez-Sáez 71c97a72b6 LaunchScreen: fix nav bar height and table view content inset 2015-04-28 23:32:32 +01:00
jwe-apple 4639a41eea Merge pull request #129 from rsanchezsaez/rsanchezsaez-namingconventions
Naming conventions: 'ident' is not an acceptable abbreviation
2015-04-28 13:18:46 -07:00
John Earl 965b39fe4a Merge branch 'jwe-apple-jwe-apple-issue-118b' 2015-04-28 12:56:09 -07:00
John Earl 4a55ec228c Merge branch 'jwe-apple-issue-118b' of https://github.com/jwe-apple/ResearchKit into jwe-apple-jwe-apple-issue-118b 2015-04-28 12:55:55 -07:00
Ricardo Sánchez-Sáez 14dd7a7c73 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-namingconventions 2015-04-28 20:53:10 +01:00
jwe-apple 1b0d93e247 Merge pull request #127 from richardrauser/RemoveDuplicateImports
Removing duplicate imports.
2015-04-28 12:50:52 -07:00
jwe-apple 4047451e4d Merge pull request #108 from rsanchezsaez/rsanchezsaez-ipadmargins
Add horizontal iPad margins
2015-04-28 12:32:41 -07:00
jwe-apple f602e85b75 Merge pull request #123 from jwe-apple/jwe-apple-issue-122
Issue #122: `shouldPresentStep:` method should correctly handle nil step
2015-04-28 12:21:28 -07:00
John Earl 3ad592e27c Whitespace fixup 2015-04-28 12:19:39 -07:00
John Earl 7ab47f3a88 Whitespace fixup 2015-04-28 12:17:00 -07:00
Ricardo Sánchez-Sáez fe82617dc5 Naming conventions: 'ident' is not an acceptable abbreviation
(https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html#//apple_ref/doc/uid/20001285-BCIHCGAE)
2015-04-28 19:43:30 +01:00
Ricardo Sánchez-Sáez ed740fe7d3 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-ipadmargins
# Conflicts:
#	ResearchKit/Common/ORKScaleSliderView.m

Also: do some whitespace conforming on the merged code.
2015-04-28 19:33:53 +01:00
jwe-apple 621652b26f Merge pull request #128 from getaaron/update-pdf-documentation
Indicate that consent document must be copied for signature to be applied correctly
2015-04-28 10:12:14 -07:00
Aaron Brager a0adc6c557 Indicate that consent document must be copied for signature to be applied correctly. 2015-04-28 08:58:32 -05:00
Ricardo Sánchez-Sáez 227e5af903 ORKUpdateScrollViewBottomInset(): Perform safe CGFloat comparison
Adds ORKCGFloatNearlyEqualToFloat() inline function to ORKHelpers.
2015-04-28 14:55:45 +01:00
Ricardo Sánchez-Sáez 01d2c72c2d ORKSkin: restore iPad ORKScreenMetricIllustrationHeight (for adapted @3x images)
(It was squished during the merge, sorry.)
2015-04-28 13:44:42 +01:00
Richard Rauser fcb9fb61b0 Removing duplicate imports. 2015-04-28 12:48:02 +01:00
jwe-apple 75c05d200b Merge pull request #126 from troligtvis/master
duplicate initialization of variable removed
2015-04-28 03:18:58 -07:00
strawberrypie 9e12bed600 duplicate initialization of variable removed 2015-04-28 12:14:38 +02:00
John Earl b3c64fc66b Merge branch 'brucehappy-issue_4' 2015-04-28 03:01:49 -07:00
John Earl edb78414ec Merge branch 'issue_4' of https://github.com/brucehappy/ResearchKit into brucehappy-issue_4 2015-04-28 03:01:20 -07:00
vtourraine 1d89b53c78 Update tone audiometry step controller dispatch, audio generator license 2015-04-28 11:52:16 +02:00
jwe-apple 706244f95d Merge pull request #124 from troligtvis/master
Small typo corrected
2015-04-28 02:43:46 -07:00
John Earl 643be7ee8b Issue #118: Adjust fitness quantity pair layout
This fixes a regression in quantity pair layout. The left view of
the quantity pair, the distance view, formerly always contained
content, which fixed the vertical height of the view. At some point
that content was no longer set, handling the no-pedometer-distance
case. The primary fix here is to ensure that a title and zero
quantity are present in the distance view, even if distance is
not available (as in the simulator).

Secondary fixes fix constraints to make them static, since they
do not need to be dynamically updated. We also introduce new baseline
constraints to better enforce alignment between the left and right
views.

Tested distance-only, heart-rate-only, both, and neither visible on
iPhone 6 on iOS 8.3. Tested with and without a value for heart rate,
with both visible.
2015-04-28 02:35:51 -07:00
vtourraine 0ba31ce525 Update tone audiometry task implementation
- Add English and French localization
- Update copyright notices
- Fix code style
- Fix comments typo
2015-04-28 11:00:43 +02:00
Coxy efc1394987 move audio outputdir nil exception to ORKAudioRecorder's start method 2015-04-28 09:46:09 +01:00
strawberrypie 0997555a34 small typo corrected 2015-04-28 09:44:17 +02:00
strawberrypie b48ac27ec8 small typo corrected 2015-04-28 09:43:10 +02:00
John Earl dc35088d39 Issue #122: shouldPresentStep: method should correctly handle nil step
Adjust internal `shouldPresentStep:` method not to call the delegate
on a nil step, and to return NO if the step is nil. When the task has
completed, a nil step indicates this, so handle that case explicitly
rather than depending on a semantically odd `YES` from `shouldPresentStep:`.
2015-04-27 23:47:21 -07:00
Ricardo Sánchez-Sáez 139a3f6d00 ORKUpdateScrollViewBottomInset: make sure bottomInset actually changes before updating
Also: remove needless log line in ORKTableContainerView.
2015-04-28 01:36:21 +01:00
Ricardo Sánchez-Sáez 4c25cc50ee Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-ipadmargins
# Conflicts:
#	ResearchKit/ActiveTasks/ORKAudioContentView.m
#	ResearchKit/Common/ORKChoiceViewCell.m
#	ResearchKit/Common/ORKHelpers.m
#	ResearchKit/Common/ORKScaleSliderView.m
#	ResearchKit/Common/ORKSkin.m
#	ResearchKit/Common/ORKSurveyAnswerCellForText.m
2015-04-28 01:16:51 +01:00
Ricardo Sánchez-Sáez a48796942c ORKTableContainerView: adjust scrollIndicatorInsets on iPad screen size
Their position is now next to the edge of the screen (instead of next to the edge of the table).
Also: reuse on-screen keyboard inset handling code.
2015-04-28 00:55:46 +01:00
Ricardo Sánchez-Sáez 136471090e ORKSkin: change iPhone 6 and down default margin from 16.0 to 15.0 2015-04-27 23:56:19 +01:00
Ricardo Sánchez-Sáez a27ecaa20a ORKFormStepViewController: fix table and footer not being layout properly 2015-04-27 23:54:38 +01:00
jwe-apple 31ea7908a2 Merge pull request #116 from rsanchezsaez/rsanchezsaez-whitespace
Complete whitespace homogenization
2015-04-27 13:59:11 -07:00
Ricardo Sánchez-Sáez 2930653a98 ORKTest AppDelegate: revert to multiline comments 2015-04-27 20:55:40 +01:00
Ricardo Sánchez-Sáez 9604154b17 Naming conventions renames 2015-04-27 19:56:06 +01:00
Ricardo Sánchez-Sáez 709dec2841 Make sure statement opening brace always has a prepending space 2015-04-27 19:54:31 +01:00
Ricardo Sánchez-Sáez e3cca38a69 Homogeneous else braces 2015-04-27 19:49:03 +01:00
Ricardo Sánchez-Sáez 66f5452a35 Conform to cocoa naming conventions 2015-04-27 19:41:39 +01:00
Ricardo Sánchez-Sáez 9b4f0a404d Homogenize whitespace (ORKTests)
Also: some naming conventions renames.
2015-04-27 19:16:48 +01:00
Ricardo Sánchez-Sáez dbdabb49c2 Homogenize whitespace (Accessibility and Unit Tests)
Also: naming conventions renames.
2015-04-27 19:00:10 +01:00
Coxy ac1cf8e16e Move nil outputdir exception from viewDidAppear: to prepareStep 2015-04-27 18:58:07 +01:00
Ricardo Sánchez-Sáez 226791c774 Homogenize whitespace (Consent)
Also: naming conventions renames.
2015-04-27 18:46:37 +01:00
Ricardo Sánchez-Sáez 08a378b6b8 Homogenize whitespace (ActiveTasks)
Also: naming conventions renames.
2015-04-27 18:14:59 +01:00
Ricardo Sánchez-Sáez 71008fcc05 Homogenize whitespace (Skin, Misc)
Also: some naming conventions renames.
2015-04-27 17:07:14 +01:00
Bruce Duncan d50d647ffd Added braces, and don't reference the sliderLayoutWidth from the delegate more than once. 2015-04-27 11:56:00 -04:00
Ricardo Sánchez-Sáez 1a8f9e81bd Homogenize whitespace (PDF, Definitions, UIKitCategories)
Also: some naming conventions renames.
2015-04-27 16:49:54 +01:00
Ricardo Sánchez-Sáez a200c992ae Homogenize whitespace (Result and Container Views)
Also: some naming conventions renames.
2015-04-27 16:13:59 +01:00
vtourraine 91821ca5ae Add new tone audiometry active task, include it in the ORKCatalog app 2015-04-27 17:02:38 +02:00
Coxy a739df5f69 Merge branch 'master' into coxy-issue87 2015-04-27 11:35:30 +01:00
jwe-apple 5cd75fc585 Merge pull request #112 from rsanchezsaez/rsanchezsaez-whitespace
Homogenize whitespace [wip]
2015-04-26 22:34:40 -07:00
Ricardo Sánchez-Sáez 28a54aac7c Homogenize whitespace (Answer format)
Also: some naming conventions renames; remove empty inherited init.
2015-04-27 01:54:38 +01:00
Ricardo Sánchez-Sáez 35841e2ba8 Homogenize whitespace (Task and Step)
Also: some naming conventions renames; remove unneeded empty return.
2015-04-27 01:19:07 +01:00
Ricardo Sánchez-Sáez 77bb256cfa Move some stray opening braces 2015-04-27 00:31:57 +01:00
Ricardo Sánchez-Sáez 74ab1b3726 Re-work iPad margins calculations
Previous approach had several problems: applied doble iPad margin on text choice questions; didn't handle correctly separator right inset in numeric and text questions.
2015-04-26 23:58:09 +01:00
Ricardo Sánchez-Sáez 49256010d5 ORKSkin: code reuse for ORKGetScreenTypeForWindow() and ORKGetScreenTypeForWindow() 2015-04-26 13:06:11 +01:00
Coxy e15f56ff6e Audio step should not show too loud if outputdir is nil and developer ignored the error (issue #87) 2015-04-25 14:28:36 +01:00
Ricardo Sánchez-Sáez 3ed725399c ORKSkin & client classes: add iPad margins 2015-04-25 01:44:29 +01:00
jwe-apple 3e48fc66a8 Merge pull request #107 from brucehappy/issue_78
Make visual assets bigger on iPad (issue #78)
2015-04-24 17:09:04 -07:00
Bruce Duncan ae6fdc65d2 Formatting change 2015-04-24 19:58:41 -04:00
Bruce Duncan 74a3f4b589 Changed ResearchKit to compile for iPhone and iPad. Changed all universal images for Active and Consent tasks into device specific. Copied @3x images to @2x~ipad. Added iPad screen size and changed the metrics for ORKScreenMetricIllustrationHeight to be 1.5x the iPhone 6 value. Forced the 3x videos to be used for iPad 2x and 2x videos to be used for iPad 1x. 2015-04-24 19:40:49 -04:00
Ricardo Sánchez-Sáez 2df6cc99e1 ORKSkin: Move some layout methods from ORKHelpers
Also:
- Add ORKScreenTypeiPhone6Plus and ORKScreenTypeiPad
- Use constants instead of magic numbers or defines
2015-04-25 00:09:05 +01:00
jwe-apple 713b27060f Merge pull request #106 from evanmiller/evanmiller-activetasks-table
Active Task docs: add thead/tbody tags to table
2015-04-24 16:01:27 -07:00
jwe-apple 8cb90d81c1 Merge pull request #105 from evanmiller/evanmiller-activetasks-typo
Fix typo in ActiveTasks template
2015-04-24 15:59:49 -07:00
Evan Miller 1f3ea67c73 Active Task docs: add thead/tbody tags to table 2015-04-24 17:53:07 -05:00
Evan Miller d18907ea56 Fix typo in ActiveTasks template
Remove extraneous "to"
2015-04-24 17:48:01 -05:00
jwe-apple ef2eec6926 Merge pull request #104 from rsanchezsaez/rsanchezsaez-unnecessarycasts
Remove unnecessary casts
2015-04-24 14:58:27 -07:00
Ricardo Sánchez-Sáez 553c675eab HKSample(ORKJSONDictionary): remove anonymous category 2015-04-24 22:52:36 +01:00
Ricardo Sánchez-Sáez b8e24f456d HKSample(ORKJSONDictionary): enforce type safety regarding mutableDictionaries (and avoid mutableCopying)
Also: naming conventions.
2015-04-24 22:40:38 +01:00
jwe-apple 4a518c8d9a Merge pull request #103 from evanmiller/evanmiller-overview-semicolon
Fix small grammatical issue
2015-04-24 14:23:51 -07:00
Ricardo Sánchez-Sáez eb30a43ac6 Remove unnecessary casts 2015-04-24 22:06:14 +01:00
Evan Miller 47babbc318 Fix small grammatical issue
Use a semicolon instead of a comma.

Also add a newline to the end of the file.
2015-04-24 16:03:08 -05:00
Bruce Duncan 711fed4ff5 Don't check delegate for nil, as sliderLayoutWidth will return 0 if it is anyway. 2015-04-24 15:11:51 -04:00
jwe-apple 0c2bdc488f Merge pull request #101 from evanmiller/evanmiller-creatingsurveys-codesample
Tweak code sample
2015-04-24 09:14:08 -07:00
DanKeen 4cbd40f0d7 Merge pull request #102 from evanmiller/evanmiller-creatingsurveys-typo
Fix typo in documentation
2015-04-24 08:13:04 -07:00
Evan Miller 0df2d9a98b Fix typo in documentation
Remove extraneous quotation mark
2015-04-24 09:31:30 -05:00
Evan Miller 6d1e80a583 Tweak code sample
* firstResult is a property of the ORKStepResult

* Remove extraneous space from the if statement
2015-04-24 09:21:13 -05:00
Bruce Duncan daa7f7cd52 Eliminated the unneeded updateConstraints and moved constraint setting to the initializer. Fixed spacing on if statement. 2015-04-24 01:42:33 -04:00
Bruce Duncan 4f792442b1 Fixed spacing of if expression 2015-04-24 01:13:34 -04:00
Bruce Duncan 1e8002279d Merge branch 'master' into issue_4 2015-04-24 00:30:32 -04:00
Bruce Duncan 9eb1d445bb Merge branch 'master' into issue_4.
Removed hardcoded cell height for vertical layout scales and used auto layout plus delegate for height.
2015-04-24 00:25:31 -04:00
jwe-apple 1b1954e9ca Merge pull request #100 from evanmiller/evanmiller-activetasks-typos
Fix spelling error
2015-04-23 20:30:58 -07:00
Evan Miller 46236a4a08 Fix spelling error
preformed => performed
2015-04-23 19:52:27 -05:00
jwe-apple ee2127397b Merge pull request #96 from rsanchezsaez/rsanchezsaez-visualconsentscroll-b
Fix visual consent scene scroll
2015-04-23 15:21:00 -07:00
jwe-apple ac1dd33c34 Merge pull request #98 from rsanchezsaez/rsanchezsaez-centerpickers
Center pickers on iPad
2015-04-23 15:19:58 -07:00
Ricardo Sánchez-Sáez 8586381fb6 ORKSurveyAnswerCellForPicker: make sure constraints don't accumulate; add _tempPicker constraint 2015-04-23 23:06:28 +01:00
Ricardo Sánchez-Sáez e79c7d25d4 ORKObserver: remove new and init NS_UNAVAILABLE annotations; add nullability and designated initializer ones 2015-04-23 20:36:11 +01:00
Ricardo Sánchez-Sáez 21dba1f124 ORKSurveyAnswerCellForPicker: center pickers on iPad 2015-04-23 12:41:21 +01:00
Ricardo Sánchez-Sáez 3251a5226c ORKObserver: reuse initializer code 2015-04-23 10:38:43 +01:00
Ricardo Sánchez-Sáez ccf6b461bc Move back ORKViewControllerToolbarObserver to ORKTaskViewController file
Also: rename some variables for naming convention conformance.
2015-04-23 09:25:16 +01:00
John Earl 45215ecb0e Additional nullability corrections 2015-04-22 22:15:02 -07:00
John Earl 439df0718b Quick fix: nullability warnings 2015-04-22 22:10:52 -07:00
Ricardo Sánchez-Sáez 3c3eb5cb02 ORKVisualConsentStepViewController: add safety check on scrollViewObserver delegate method 2015-04-23 01:28:22 +01:00
Ricardo Sánchez-Sáez 6a895b4b5c ORKObserver: fix naming conventions and copyright headers 2015-04-23 01:28:03 +01:00
jwe-apple 720aed5388 Merge pull request #95 from rsanchezsaez/rsanchezsaez-singletextchoice
Fix single text choice cell should not deselect when re-selecting the same answer
2015-04-22 17:01:05 -07:00
Ricardo Sánchez-Sáez e2950decc2 ORKVisualConsentStepViewController: use NSRunLoopCommonModes for CADisplayLink so animation doesn't freeze when scrolling
Also, simultaneously scrollToTop animationView with scrollView
2015-04-23 00:51:43 +01:00
Ricardo Sánchez-Sáez f9e119acad ORKTextChoiceCellGroup: single text choice cell should not deselect when re-selecting the same answer
Also: fixed tests accordingly.
2015-04-23 00:14:05 +01:00
Ricardo Sánchez-Sáez bbda212a04 ORKVisualConsentStepViewController: enable scene scrolling before video animation finish and track animation view position with scrollView contentOffset 2015-04-22 23:06:16 +01:00
Ricardo Sánchez-Sáez 891c096bc1 Generalize and extract ORKObserver and subclasses for reuse 2015-04-22 22:33:24 +01:00
Ricardo Sánchez-Sáez cec9c3acf6 Merge remote-tracking branch 'upstream/master' into rsanchezsaez-visualconsentscroll 2015-04-22 21:56:25 +01:00
Ricardo Sánchez-Sáez 2612aca236 ORKVisualConsentStepViewController: register consent scene scrollView with taskViewController (enables hairline) 2015-04-22 20:30:16 +01:00
Dan Keen 2272d2e6db Update sub-headings in code examples to italicize.
r=jwe
2015-04-22 11:34:31 -07:00
John Earl ed8960f8b5 Disable unit tests from ORKTest scheme in 'Run' mode 2015-04-22 11:08:40 -07:00
John Earl 0f8a07fd8f Merge branch 'rsanchezsaez-rsanchezsaez-firstrespondercell' 2015-04-22 10:43:57 -07:00
John Earl 93c9c8d85a Merge branch 'rsanchezsaez-firstrespondercell' of https://github.com/rsanchezsaez/ResearchKit into rsanchezsaez-rsanchezsaez-firstrespondercell
Conflicts:
	ResearchKit/Common/ORKFormStepViewController.m
2015-04-22 10:43:50 -07:00
John Earl 25c543c468 Merge branch 'garnett-moar-tests' 2015-04-22 10:40:16 -07:00
John Earl fb519862b8 Merge branch 'moar-tests' of https://github.com/garnett/ResearchKit into garnett-moar-tests
Conflicts:
	ResearchKit/ActiveTasks/ORKVoiceEngine.m
2015-04-22 10:39:59 -07:00
John Earl 681891b300 Merge branch 'codestergit-fixed-formatting-of-curly-braces' 2015-04-22 10:35:09 -07:00
John Earl 1c5b93cae6 Merge branch 'fixed-formatting-of-curly-braces' of https://github.com/codestergit/ResearchKit into codestergit-fixed-formatting-of-curly-braces
Conflicts:
	ResearchKit/ActiveTasks/ORKAccelerometerRecorder.m
	ResearchKit/ActiveTasks/ORKAudioRecorder.m
	ResearchKit/ActiveTasks/ORKDataLogger.m
	ResearchKit/ActiveTasks/ORKDeviceMotionRecorder.m
	ResearchKit/ActiveTasks/ORKHealthQuantityTypeRecorder.m
	ResearchKit/ActiveTasks/ORKLocationRecorder.m
	ResearchKit/ActiveTasks/ORKPedometerRecorder.m
	ResearchKit/ActiveTasks/ORKRecorder.m
	ResearchKit/ActiveTasks/ORKTouchRecorder.m
	ResearchKit/Common/ORKAnswerFormat.m
	ResearchKit/Common/ORKQuestionStepViewController.m
	ResearchKit/Common/ORKResult.m
	ResearchKit/Common/ORKScaleSlider.m
	ResearchKit/Common/ORKSurveyAnswerCellForText.m
	ResearchKit/Consent/ORKConsentSignature.m
	ResearchKit/Consent/ORKEAGLMoviePlayerView.m
2015-04-22 10:34:57 -07:00
Ricardo Sánchez-Sáez 8a7ea2d051 ORKFormStepViewController: clear 'currentFirstResponderCell' on formItemCellDidResignFirstResponder: 2015-04-22 18:34:19 +01:00
jwe-apple 12148d0973 Merge pull request #79 from rsanchezsaez/rsanchezsaez-visualconsentscroll
Add scroll to visual content screens
2015-04-22 10:01:30 -07:00
Ricardo Sánchez-Sáez acd1f4379c ORKTableContainerView & ORKFormItemCell: add nullable attribute to delegate property 2015-04-22 15:21:48 +01:00
Ricardo Sánchez-Sáez 2a7d12381f ORKTableContainerView: track current first responder cell via delegate (for keyboard scrolling)
Also: remove 'ork_currentFirstResponderView' hack method.
2015-04-22 15:03:26 +01:00
Ricardo Sánchez-Sáez 2541fa2835 ORKVisualConsentStepViewController: make sure scrollToTopAnimated: is finished before starting transition (re-enable scrolling otherwise)
Also: remove needless delegate conformance, add comment, add copyright.
2015-04-22 12:02:06 +01:00
jwe-apple ca43fbf341 Merge pull request #80 from garnett/enable-ipad
Make apps universal, remove healthkit requirement
2015-04-22 00:34:44 -07:00
Denis Lebedev 745fb12b9b Fix actionSheet presentation on iPad 2015-04-22 09:12:09 +03:00
Denis Lebedev edb33fa975 Make apps universal, remove healthkit requirement 2015-04-22 08:55:54 +03:00
Denis Lebedev 0984008494 Update copyrights with contributor's name 2015-04-22 08:47:15 +03:00
Ricardo Sánchez-Sáez ca0b2b2a5c Move visual content scroll test task from ORKCatalog to ORKTest 2015-04-22 02:53:59 +01:00
Ricardo Sánchez-Sáez a4fad3df74 ORKVisualConsentStepViewController & ORKConsentSceneViewController: replace 'setContentOffset:' by bounds animation with completion block 2015-04-22 02:44:46 +01:00
Ricardo Sánchez-Sáez 0c6b420744 ORKVisualConsentStepViewController & ORKConsentSceneViewController: allow vertical scrolling in visual consent screens 2015-04-22 00:40:25 +01:00
John Earl 9aa69cd1ef Fix build after merging rsanchezsaez-rsanchezsaez-verticalscale 2015-04-21 14:34:52 -07:00
John Earl 6bf1e4aec5 Merge branch 'rsanchezsaez-rsanchezsaez-verticalscale' 2015-04-21 12:44:53 -07:00
John Earl cfe35edfef Merge branch 'rsanchezsaez-verticalscale' of https://github.com/rsanchezsaez/ResearchKit into rsanchezsaez-rsanchezsaez-verticalscale
Conflicts:
	ResearchKit/Common/ORKScaleSlider.m
2015-04-21 12:44:32 -07:00
Ricardo Sánchez-Sáez cdff825c7b ORKQuestionStep: rename 'isFormatVertical' to 'isFormatVerticalScale' 2015-04-21 20:18:50 +01:00
Ricardo Sánchez-Sáez 881f01a2d5 ORKScaleSlider: widen vertical scale tap target 2015-04-21 19:34:13 +01:00
John Earl 793deeec7d Convert assertions to exceptions so they are applied in release builds too. 2015-04-21 11:33:24 -07:00
Ricardo Sánchez-Sáez 3d5abb0b7a ORKScaleSlider: add comment about thumb rotation issue 2015-04-21 19:32:49 +01:00
Ricardo Sánchez-Sáez ed88a71af0 ORKScaleSlider: revert to explicit use of '[self bounds]' method instead of 'self.bounds' 2015-04-21 19:27:32 +01:00
Ricardo Sánchez-Sáez aed6935765 ORKAnswerFormat: & ORKQuestionStep: replace 'ORKQuestionTypeVerticalScale' type by 'isVertical' method querying 2015-04-21 19:24:09 +01:00
Denis Lebedev 022fe854b0 Return nullability to ORKVoiceEngine_internal 2015-04-21 07:42:50 +03:00
Ricardo Sánchez-Sáez 4039555bbc ORKTest: add vertical scales to scale task 2015-04-21 01:31:28 +01:00
Ricardo Sánchez-Sáez 0453c28748 ORKScaleAnswerFormat & ORKContinuousScaleAnswerFormat: more 'verticalFlag' to 'vertical' renaming 2015-04-21 01:29:47 +01:00
Ricardo Sánchez-Sáez a8affe5e06 ORKScaleAnswerFormat & ORKContinuousScaleAnswerFormat: handle vertical property in NSCoding; add it to serialization tests and testTaskModel
Also fix MainViewController scale answer format calls.
2015-04-21 01:15:08 +01:00
jwe-apple e5e2f5810e Merge pull request #64 from pbodsk/master
replacing (id) with (instancetype) in initWithCoder: methods
2015-04-20 15:05:03 -07:00
Yuan Zhu c9983cae47 Merge pull request #57 from mharper/master
Adds Swift code snippets for Getting Started
2015-04-20 14:07:52 -07:00
Michael Harper dcca7bf200 Remove self. from method calls
Conforms to Swift style per @YuanZhu-Apple.
2015-04-20 14:04:02 -07:00
Ricardo Sánchez-Sáez a08f8ee42d ORKAnswerFormat: rename 'verticalFlag' argument to 'vertical' 2015-04-20 21:01:51 +01:00
jwe-apple 2f81b9d31d Merge pull request #58 from rsanchezsaez/rsanchezsaez-plaintextstrings
Convert all non-English Localizable.strings to human-readable format
2015-04-20 12:49:29 -07:00
pbodsk adfe0147ab replacing (id) with (instancetype) in initWithCoder: methods 2015-04-20 21:48:59 +02:00
jwe-apple f750ccff78 Merge pull request #48 from wczekalski/improvement/Dynamic-Cast-Macro
Fixed possible double evaluation in the ORKDynamicCast macro
2015-04-20 12:37:40 -07:00
jwe-apple 95634467f6 Merge pull request #44 from rsanchezsaez/rsanchezsaez-recorderidentifier
Add identifier to ORKRecorderConfiguration and ORKRecorder
2015-04-20 12:36:26 -07:00
Ricardo Sánchez-Sáez d9b0e5dfed ORKScaleSlider: reset _thumbImageNeedsTransformUpdate flag
Also: don't use '_' prefix for method names.
2015-04-20 19:55:02 +01:00
Ricardo Sánchez-Sáez 59ac68442f ORKScaleSlider: minor optimization to _thumbImageSubview method 2015-04-19 16:02:36 +01:00
Ricardo Sánchez-Sáez 483cf7cd11 plist-to-strings.py: improve comments and inner function name 2015-04-19 14:16:47 +01:00
Ricardo Sánchez-Sáez 3817139626 plist-to-strings.py: move argument checks and logging outside function 2015-04-19 13:53:45 +01:00
Ricardo Sánchez-Sáez 4ec792498e plist-to-strings.py: remove unneeded import 2015-04-19 13:46:23 +01:00
Ricardo Sánchez-Sáez ad87af34cf plist-to-strings.py: add Python version information 2015-04-19 02:51:58 +01:00
Ricardo Sánchez-Sáez 52550021a9 Localizable.strings: convert all localized .strings files to plaintext 2015-04-19 02:48:31 +01:00
Ricardo Sánchez-Sáez 686fb2458a Add plist-to-strings.py script
It can be used to convert binary .strings files to plaintext .strings files. It takes a master plaintext .strings file for the key sort order of the converted file.
2015-04-19 02:47:58 +01:00
Ricardo Sánchez-Sáez 62cff57325 Add copyright line to ORKScaleSlider & ORKScaleSliderView 2015-04-19 00:06:15 +01:00
Ricardo Sánchez-Sáez 9877ec749e ORKOrderedTask: reuse recorder identifiers between steps
Also added my copyright line.
2015-04-19 00:01:13 +01:00
Ricardo Sánchez-Sáez 22d0de778b ORKRecorderConfiguration & friends: move base class initializers to the private header 2015-04-18 23:14:08 +01:00
Michael Harper 598b275a1a Adds Swift code snippets for Getting Started 2015-04-18 14:31:39 -07:00
Ricardo Sánchez-Sáez f0675d2646 ORKRecorder subclasses: remove needless casts
Also improved some code alignment.
2015-04-18 22:29:01 +01:00
Ricardo Sánchez-Sáez 15be84da3b ORKRecorder.h: improve documentation whitespace alignment 2015-04-18 22:28:47 +01:00
Ricardo Sánchez-Sáez 553b27735b ORKScaleSlider: improve code formatting (braces, whitespace) 2015-04-18 21:16:28 +01:00
Ricardo Sánchez-Sáez c7d27e2e0a ORKScaleSlider: keep thumbImage view original orientation in vertical scale 2015-04-18 21:13:33 +01:00
Denis Lebedev 83eb2a5766 Remove newline 2015-04-18 13:11:36 +03:00
Denis Lebedev 5ecb0490a9 Split tests 2015-04-18 12:26:13 +03:00
Denis Lebedev ecac08f098 Modify accessors in ORKVoiceEngineTests 2015-04-18 12:26:01 +03:00
Denis Lebedev 3db44a194d Make speachSynthesizer readonly 2015-04-18 12:15:52 +03:00
Denis Lebedev fc0f58e664 Remove nullability annotations 2015-04-18 12:09:50 +03:00
Denis Lebedev f9b46de2be Rename test class 2015-04-18 12:08:04 +03:00
Bruce Duncan c6df59cfbb Removed the need for a fixed cell height (140) for both Form and Question Step table cells containing scales. Removed the need for fixing the baseline of the value label in relation to the slider to a magic number. Force the value label to always use the height of its font for its intrinsic size, even when its content is empty string, which can happen on scale's with no value set. 2015-04-18 04:00:18 -04:00
Wojtek Czekalski 5f3c5ccd7d #48: Fixed code formatting issues 2015-04-18 09:04:53 +02:00
Yuan Zhu f4c30882c7 Merge pull request #56 from mluedke2/master
Corrects typo in a comment
2015-04-17 22:24:24 -07:00
mluedke2 aa150c1fa7 comment typo 2015-04-17 22:20:45 -07:00
jwe-apple f4949f859d Merge pull request #54 from jhersh/podspec-version
[Podspec] Fixed tag naming
2015-04-17 16:43:45 -07:00
Yuan Zhu 4fe283f294 Merge pull request #52 from mattshedlick/modern_syntax
Updating to use modern Objective-C syntax.
2015-04-17 16:03:50 -07:00
Yuan Zhu f78bbece03 Merge pull request #53 from mattshedlick/using_instancetype
Updating init methods that return id to return instancetype instead.
 initWithCoder: still returns (id) so those were left alone.
2015-04-17 15:52:03 -07:00
Jonathan Hersh d77dc73201 [Podspec] Fixed tag naming 2015-04-17 15:48:33 -07:00
Matthew Shedlick 3d39c73a37 Updating init methods that return (id) to return (instancetype) instead. 2015-04-17 18:46:26 -04:00
Matthew Shedlick 7142e9e4eb Updating to use modern Objective-C syntax. 2015-04-17 18:37:20 -04:00
jwe-apple 94a47a4b3a Merge pull request #5 from dasmer/master
Adds dependency management documentation (and CocoaPods support)
2015-04-17 15:30:59 -07:00
Denis Lebedev 18988376aa Add ORKVoiceEngineTests 2015-04-18 01:12:40 +03:00
Denis Lebedev 37673a096b Add tests for UIView+ORKAccessibility 2015-04-18 00:38:38 +03:00
Ricardo Sánchez-Sáez 44f6355977 ORKRecorderTests: add test for identifier propagation from recorder configuration to recorder 2015-04-17 22:25:11 +01:00
Yuan Zhu c0d84dc4a9 Merge pull request #49 from philliptharris/veryMinorTypo
Very minor typo fix
2015-04-17 14:24:36 -07:00
Phillip Harris d9739e0843 Very minor typo fix 2015-04-17 17:07:17 -04:00
Ricardo Sánchez-Sáez 47261f181c ORKRecorder: add my copyright info 2015-04-17 20:51:37 +01:00
Wojtek Czekalski 447594d36c Fixed possible double evaluation in the ORKDynamicCast macro 2015-04-17 21:49:37 +02:00
Ricardo Sánchez-Sáez 8c39fcf935 ORKRecorder & friends: improve documentation 2015-04-17 20:37:36 +01:00
codestergit fbbfac9a23 fixed formatting of curly braces in all files 2015-04-18 01:02:57 +05:30
Ricardo Sánchez-Sáez 49e79ab9f4 ORKRecorder: use recorder identifier for data log filename instead of step identifier 2015-04-17 20:26:43 +01:00
Dasmer Singh fc558417ac Set Xcode's Public files and Private files as podspec's public_header_files
[dependency_management.md] Fix typo

[Podspec] Add Xcode Public and Private files to public_header_files
2015-04-17 14:23:55 -04:00
Ricardo Sánchez-Sáez d58785fcf7 ORKJSONSerializationTests: Fix indentation 2015-04-17 19:13:04 +01:00
Ricardo Sánchez-Sáez 4362e13ebc Relayout vertical ORKScaleSliderView (optimized for iPhone 6 and up) 2015-04-17 15:09:42 +01:00
Dasmer Singh 7d4853a197 Create dependency managment file to list CocoaPods and Carthage.
[README] Drop fourth-level headers

Add Dependency Management file

[README.md] Link to dependency_management.md

Move /usr/bin/env ruby to top of script
2015-04-17 09:35:45 -04:00
Ricardo Sánchez-Sáez e0e216eecc Allow different cell heights in ORKSurveyAnswerCellForScale and ORKSurveyAnswerCellForVerticalScale 2015-04-17 14:12:28 +01:00
Ricardo Sánchez-Sáez a2140aff06 Replace ORKVerticalScaleAnswerFormat and ORKContinuousVerticalScaleAnswerFormat classes by 'vertical' property in ORKScaleAnswerFormat and ORKContinuousScaleAnswerFormat
Also:
- Rename 'minValue' and 'maxValue' to 'minimumValue' and 'maximumValue' (Coding Guidelines for Cocoa)
- Reorder 'defaultValue' before 'steps' in ORKScaleAnswerFormat initializers (for coherence with ORKContinuousScaleAnswerFormat)
2015-04-17 13:56:35 +01:00
Ricardo Sánchez-Sáez 99bc310088 ORKScaleSlider: rename 'isVertical' property to 'vertical' with specified 'isVertical' getter
(Coding Guidelines for Cocoa)
2015-04-17 12:40:11 +01:00
Ricardo Sánchez-Sáez 5f52f13833 ORKRecorderTests: rename 'conf' to 'recorderConfiguration'
(As per Coding Guidelines for Cocoa)
2015-04-17 12:21:28 +01:00
Ricardo Sánchez-Sáez 7b1725a955 ORKRecorderTests: add recorder identifier tests 2015-04-17 12:18:41 +01:00
Ricardo Sánchez-Sáez f349bd9b7f Fix whitespace alignment on some method arguments 2015-04-17 12:05:09 +01:00
Dasmer Singh b66fa14873 Merge remote-tracking branch 'upstream/master' 2015-04-16 22:57:12 -04:00
Dasmer Singh 56bd6301b1 [Podspec] Update author 2015-04-16 22:56:53 -04:00
Dasmer Singh 073d712324 [find_headers] Add license and copyright 2015-04-16 22:56:41 -04:00
Bruce Duncan d3dba26b79 Merge branch 'master' into issue_4 2015-04-16 22:44:09 -04:00
Bruce Duncan 2fc27d7bda Added fixed step and continuous scale examples to the kitchen sink form step in ORKTest 2015-04-16 22:34:57 -04:00
Bruce Duncan a3d3fbb439 Revert "Added example of fixed scale and continuous scale form items."
This reverts commit 10ca52e63d.
2015-04-16 22:32:34 -04:00
jwe-apple f5e0594c75 Merge pull request #18 from ricardopereira/improvement/localization/pt
ERROR_DATALOGGER_COULD_NOT_MAORK changed 'pagado' to 'eliminado'
2015-04-16 15:20:19 -07:00
Yuan Zhu 96f83191dd Merge pull request #47 from mdznr/Capitalization-Consistency
Capitalization Consistency of sections in README
2015-04-16 14:13:45 -07:00
Matt Zanchelli fe40138b12 "Getting Started" capitalization in README 2015-04-16 14:12:15 -07:00
Yuan Zhu 4376582b4a Add .gitignore 2015-04-16 13:41:40 -07:00
Yuan Zhu d313e3f7a5 Merge pull request #32 from alexruperez/master
Fixed Form Sample Crash
2015-04-16 11:26:58 -07:00
Yuan Zhu 6d39c5e744 Fix license link 2015-04-16 11:14:17 -07:00
Yuan Zhu 96e22ba0c2 Fix best practice link 2015-04-16 11:12:45 -07:00
Yuan Zhu 5a9bb2f8fd Fix best practice link 2015-04-16 11:12:03 -07:00
alexruperez 5de3d1ec8b Fixes ResearchKit/ResearchKit#32 2015-04-16 20:10:59 +02:00
Yuan Zhu de7ec25b28 Merge pull request #15 from justinjdickow/master
Added CONTRIBUTING.md
2015-04-16 11:08:04 -07:00
Yuan Zhu 9849beded4 Merge pull request #34 from dplusm/master
Fixed coding-style inconsistencies
2015-04-16 11:05:01 -07:00
Ricardo Pereira 1503c05d6e Changed to 'apagado' 2015-04-16 18:56:53 +01:00
Yuan Zhu 6f517f89cf Merge pull request #23 from fyaqub/master
Objects that conform to NSCopying should use copy instead of strong
2015-04-16 10:53:11 -07:00
Yuan Zhu d56fc3e1bd Merge pull request #13 from steipete/master
Uses modern version detection API instead of floating point comparison.
2015-04-16 10:52:54 -07:00
Yuan Zhu e6b5a96c48 Merge pull request #43 from kindraywind/patch-1
Fix comma inconsistencies.
2015-04-16 10:50:31 -07:00
Yuan Zhu 228da9c789 Merge pull request #46 from sferrini/master
Avoid retain cycle
2015-04-16 10:45:27 -07:00
Dasmer Singh 75ece11fc1 Update syntax and add argument exception 2015-04-16 13:27:17 -04:00
dasmer / eliperkins 9044b794a3 Add documentation_url to podspec 2015-04-16 13:26:43 -04:00
dasmer / eliperkins a2ff2bd393 Add find header script for public and private headers and use in podspec 2015-04-16 13:26:33 -04:00
Simone Ferrini f2ada1a01c Avoid retain cycle 2015-04-16 19:10:44 +02:00
Bruce Duncan 10ca52e63d Added example of fixed scale and continuous scale form items. 2015-04-16 12:39:00 -04:00
Matt Zanchelli 627399a78c Capitalization Consistency of sections in README
"cases" should be capitalized correctly in the "Use cases" header in the README.
2015-04-16 09:06:03 -07:00
Woramet Muangsiri 58b544d5df Fix comma inconsistencies. 2015-04-16 21:35:55 +07:00
alexruperez 422d3afb41 Resolves ResearchKit/ResearchKit#32 2015-04-16 14:18:11 +02:00
Ricardo Sánchez-Sáez e5f5119bba Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-recorderidentifier 2015-04-16 12:51:19 +01:00
Ricardo Sánchez-Sáez 44036cb73e ORKRecorder & ORKRecorderConfiguration: add identifier property
Modeled after ORKStep's identifier (read-only property that is assigned in the initializers).
The identifier gets passed from ORKRecorderConfiguration to ORKRecorder and finally to the corresponding ORKFileResult.
ORKRecorderConfiguration serialization added: ORKTest tests modified to support the new property and passing.
2015-04-16 12:51:03 +01:00
Bruce Duncan ac4f40a902 Basic implementation of issue #4 2015-04-16 04:21:46 -04:00
Yuan Zhu 954a2a05a6 Merge pull request #39 from sikhapol/format-property-declarations
Format property declarations
2015-04-16 00:05:45 -07:00
Sikhapol Saijit 34b481f68c Format property declarations 2015-04-16 12:29:25 +07:00
Ricardo Sánchez-Sáez 00aa3212b4 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-verticalscale 2015-04-16 00:38:18 +01:00
Yuan Zhu b7824b1851 Merge pull request #38 from streeter/patch-1
Fix typo
2015-04-15 11:43:30 -07:00
Chris Streeter 9d97a29104 Fix typo 2015-04-15 11:16:47 -07:00
jwe-apple 4726d6fdd7 Merge pull request #30 from franklinsch/master
Replaced magic numbers in OKHTMLPDFWriter.m
2015-04-15 11:12:17 -07:00
fs2014 bd1d1ca3e6 Updated float to CGFloat. 2015-04-15 20:11:26 +02:00
fs2014 390c52e5e8 Used static consts instead of define for type safety, as suggested by jwe-apple. 2015-04-15 19:40:04 +02:00
Yuan Zhu 37b30537e9 Merge pull request #31 from codestergit/remove-spaces-from-method-params
Removed spaces between colon and parameters according to Apple's cocoa coding style.
2015-04-15 10:32:22 -07:00
jwe-apple 4aac2f9010 Merge pull request #8 from garnett/cleanup-tests
Cleanup tests
2015-04-15 10:31:12 -07:00
jwe-apple 2c29f029c4 Merge pull request #36 from troligtvis/master
variable name corrected
2015-04-15 10:29:49 -07:00
DanKeen 175679468e Merge pull request #37 from hcanzonetta/master
Fixed typo in AdjustToScale
2015-04-15 10:08:47 -07:00
Justin Dickow 5f288877d0 Referenced CONTRIBUTING.md in README 2015-04-15 10:08:21 -04:00
Justin Dickow 3faffe89ea Addressed PR Comments, updated inline links 2015-04-15 09:47:46 -04:00
Hernán Canzonetta 648b382fe9 Fixed typo in AdjustToScale 2015-04-15 10:23:14 -03:00
strawberrypie 077e1bb94b small typo corrected 2015-04-15 14:35:01 +02:00
strawberrypie 17ae36d939 wrong variable name fixed 2015-04-15 13:39:42 +02:00
Ricardo Sánchez-Sáez ddcb2ce4f0 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-dev 2015-04-15 11:26:11 +01:00
Ricardo Sánchez-Sáez 5953891a7c TaskListRow: add DiscreteVerticalScaleQuestionStep and ContinuousVerticalScaleQuestionStep examples to scaleQuestionTask 2015-04-15 11:25:28 +01:00
Ricardo Sánchez-Sáez fd2ab4b4a3 ORKAnswerFormat: add ORKVerticalScaleAnswerFormat and ORKContinuousVerticalScaleAnswerFormat classes and factory methods
Also:
ORKAnswerFormat .h: make spacing coherent; add missing ORKContinuousScaleAnswerFormat initializer comment
2015-04-15 11:24:46 +01:00
alexruperez b923899ced Fixed Form Sample Crash 2015-04-15 12:21:02 +02:00
Ricardo Sánchez-Sáez 87fd1537d7 ORKScaleAnswerFormatProvider protocol: add isVertical method; ORKScaleSliderView: add vertical mode support 2015-04-15 11:09:06 +01:00
Daniel Martens 3cb3b72c2d Fixed coding-style inconsistencies 2015-04-15 11:59:43 +02:00
Ricardo Sánchez-Sáez e270c9812d ORKScaleSlider: add vertical scale mode 2015-04-15 10:51:13 +01:00
Ricardo Sánchez-Sáez 0b5f1d7082 ORKScaleSlider: fix issue when left dragging touch outside the segmented scale
(Scale was being set to the maximumValue when you dragged the touch outside the segmented scale through the view's left bound)
2015-04-15 10:49:32 +01:00
codestergit f7f7c73ccc Removed space between colon and parameters 2015-04-15 14:50:24 +05:30
Peter Steinberger d4bd7b07d7 Remove Macro redefinition of HKBiologicalSexOther 2015-04-15 10:32:31 +02:00
fs2014 bd89f14b7e Replaced magic numbers in OKHTMLPDFWriter.m 2015-04-15 10:06:01 +02:00
Peter Steinberger 9b5ee80420 Remove _IPHONE_8_2 checks since nullability requires Xcode 6.3. 2015-04-15 09:38:00 +02:00
Denis Lebedev a2ab9874ab Revert ORKHKSampleTests to user ivars 2015-04-15 10:22:07 +03:00
Faisal Yaqub c1593b312d Switch NSArray objects to copy 2015-04-15 00:12:41 -07:00
Faisal Yaqub aeddc8fea9 Change NSValue and NSData properties to strong 2015-04-15 00:07:37 -07:00
Faisal Yaqub 9a03d12817 Revert accidental change to strong 2015-04-14 23:59:15 -07:00
Faisal Yaqub 54e147c969 Switch NSCalendar property to strong 2015-04-14 23:54:24 -07:00
Faisal Yaqub 9f0bdfd2fd Removing unused NSError properties 2015-04-14 23:52:48 -07:00
DanKeen 4ddf07f106 Merge pull request #26 from kindraywind/patch-1
Remove spaces according to Apple's cocoa coding style.
2015-04-14 22:52:24 -07:00
Woramet Muangsiri eae5f56040 Remove spaces according to Apple's cocoa coding style. 2015-04-15 12:38:30 +07:00
Faisal Yaqub 120d063bdf Switching collections back to copy 2015-04-14 22:29:31 -07:00
DanKeen 1d8182db32 Merge pull request #22 from waynn/patch-1
make it clear myStep is a variable
2015-04-14 21:59:43 -07:00
Dasmer Singh 946753ea91 [Podspec] Remove spaces between filenames 2015-04-14 22:40:29 -04:00
Faisal Yaqub 4757edc130 Objects that conform to NSCopying should use copy instead of strong 2015-04-14 18:32:53 -07:00
Waynn Lue 19460998b6 make it clear myStep is a variable 2015-04-14 18:07:44 -07:00
Yuan Zhu 1f0307aa63 Merge pull request #21 from sferrini/master
Removed unnecessary semicolons
2015-04-14 16:01:53 -07:00
Yuan Zhu e477f4e38b Capitalizing "Predefined" 2015-04-14 15:38:53 -07:00
Dasmer Singh 06125bb24d Explicitly add all public header files. Limit source files to only be .h and .m files 2015-04-14 17:06:46 -04:00
Dasmer Singh 4ff80ee4c2 Add shader files to resources 2015-04-14 17:06:34 -04:00
Simone Ferrini f61f4e66db Removed unnecessary semicolons 2015-04-14 23:03:47 +02:00
jwe-apple c11ae6d95e Merge pull request #20 from Rudimental/patch-1
Add closing p tag to fix formatting in section 2
2015-04-14 13:50:48 -07:00
Yuan Zhu 064d4d0a03 Merge pull request #19 from fedetrim/patch-1
Adopting Apple coding convention
2015-04-14 13:35:19 -07:00
David Rabkin fd84004c37 Add closing p tag to fix formatting in section 2
-The code isn't formatting correctly in section 2. By adding a closing p tag, the documentation can be read more easily.
2015-04-14 13:26:38 -07:00
fedetrim 33880857a0 Adopting Apple coding convention 2015-04-14 16:58:37 -03:00
Ricardo Pereira 9b6decc643 ERROR_DATALOGGER_COULD_NOT_MAORK changed 'pagado' to 'eliminado' 2015-04-14 20:12:30 +01:00
Justin Dickow d81f303959 Added CONTRIBUTING.md 2015-04-14 15:10:37 -04:00
Peter Steinberger e4f8af52eb Uses modern version detection API instead of floating point comparison.
While the current way of checking for the version is not deprecated,
converting the string to float isn’t a good idea either.

The framework is for iOS 8 and above, so we can use the new Foundation API.
2015-04-14 21:08:34 +02:00
Dasmer Singh 208249a3b9 Add project resources to podspec 2015-04-14 14:11:55 -04:00
Denis Lebedev 71373cc46f Remove empty test setup overrides 2015-04-14 20:55:26 +03:00
Denis Lebedev aa8186e175 DRY test fixtures 2015-04-14 20:40:33 +03:00
Denis Lebedev cabe77ca67 Delete template code 2015-04-14 20:37:09 +03:00
Dasmer Singh cdcda16714 Update README for CocoaPods 2015-04-14 13:27:42 -04:00
Yuan Zhu 9c75263ac5 Merge pull request #6 from frewsxcv/patch-1
Fix spelling error in readme
2015-04-14 10:21:39 -07:00
Corey Farwell 3d08b355bd Fix spelling error in readme 2015-04-14 13:19:30 -04:00
Dasmer Singh c5b1640343 Adds a podspec for Cocoapods 2015-04-14 13:15:13 -04:00
John Earl f22c425b25 Update readme links 2015-04-14 09:24:12 -07:00
562 changed files with 18500 additions and 7890 deletions
-2
View File
@@ -18,6 +18,4 @@ DerivedData
*.xcuserstate
.DS_Store
StudyDemo/ResearchKit
*.pyc
+180
View File
@@ -0,0 +1,180 @@
Contributing to the ResearchKit Framework
===========================
This page focuses on code contributions to the existing
codebase. However, other types of contributions are welcome too, in
keeping with the ResearchKit™ framework [best practices](../../wiki/best-practices). For example,
contributions of original free-to-use survey content, back-end integrations,
validation data, and analysis or processing tools are all welcome. Ask
on [researchkit-dev](https://lists.apple.com/mailman/listinfo/researchkit-dev) or [contact us](https://developer.apple.com/contact/researchkit/) for guidance.
Contributing software
---------------------
This page assumes you already know how to check out and build the
code. Contributions to the ResearchKit framework are expected to comply with the
[ResearchKit Contribution Terms and License Policy](#contribution); please familiarize yourself
with this policy prior to submitting a pull request. For any contribution, ensure that you own
the rights or have permission from the copyright holder. (e.g. code, images, surveys, videos
and other content you may include)
To contribute to ResearchKit:
1. [Choose or create an issue to work on.](#create)
2. [Create a personal fork of the ResearchKit framework.](#fork)
3. [Develop your changes in your fork.](#develop)
4. [Run the tests.](#test)
5. [Submit a pull request.](#request)
6. Make any changes requested by the reviewer, and update your pull request as needed.
7. Once accepted, your pull request will be merged into master.
Choosing an issue to work on<a name="create"></a>
----------------------------
To find an issue to work on, either pick something that you need for
your app, or select one of the issues from our [issue list](../../issues). Or,
consider one of the areas where we'd like to extend ResearchKit:
* Faster 'get started' to a useful app
* More active tasks
* Data analysis for active tasks
* More consent sections
* Back end integrations
If in doubt, bring your idea up on [researchkit-dev](https://lists.apple.com/mailman/listinfo/researchkit-dev).
Creating a personal fork<a name="fork"></a>
------------------------
On GitHub, it's easy to create a personal fork. Just tap the "Fork"
button on the top right, and clone your new repository.
Develop your changes in your fork<a name="develop"></a>
---------------------------------
Develop your changes using your normal development process. If you
already have code from an existing project, you may need to adjust its
style to more closely match that in the ResearchKit framework.
New components may need to expose new Public or Private
headers. Public headers are for APIs that are likely to be a stable
part of the interface of the ResearchKit framework. Private headers are for APIs that
may need to be accessed from app-side unit tests, or that are more
subject to change than the public interface. All other headers should
be internal, "Project" headers.
Please review and ensure that any contributions you make comply with
the [ResearchKit Contribution Terms and License Policy](#contribution).
Add automated tests for your feature, where it is possible to do
so. For UI driven components where it is harder to write automated
tests, add UI to at least one test application so that the new
features can be reviewed and tested. Consider also whether to add new
code to other existing demo apps to exercise your feature.
Keep changes that fix different issues separate. For bug fixes,
separate bugs should be submitted as separate pull requests. A good
way to do this is to create a new branch in your fork for each new
bug work on.
Any new user-visible strings should be included in the English
`Localizable.strings` table so that they can be picked up and
localized in the next release cycle.
Run the tests<a name="test"></a>
-------------
All unit tests should pass, and there should be no warnings. Also
verify that test apps run on both device and simulator.
Where your code affects UI presentation, also test:
* Multiple device form factors (for instance, iPhone 4S, iPhone 5, iPhone 6, iPhone 6 Plus).
* Dynamic text, especially at the "Large" setting.
* Rotation between portrait and landscape, where appropriate.
You can use the apps in the `Testing` and `samples` directories to
test your changes.
Submit a pull request<a name="request"></a>
---------------------
The reviewers may request changes. Make the changes, and update your
pull request as needed. Reviews will focus on coding style,
correctness, and design consistency.
This process does not take the place of an ethical review, for example
by an institutional review board (IRB) or ethics committee.
After acceptance<a name="after"></a>
----------------
Once your pull request has been accepted, your changes will be merged
to master. You are still responsible for your change after it is
accepted. Stay in contact, in case bugs are detected that may require
your attention.
When the project is next branched for release, your changes will be
incorporated. Queries may come back to you regarding localization,
documentation, or other issues during this process.
Release process
-----------------
The `master` branch is used for work in progress. On `master`:
* All test apps should build and run error free.
* Unit tests should all pass.
* Everything should be continuously in working order in English (the
base language).
The project will make periodic releases. When preparing a stable release, we
will branch from `master` to a convergence branch. During this process,
changes will be made first to the convergence branch, and then merged into
`master`. On the convergence branch, changes will be made only to:
* Fix high priority issues.
* Update documentation.
* Bring localization up to date.
* Ensure good behavior across all supported devices.
After the converging process is completed, we will merge everything to the
`stable` branch and tag with a new release number. The most recent release
will be highlighted in the [README](../..).
ResearchKit Contribution Terms and License Policy<a name="contribution"></a>
=======================================
Thank you for your interest in contributing to the ResearchKit
community. In order to maintain consistency and license compatibility
throughout the project, all contributions must comply with our
licensing policy and terms for contributing code to the ResearchKit
project:
1. If you are submitting a patch to the existing codebase, you
represent that you have the right to license the patch to the
community, and agree by submitting the patch that your changes are
licensed under the existing license terms of the file you are
modifying (i.e., [ResearchKit BSD license](LICENSE)).
Please also add your copyright (name and year) to the relevant
files for changes that are more than 10 lines of code.
2. If you are submitting a new file for inclusion in the ResearchKit framework (no
code copied from another source), please include your copyright (name
and year) and a copy of the ResearchKit BSD license. By submitting
your new file you represent that you have the right to license your
file to the community, and agree that your file is licensed under the
ResearchKit BSD license.
3. If you aren't the author of the patch, you agree to include the
original copyright notices and licensing terms with it, to the extent
that they exist. If there wasn't a copyright notice or license,
please make a note of it. Generally we can only take in patches that
are BSD-licensed in order to maintain license compatibility within the
project.
+56 -11
View File
@@ -5,10 +5,10 @@ The ResearchKit™ framework is an open source software framework that makes it
create apps for medical research or for other research projects.
* Getting Started: [Getting Started](#gettingstarted)
* Documentation: ([Programming Guide](http://researchkit.org/docs/docs/Overview/GuideOverview.html)) ([API](http://researchkit.org/docs/index.html))
* Best practices: [Best Practices](../../wiki/best_practices)
* Contributing to ResearchKit: [Contributing](../../wiki/contributing)
* Website and blog: ([researchkit.org](http://researchkit.org/index.html)) ([Blog](http://researchkit.org/blog.html))
* Documentation: ([Programming Guide](http://researchkit.github.io/docs/docs/Overview/GuideOverview.html)) ([API](http://researchkit.github.io/docs/index.html))
* Best practices: [Best Practices](../../wiki/best-practices)
* Contributing to ResearchKit: [Contributing](CONTRIBUTING.md)
* Website and blog: ([researchkit.org](http://researchkit.github.io/index.html)) ([Blog](http://researchkit.github.io/blog.html))
* ResearchKit BSD License: [License](#license)
Getting More Information
@@ -18,7 +18,7 @@ Getting More Information
* Join [researchkit-dev](https://lists.apple.com/mailman/listinfo/researchkit-dev) for discussing ongoing work to improve and expand the framework.
* Or [contact us](https://developer.apple.com/contact/researchkit/)
Use cases
Use Cases
===========
A task in the ResearchKit framework contains a set of steps to present to a
@@ -29,14 +29,14 @@ Surveys
-------
The ResearchKit framework provides a pre-built user interface for surveys, which can be
presented modally on an iPhone, iPod Touch, or iPad. [Surveys](http://researchkit.org/docs/docs/Survey/CreatingSurveys.html)
presented modally on an iPhone, iPod Touch, or iPad. [Surveys](http://researchkit.github.io/docs/docs/Survey/CreatingSurveys.html)
Consent
----------------
The ResearchKit framework provides visual consent templates that you can customize to
explain the details of your research study and obtain a signature if needed. [Consent](http://researchkit.org/docs/docs/InformedConsent/InformedConsent.html)
explain the details of your research study and obtain a signature if needed. [Consent](http://researchkit.github.io/docs/docs/InformedConsent/InformedConsent.html)
Active Tasks
@@ -45,10 +45,10 @@ Active Tasks
Some studies may need data beyond survey questions or the passive data collection
capabilities available through use of the HealthKit and CoreMotion APIs if you are
programming for iOS. ResearchKit's active tasks invite users to perform activities
under semi-controlled conditions, while iPhone sensors actively collect data. [Active Tasks](http://researchkit.org/docs/docs/ActiveTasks/ActiveTasks.html)
under semi-controlled conditions, while iPhone sensors actively collect data. [Active Tasks](http://researchkit.github.io/docs/docs/ActiveTasks/ActiveTasks.html)
Getting started<a name="gettingstarted"></a>
Getting Started<a name="gettingstarted"></a>
===============
@@ -63,7 +63,7 @@ using the ResearchKit framework can run on devices with iOS 8.0 or newer.
Installation
------------
The lastest stable version of ResearchKit framework can be cloned with
The latest stable version of ResearchKit framework can be cloned with
```
git clone -b stable https://github.com/ResearchKit/ResearchKit.git
@@ -110,6 +110,8 @@ target as shown in the figure below.
</figure>
</center>
Note: You can also import ResearchKit into your project using a [dependency manager](./dependency_management.md) such as CocoaPods or Carthage.
###2. Create a Step
In this walk-through, we will use the ResearchKit framework to modally present a
@@ -120,24 +122,41 @@ Create a step for your task by adding some code, perhaps in
simple, we'll use an instruction step (`ORKInstructionStep`) and name
the step `myStep`.
*Objective-C*
```objc
ORKInstructionStep *myStep =
[[ORKInstructionStep alloc] initWithIdentifier:@"intro"];
myStep.title = @"Welcome to ResearchKit";
```
*Swift*
```swift
let myStep = ORKInstructionStep(identifier: "intro")
myStep.title = "Welcome to ResearchKit"
```
###3. Create a Task
Use the ordered task class (`ORKOrderedTask`) to create a task that
contains myStep. An ordered task is just a task where the order and
contains `myStep`. An ordered task is just a task where the order and
selection of later steps does not depend on the results of earlier
ones. Name your task `task` and initialize it with `myStep`.
*Objective-C*
```objc
ORKOrderedTask *task =
[[ORKOrderedTask alloc] initWithIdentifier:@"task" steps:@[myStep]];
```
*Swift*
```swift
let task = ORKOrderedTask(identifier: "task", steps: [myStep])
```
###4. Present the Task
Create a task view controller (`ORKTaskViewController`) and initialize
@@ -145,6 +164,8 @@ it with your `task`. A task view controller manages a task and collects the
results of each step. In this case, your task view
controller simply displays your instruction step.
*Objective-C*
```objc
ORKTaskViewController *taskViewController =
[[ORKTaskViewController alloc] initWithTask:task taskRunUUID:nil];
@@ -152,10 +173,20 @@ taskViewController.delegate = self;
[self presentViewController:taskViewController animated:YES completion:nil];
```
*Swift*
```swift
let taskViewController = ORKTaskViewController(task: task, taskRunUUID: nil)
taskViewController.delegate = self
presentViewController(taskViewController, animated: true, completion: nil)
```
The above snippet assumes that your class implements the
`ORKTaskViewControllerDelegate` protocol. This has just one required method,
which you must implement in order to handle the completion of the task:
*Objective-C*
```objc
- (void)taskViewController:(ORKTaskViewController *)taskViewController
didFinishWithReason:(ORKTaskViewControllerFinishReason)reason
@@ -169,6 +200,20 @@ which you must implement in order to handle the completion of the task:
}
```
*Swift*
```swift
func taskViewController(taskViewController: ORKTaskViewController,
didFinishWithReason reason: ORKTaskViewControllerFinishReason,
error: NSError?) {
let taskResult = taskViewController.result
// You could do something with the result here.
// Then, dismiss the task view controller.
dismissViewControllerAnimated(true, completion: nil)
}
```
If you now run your app, you should see your first ResearchKit framework
instruction step:
+15
View File
@@ -0,0 +1,15 @@
Pod::Spec.new do |s|
s.name = 'ResearchKit'
s.version = '1.1.2'
s.summary = 'ResearchKit is an open source software framework that makes it easy to create apps for medical research or for other research projects.'
s.homepage = 'https://www.github.com/ResearchKit/ResearchKit'
s.documentation_url = 'http://researchkit.github.io/docs/'
s.license = { :type => 'BSD', :file => 'LICENSE' }
s.author = { 'researchkit.org' => 'http://researchkit.org' }
s.source = { :git => 'https://github.com/ResearchKit/ResearchKit.git', :tag => s.version.to_s }
s.public_header_files = `./scripts/find_headers.rb --public --private`.split("\n")
s.source_files = 'ResearchKit/**/*.{h,m}'
s.resources = 'ResearchKit/**/*.{fsh,vsh}', 'ResearchKit/Animations/**/*.m4v', 'ResearchKit/Artwork.xcassets', 'ResearchKit/Localized/*.lproj'
s.platform = :ios, '8.0'
s.requires_arc = true
end
+308 -58
View File
@@ -22,6 +22,24 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
147503AF1AEE8071004B17F3 /* ORKAudioGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 147503AD1AEE8071004B17F3 /* ORKAudioGenerator.h */; };
147503B01AEE8071004B17F3 /* ORKAudioGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 147503AE1AEE8071004B17F3 /* ORKAudioGenerator.m */; };
147503B71AEE807C004B17F3 /* ORKToneAudiometryContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = 147503B11AEE807C004B17F3 /* ORKToneAudiometryContentView.h */; };
147503B81AEE807C004B17F3 /* ORKToneAudiometryContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 147503B21AEE807C004B17F3 /* ORKToneAudiometryContentView.m */; };
147503B91AEE807C004B17F3 /* ORKToneAudiometryStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 147503B31AEE807C004B17F3 /* ORKToneAudiometryStep.h */; settings = {ATTRIBUTES = (Private, ); }; };
147503BA1AEE807C004B17F3 /* ORKToneAudiometryStep.m in Sources */ = {isa = PBXBuildFile; fileRef = 147503B41AEE807C004B17F3 /* ORKToneAudiometryStep.m */; };
147503BB1AEE807C004B17F3 /* ORKToneAudiometryStepViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 147503B51AEE807C004B17F3 /* ORKToneAudiometryStepViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
147503BC1AEE807C004B17F3 /* ORKToneAudiometryStepViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 147503B61AEE807C004B17F3 /* ORKToneAudiometryStepViewController.m */; };
25ECC0951AFBD68300F3D63B /* ORKReactionTimeStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 25ECC0931AFBD68300F3D63B /* ORKReactionTimeStep.h */; };
25ECC0961AFBD68300F3D63B /* ORKReactionTimeStep.m in Sources */ = {isa = PBXBuildFile; fileRef = 25ECC0941AFBD68300F3D63B /* ORKReactionTimeStep.m */; };
25ECC09B1AFBD8B300F3D63B /* ORKReactionTimeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 25ECC0991AFBD8B300F3D63B /* ORKReactionTimeViewController.h */; };
25ECC09C1AFBD8B300F3D63B /* ORKReactionTimeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 25ECC09A1AFBD8B300F3D63B /* ORKReactionTimeViewController.m */; };
25ECC09F1AFBD92D00F3D63B /* ORKReactionTimeContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = 25ECC09D1AFBD92D00F3D63B /* ORKReactionTimeContentView.h */; };
25ECC0A01AFBD92D00F3D63B /* ORKReactionTimeContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 25ECC09E1AFBD92D00F3D63B /* ORKReactionTimeContentView.m */; };
25ECC0A31AFBDD2700F3D63B /* ORKReactionTimeStimulusView.h in Headers */ = {isa = PBXBuildFile; fileRef = 25ECC0A11AFBDD2700F3D63B /* ORKReactionTimeStimulusView.h */; };
25ECC0A41AFBDD2700F3D63B /* ORKReactionTimeStimulusView.m in Sources */ = {isa = PBXBuildFile; fileRef = 25ECC0A21AFBDD2700F3D63B /* ORKReactionTimeStimulusView.m */; };
2EBFE11D1AE1B32D00CB8254 /* ORKUIViewAccessibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EBFE11C1AE1B32D00CB8254 /* ORKUIViewAccessibilityTests.m */; };
2EBFE1201AE1B74100CB8254 /* ORKVoiceEngineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EBFE11F1AE1B74100CB8254 /* ORKVoiceEngineTests.m */; };
618DA04E1A93D0D600E63AA8 /* ORKAccessibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 618DA0481A93D0D600E63AA8 /* ORKAccessibility.h */; };
618DA0501A93D0D600E63AA8 /* ORKAccessibilityFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 618DA0491A93D0D600E63AA8 /* ORKAccessibilityFunctions.h */; };
618DA0521A93D0D600E63AA8 /* ORKAccessibilityFunctions.m in Sources */ = {isa = PBXBuildFile; fileRef = 618DA04A1A93D0D600E63AA8 /* ORKAccessibilityFunctions.m */; };
@@ -268,8 +286,6 @@
86C40DDE1A8D7C5C00081FAC /* ORKVerticalContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40BE11A8D7C5C00081FAC /* ORKVerticalContainerView.h */; };
86C40DE01A8D7C5C00081FAC /* ORKVerticalContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 86C40BE21A8D7C5C00081FAC /* ORKVerticalContainerView.m */; };
86C40DE21A8D7C5C00081FAC /* ORKVerticalContainerView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40BE31A8D7C5C00081FAC /* ORKVerticalContainerView_Internal.h */; };
86C40DE61A8D7C5C00081FAC /* UIApplication+ResearchKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40BE51A8D7C5C00081FAC /* UIApplication+ResearchKit.h */; };
86C40DE81A8D7C5C00081FAC /* UIApplication+ResearchKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 86C40BE61A8D7C5C00081FAC /* UIApplication+ResearchKit.m */; };
86C40DEA1A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40BE71A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.h */; };
86C40DEC1A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 86C40BE81A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.m */; };
86C40DEE1A8D7C5C00081FAC /* UIResponder+ResearchKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40BE91A8D7C5C00081FAC /* UIResponder+ResearchKit.h */; };
@@ -291,8 +307,6 @@
86C40E0E1A8D7C5C00081FAC /* ORKConsentReviewStepViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 86C40BFA1A8D7C5C00081FAC /* ORKConsentReviewStepViewController.m */; };
86C40E101A8D7C5C00081FAC /* ORKConsentSceneViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40BFB1A8D7C5C00081FAC /* ORKConsentSceneViewController.h */; };
86C40E121A8D7C5C00081FAC /* ORKConsentSceneViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 86C40BFC1A8D7C5C00081FAC /* ORKConsentSceneViewController.m */; };
86C40E141A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40BFD1A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.h */; };
86C40E161A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.m in Sources */ = {isa = PBXBuildFile; fileRef = 86C40BFE1A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.m */; };
86C40E181A8D7C5C00081FAC /* ORKConsentSection.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40BFF1A8D7C5C00081FAC /* ORKConsentSection.h */; settings = {ATTRIBUTES = (Public, ); }; };
86C40E1A1A8D7C5C00081FAC /* ORKConsentSection.m in Sources */ = {isa = PBXBuildFile; fileRef = 86C40C001A8D7C5C00081FAC /* ORKConsentSection.m */; };
86C40E1C1A8D7C5C00081FAC /* ORKConsentSection_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C40C011A8D7C5C00081FAC /* ORKConsentSection_Internal.h */; };
@@ -323,6 +337,10 @@
B11C549B1A9EEF8800265E61 /* ORKConsentSharingStep.m in Sources */ = {isa = PBXBuildFile; fileRef = B11C54971A9EEF8800265E61 /* ORKConsentSharingStep.m */; };
B11C549F1A9EF4A700265E61 /* ORKConsentSharingStepViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = B11C549C1A9EF4A700265E61 /* ORKConsentSharingStepViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
B11C54A11A9EF4A700265E61 /* ORKConsentSharingStepViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B11C549D1A9EF4A700265E61 /* ORKConsentSharingStepViewController.m */; };
B12EA0151B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.h in Headers */ = {isa = PBXBuildFile; fileRef = B12EA0131B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.h */; settings = {ATTRIBUTES = (Private, ); }; };
B12EA0161B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.m in Sources */ = {isa = PBXBuildFile; fileRef = B12EA0141B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.m */; };
B12EA0191B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = B12EA0171B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
B12EA01A1B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B12EA0181B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.m */; };
B17FE7FD1A8DBE7C00BF9C28 /* Artwork.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 861610BF1A8D8EDD00245F7A /* Artwork.xcassets */; };
B183A4A21A8535D100C76870 /* ResearchKit_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B1B894391A00345200C5CF2D /* ResearchKit_Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
B183A4DD1A8535D100C76870 /* ResearchKit.h in Headers */ = {isa = PBXBuildFile; fileRef = B1C1DE4F196F541F00F75544 /* ResearchKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -343,6 +361,37 @@
B1A860F71A9693C400EA57B7 /* consent_07@3x.m4v in Resources */ = {isa = PBXBuildFile; fileRef = B1A860E91A9693C400EA57B7 /* consent_07@3x.m4v */; };
B1C0F4E41A9BA65F0022C153 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B1C0F4E11A9BA65F0022C153 /* Localizable.strings */; };
B1C7955E1A9FBF04007279BA /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1C7955D1A9FBF04007279BA /* HealthKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
B8760F2B1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = B8760F291AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.h */; };
B8760F2C1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = B8760F2A1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.m */; };
BC01B0FB1B0EB99700863803 /* ORKTintedImageView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = BC01B0FA1B0EB99700863803 /* ORKTintedImageView_Internal.h */; };
BC13CE391B0660220044153C /* ORKNavigableOrderedTask.h in Headers */ = {isa = PBXBuildFile; fileRef = BC13CE371B0660220044153C /* ORKNavigableOrderedTask.h */; settings = {ATTRIBUTES = (Public, ); }; };
BC13CE3A1B0660220044153C /* ORKNavigableOrderedTask.m in Sources */ = {isa = PBXBuildFile; fileRef = BC13CE381B0660220044153C /* ORKNavigableOrderedTask.m */; };
BC13CE3C1B0662990044153C /* ORKStepNavigationRule_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BC13CE3B1B0662990044153C /* ORKStepNavigationRule_Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC13CE3E1B0662A80044153C /* ORKOrderedTask_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = BC13CE3D1B0662A80044153C /* ORKOrderedTask_Internal.h */; };
BC13CE401B0666FD0044153C /* ORKResultPredicate.h in Headers */ = {isa = PBXBuildFile; fileRef = BC13CE3F1B0666FD0044153C /* ORKResultPredicate.h */; settings = {ATTRIBUTES = (Public, ); }; };
BC13CE421B066A990044153C /* ORKStepNavigationRule_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = BC13CE411B066A990044153C /* ORKStepNavigationRule_Internal.h */; };
BC4194291AE8453A00073D6B /* ORKObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = BC4194271AE8453A00073D6B /* ORKObserver.h */; };
BC41942A1AE8453A00073D6B /* ORKObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4194281AE8453A00073D6B /* ORKObserver.m */; };
BCA5C0351AEC05F20092AC8D /* ORKStepNavigationRule.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA5C0331AEC05F20092AC8D /* ORKStepNavigationRule.h */; settings = {ATTRIBUTES = (Public, ); }; };
BCA5C0361AEC05F20092AC8D /* ORKStepNavigationRule.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA5C0341AEC05F20092AC8D /* ORKStepNavigationRule.m */; };
BCAD50E81B0201EE0034806A /* ORKTaskTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BCAD50E71B0201EE0034806A /* ORKTaskTests.m */; };
BCB96C131B19C0EC002A0B96 /* ORKStepTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BCB96C121B19C0EC002A0B96 /* ORKStepTests.m */; };
BCFF24BD1B0798D10044EC35 /* ORKResultPredicate.m in Sources */ = {isa = PBXBuildFile; fileRef = BCFF24BC1B0798D10044EC35 /* ORKResultPredicate.m */; };
D42FEFB81AF7557000A124F8 /* ORKImageCaptureView.h in Headers */ = {isa = PBXBuildFile; fileRef = D42FEFB61AF7557000A124F8 /* ORKImageCaptureView.h */; };
D42FEFB91AF7557000A124F8 /* ORKImageCaptureView.m in Sources */ = {isa = PBXBuildFile; fileRef = D42FEFB71AF7557000A124F8 /* ORKImageCaptureView.m */; };
D44239791AF17F5100559D96 /* ORKImageCaptureStep.h in Headers */ = {isa = PBXBuildFile; fileRef = D44239771AF17F5100559D96 /* ORKImageCaptureStep.h */; settings = {ATTRIBUTES = (Public, ); }; };
D442397A1AF17F5100559D96 /* ORKImageCaptureStep.m in Sources */ = {isa = PBXBuildFile; fileRef = D44239781AF17F5100559D96 /* ORKImageCaptureStep.m */; };
D442397D1AF17F7600559D96 /* ORKImageCaptureStepViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D442397B1AF17F7600559D96 /* ORKImageCaptureStepViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
D442397E1AF17F7600559D96 /* ORKImageCaptureStepViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D442397C1AF17F7600559D96 /* ORKImageCaptureStepViewController.m */; };
D458520A1AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.h in Headers */ = {isa = PBXBuildFile; fileRef = D45852081AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.h */; };
D458520B1AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = D45852091AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.m */; };
FA7A9D2B1B082688005A2BEA /* ORKConsentDocumentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FA7A9D2A1B082688005A2BEA /* ORKConsentDocumentTests.m */; };
FA7A9D2F1B083DD3005A2BEA /* ORKConsentSectionFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7A9D2D1B083DD3005A2BEA /* ORKConsentSectionFormatter.h */; };
FA7A9D301B083DD3005A2BEA /* ORKConsentSectionFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = FA7A9D2E1B083DD3005A2BEA /* ORKConsentSectionFormatter.m */; };
FA7A9D331B0843A9005A2BEA /* ORKConsentSignatureFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7A9D311B0843A9005A2BEA /* ORKConsentSignatureFormatter.h */; };
FA7A9D341B0843A9005A2BEA /* ORKConsentSignatureFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = FA7A9D321B0843A9005A2BEA /* ORKConsentSignatureFormatter.m */; };
FA7A9D371B09365F005A2BEA /* ORKConsentSectionFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FA7A9D361B09365F005A2BEA /* ORKConsentSectionFormatterTests.m */; };
FA7A9D391B0969A7005A2BEA /* ORKConsentSignatureFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FA7A9D381B0969A7005A2BEA /* ORKConsentSignatureFormatterTests.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -363,6 +412,25 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
147503AD1AEE8071004B17F3 /* ORKAudioGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKAudioGenerator.h; sourceTree = "<group>"; };
147503AE1AEE8071004B17F3 /* ORKAudioGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKAudioGenerator.m; sourceTree = "<group>"; };
147503B11AEE807C004B17F3 /* ORKToneAudiometryContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKToneAudiometryContentView.h; sourceTree = "<group>"; };
147503B21AEE807C004B17F3 /* ORKToneAudiometryContentView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKToneAudiometryContentView.m; sourceTree = "<group>"; };
147503B31AEE807C004B17F3 /* ORKToneAudiometryStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKToneAudiometryStep.h; sourceTree = "<group>"; };
147503B41AEE807C004B17F3 /* ORKToneAudiometryStep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKToneAudiometryStep.m; sourceTree = "<group>"; };
147503B51AEE807C004B17F3 /* ORKToneAudiometryStepViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKToneAudiometryStepViewController.h; sourceTree = "<group>"; };
147503B61AEE807C004B17F3 /* ORKToneAudiometryStepViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKToneAudiometryStepViewController.m; sourceTree = "<group>"; };
25ECC0931AFBD68300F3D63B /* ORKReactionTimeStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKReactionTimeStep.h; sourceTree = "<group>"; };
25ECC0941AFBD68300F3D63B /* ORKReactionTimeStep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKReactionTimeStep.m; sourceTree = "<group>"; };
25ECC0991AFBD8B300F3D63B /* ORKReactionTimeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKReactionTimeViewController.h; sourceTree = "<group>"; };
25ECC09A1AFBD8B300F3D63B /* ORKReactionTimeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKReactionTimeViewController.m; sourceTree = "<group>"; };
25ECC09D1AFBD92D00F3D63B /* ORKReactionTimeContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKReactionTimeContentView.h; sourceTree = "<group>"; };
25ECC09E1AFBD92D00F3D63B /* ORKReactionTimeContentView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKReactionTimeContentView.m; sourceTree = "<group>"; };
25ECC0A11AFBDD2700F3D63B /* ORKReactionTimeStimulusView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKReactionTimeStimulusView.h; sourceTree = "<group>"; };
25ECC0A21AFBDD2700F3D63B /* ORKReactionTimeStimulusView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKReactionTimeStimulusView.m; sourceTree = "<group>"; };
2EBFE11C1AE1B32D00CB8254 /* ORKUIViewAccessibilityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKUIViewAccessibilityTests.m; sourceTree = "<group>"; };
2EBFE11E1AE1B68800CB8254 /* ORKVoiceEngine_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ORKVoiceEngine_Internal.h; sourceTree = "<group>"; };
2EBFE11F1AE1B74100CB8254 /* ORKVoiceEngineTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKVoiceEngineTests.m; sourceTree = "<group>"; };
618DA0481A93D0D600E63AA8 /* ORKAccessibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKAccessibility.h; sourceTree = "<group>"; };
618DA0491A93D0D600E63AA8 /* ORKAccessibilityFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKAccessibilityFunctions.h; sourceTree = "<group>"; };
618DA04A1A93D0D600E63AA8 /* ORKAccessibilityFunctions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKAccessibilityFunctions.m; sourceTree = "<group>"; };
@@ -611,8 +679,6 @@
86C40BE11A8D7C5C00081FAC /* ORKVerticalContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKVerticalContainerView.h; sourceTree = "<group>"; };
86C40BE21A8D7C5C00081FAC /* ORKVerticalContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ORKVerticalContainerView.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BE31A8D7C5C00081FAC /* ORKVerticalContainerView_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKVerticalContainerView_Internal.h; sourceTree = "<group>"; };
86C40BE51A8D7C5C00081FAC /* UIApplication+ResearchKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "UIApplication+ResearchKit.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
86C40BE61A8D7C5C00081FAC /* UIApplication+ResearchKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "UIApplication+ResearchKit.m"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BE71A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "UIBarButtonItem+ORKBarButtonItem.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
86C40BE81A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "UIBarButtonItem+ORKBarButtonItem.m"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BE91A8D7C5C00081FAC /* UIResponder+ResearchKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "UIResponder+ResearchKit.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@@ -634,8 +700,6 @@
86C40BFA1A8D7C5C00081FAC /* ORKConsentReviewStepViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ORKConsentReviewStepViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BFB1A8D7C5C00081FAC /* ORKConsentSceneViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKConsentSceneViewController.h; sourceTree = "<group>"; };
86C40BFC1A8D7C5C00081FAC /* ORKConsentSceneViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ORKConsentSceneViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BFD1A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "ORKConsentSection+AssetLoading.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
86C40BFE1A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "ORKConsentSection+AssetLoading.m"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
86C40BFF1A8D7C5C00081FAC /* ORKConsentSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKConsentSection.h; sourceTree = "<group>"; };
86C40C001A8D7C5C00081FAC /* ORKConsentSection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKConsentSection.m; sourceTree = "<group>"; };
86C40C011A8D7C5C00081FAC /* ORKConsentSection_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKConsentSection_Internal.h; sourceTree = "<group>"; };
@@ -669,8 +733,12 @@
B11C549C1A9EF4A700265E61 /* ORKConsentSharingStepViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKConsentSharingStepViewController.h; sourceTree = "<group>"; };
B11C549D1A9EF4A700265E61 /* ORKConsentSharingStepViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ORKConsentSharingStepViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
B11DF3B31AA109C8009E76D2 /* AppledocSettings.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = AppledocSettings.plist; sourceTree = "<group>"; };
B11DF4C21AA10D70009E76D2 /* tr */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; };
B14660481AA10DD7002F95C2 /* zh_TW */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = zh_TW; path = zh_TW.lproj/Localizable.strings; sourceTree = "<group>"; };
B11DF4C21AA10D70009E76D2 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; };
B12EA0131B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKToneAudiometryPracticeStep.h; sourceTree = "<group>"; };
B12EA0141B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKToneAudiometryPracticeStep.m; sourceTree = "<group>"; };
B12EA0171B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKToneAudiometryPracticeStepViewController.h; sourceTree = "<group>"; };
B12EA0181B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKToneAudiometryPracticeStepViewController.m; sourceTree = "<group>"; };
B14660481AA10DD7002F95C2 /* zh_TW */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = zh_TW; path = zh_TW.lproj/Localizable.strings; sourceTree = "<group>"; };
B183A5951A8535D100C76870 /* ResearchKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ResearchKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B18AABE01A9F08D9003871B5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
B1A860DB1A9693C400EA57B7 /* consent_01@2x.m4v */ = {isa = PBXFileReference; lastKnownFileType = file; path = "consent_01@2x.m4v"; sourceTree = "<group>"; };
@@ -687,46 +755,78 @@
B1A860E71A9693C400EA57B7 /* consent_05@3x.m4v */ = {isa = PBXFileReference; lastKnownFileType = file; path = "consent_05@3x.m4v"; sourceTree = "<group>"; };
B1A860E81A9693C400EA57B7 /* consent_06@3x.m4v */ = {isa = PBXFileReference; lastKnownFileType = file; path = "consent_06@3x.m4v"; sourceTree = "<group>"; };
B1A860E91A9693C400EA57B7 /* consent_07@3x.m4v */ = {isa = PBXFileReference; lastKnownFileType = file; path = "consent_07@3x.m4v"; sourceTree = "<group>"; };
B1B349E41AA10DED005FAD66 /* zh_HK */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = zh_HK; path = zh_HK.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E51AA10DF8005FAD66 /* zh_CN */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = zh_CN; path = zh_CN.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E61AA10E02005FAD66 /* vi */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E71AA10E0B005FAD66 /* uk */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E81AA10E12005FAD66 /* th */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = th; path = th.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E91AA10E27005FAD66 /* sv */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EA1AA10E2E005FAD66 /* sk */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EB1AA10E38005FAD66 /* ru */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EC1AA10E40005FAD66 /* ro */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349ED1AA10E47005FAD66 /* pt */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = pt; path = pt.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EE1AA10E4F005FAD66 /* pt_PT */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = pt_PT; path = pt_PT.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EF1AA10E56005FAD66 /* pl */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F01AA10E5E005FAD66 /* nl */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F11AA10E65005FAD66 /* ms */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = ms; path = ms.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F21AA10E6C005FAD66 /* ko */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F31AA10E73005FAD66 /* ja */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F41AA10E79005FAD66 /* it */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F51AA10E80005FAD66 /* id */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = id; path = id.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F61AA10E89005FAD66 /* hu */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F71AA10E90005FAD66 /* hr */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = hr; path = hr.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F81AA10E96005FAD66 /* hi */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = hi; path = hi.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F91AA10E9C005FAD66 /* he */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = he; path = he.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FA1AA10EA2005FAD66 /* fr */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FB1AA10EA8005FAD66 /* fr_CA */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = fr_CA; path = fr_CA.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FC1AA10EAE005FAD66 /* fi */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FD1AA10EB4005FAD66 /* es */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FE1AA10EBA005FAD66 /* es_MX */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = es_MX; path = es_MX.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FF1AA10EC1005FAD66 /* en_GB */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = en_GB; path = en_GB.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A001AA10EC6005FAD66 /* en_AU */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = en_AU; path = en_AU.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A011AA10ECB005FAD66 /* el */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A021AA10ED1005FAD66 /* de */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A031AA10ED5005FAD66 /* da */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A041AA10EDA005FAD66 /* cs */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A051AA10EDF005FAD66 /* ca */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A061AA10EE4005FAD66 /* ar */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A061AABBCCDDEEFFAAA /* no */ = {isa = PBXFileReference; explicitFileType = file.bplist; name = no; path = no.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E41AA10DED005FAD66 /* zh_HK */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = zh_HK; path = zh_HK.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E51AA10DF8005FAD66 /* zh_CN */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = zh_CN; path = zh_CN.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E61AA10E02005FAD66 /* vi */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E71AA10E0B005FAD66 /* uk */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E81AA10E12005FAD66 /* th */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = th; path = th.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349E91AA10E27005FAD66 /* sv */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EA1AA10E2E005FAD66 /* sk */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EB1AA10E38005FAD66 /* ru */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EC1AA10E40005FAD66 /* ro */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349ED1AA10E47005FAD66 /* pt */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EE1AA10E4F005FAD66 /* pt_PT */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = pt_PT; path = pt_PT.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349EF1AA10E56005FAD66 /* pl */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F01AA10E5E005FAD66 /* nl */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F11AA10E65005FAD66 /* ms */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = ms; path = ms.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F21AA10E6C005FAD66 /* ko */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F31AA10E73005FAD66 /* ja */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F41AA10E79005FAD66 /* it */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F51AA10E80005FAD66 /* id */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = id; path = id.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F61AA10E89005FAD66 /* hu */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F71AA10E90005FAD66 /* hr */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = hr; path = hr.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F81AA10E96005FAD66 /* hi */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349F91AA10E9C005FAD66 /* he */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FA1AA10EA2005FAD66 /* fr */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FB1AA10EA8005FAD66 /* fr_CA */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = fr_CA; path = fr_CA.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FC1AA10EAE005FAD66 /* fi */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FD1AA10EB4005FAD66 /* es */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FE1AA10EBA005FAD66 /* es_MX */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = es_MX; path = es_MX.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B349FF1AA10EC1005FAD66 /* en_GB */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = en_GB; path = en_GB.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A001AA10EC6005FAD66 /* en_AU */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = en_AU; path = en_AU.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A011AA10ECB005FAD66 /* el */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A021AA10ED1005FAD66 /* de */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A031AA10ED5005FAD66 /* da */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A041AA10EDA005FAD66 /* cs */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A051AA10EDF005FAD66 /* ca */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A061AA10EE4005FAD66 /* ar */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B34A061AABBCCDDEEFFAAA /* no */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = no; path = no.lproj/Localizable.strings; sourceTree = "<group>"; };
B1B894391A00345200C5CF2D /* ResearchKit_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ResearchKit_Private.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
B1C0F4E21A9BA65F0022C153 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
B1C1DE4F196F541F00F75544 /* ResearchKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResearchKit.h; sourceTree = "<group>"; };
B1C7955D1A9FBF04007279BA /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };
B8760F291AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKScaleRangeDescriptionLabel.h; sourceTree = "<group>"; };
B8760F2A1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKScaleRangeDescriptionLabel.m; sourceTree = "<group>"; };
BC01B0FA1B0EB99700863803 /* ORKTintedImageView_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKTintedImageView_Internal.h; sourceTree = "<group>"; };
BC13CE371B0660220044153C /* ORKNavigableOrderedTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKNavigableOrderedTask.h; sourceTree = "<group>"; };
BC13CE381B0660220044153C /* ORKNavigableOrderedTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKNavigableOrderedTask.m; sourceTree = "<group>"; };
BC13CE3B1B0662990044153C /* ORKStepNavigationRule_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKStepNavigationRule_Private.h; sourceTree = "<group>"; };
BC13CE3D1B0662A80044153C /* ORKOrderedTask_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKOrderedTask_Internal.h; sourceTree = "<group>"; };
BC13CE3F1B0666FD0044153C /* ORKResultPredicate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKResultPredicate.h; sourceTree = "<group>"; };
BC13CE411B066A990044153C /* ORKStepNavigationRule_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKStepNavigationRule_Internal.h; sourceTree = "<group>"; };
BC4194271AE8453A00073D6B /* ORKObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKObserver.h; sourceTree = "<group>"; };
BC4194281AE8453A00073D6B /* ORKObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKObserver.m; sourceTree = "<group>"; };
BCA5C0331AEC05F20092AC8D /* ORKStepNavigationRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKStepNavigationRule.h; sourceTree = "<group>"; };
BCA5C0341AEC05F20092AC8D /* ORKStepNavigationRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKStepNavigationRule.m; sourceTree = "<group>"; };
BCAD50E71B0201EE0034806A /* ORKTaskTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKTaskTests.m; sourceTree = "<group>"; };
BCB96C121B19C0EC002A0B96 /* ORKStepTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKStepTests.m; sourceTree = "<group>"; };
BCFB2EAF1AE70E4E0070B5D0 /* ORKConsentSceneViewController_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ORKConsentSceneViewController_Internal.h; sourceTree = "<group>"; };
BCFF24BC1B0798D10044EC35 /* ORKResultPredicate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKResultPredicate.m; sourceTree = "<group>"; };
D42FEFB61AF7557000A124F8 /* ORKImageCaptureView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKImageCaptureView.h; sourceTree = "<group>"; };
D42FEFB71AF7557000A124F8 /* ORKImageCaptureView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKImageCaptureView.m; sourceTree = "<group>"; };
D44239771AF17F5100559D96 /* ORKImageCaptureStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKImageCaptureStep.h; sourceTree = "<group>"; };
D44239781AF17F5100559D96 /* ORKImageCaptureStep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKImageCaptureStep.m; sourceTree = "<group>"; };
D442397B1AF17F7600559D96 /* ORKImageCaptureStepViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKImageCaptureStepViewController.h; sourceTree = "<group>"; };
D442397C1AF17F7600559D96 /* ORKImageCaptureStepViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKImageCaptureStepViewController.m; sourceTree = "<group>"; };
D45852081AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKImageCaptureCameraPreviewView.h; sourceTree = "<group>"; };
D45852091AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKImageCaptureCameraPreviewView.m; sourceTree = "<group>"; };
FA7A9D2A1B082688005A2BEA /* ORKConsentDocumentTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKConsentDocumentTests.m; sourceTree = "<group>"; };
FA7A9D2D1B083DD3005A2BEA /* ORKConsentSectionFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKConsentSectionFormatter.h; sourceTree = "<group>"; };
FA7A9D2E1B083DD3005A2BEA /* ORKConsentSectionFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKConsentSectionFormatter.m; sourceTree = "<group>"; };
FA7A9D311B0843A9005A2BEA /* ORKConsentSignatureFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKConsentSignatureFormatter.h; sourceTree = "<group>"; };
FA7A9D321B0843A9005A2BEA /* ORKConsentSignatureFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKConsentSignatureFormatter.m; sourceTree = "<group>"; };
FA7A9D361B09365F005A2BEA /* ORKConsentSectionFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKConsentSectionFormatterTests.m; sourceTree = "<group>"; };
FA7A9D381B0969A7005A2BEA /* ORKConsentSignatureFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKConsentSignatureFormatterTests.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -749,6 +849,40 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
147503AC1AEE8058004B17F3 /* Tone Audiometry */ = {
isa = PBXGroup;
children = (
147503AD1AEE8071004B17F3 /* ORKAudioGenerator.h */,
147503AE1AEE8071004B17F3 /* ORKAudioGenerator.m */,
147503B11AEE807C004B17F3 /* ORKToneAudiometryContentView.h */,
147503B21AEE807C004B17F3 /* ORKToneAudiometryContentView.m */,
B12EA0131B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.h */,
B12EA0141B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.m */,
147503B31AEE807C004B17F3 /* ORKToneAudiometryStep.h */,
147503B41AEE807C004B17F3 /* ORKToneAudiometryStep.m */,
B12EA0171B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.h */,
B12EA0181B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.m */,
147503B51AEE807C004B17F3 /* ORKToneAudiometryStepViewController.h */,
147503B61AEE807C004B17F3 /* ORKToneAudiometryStepViewController.m */,
);
name = "Tone Audiometry";
sourceTree = "<group>";
};
25ECC0921AFBD64800F3D63B /* Reaction Time */ = {
isa = PBXGroup;
children = (
25ECC0931AFBD68300F3D63B /* ORKReactionTimeStep.h */,
25ECC0941AFBD68300F3D63B /* ORKReactionTimeStep.m */,
25ECC0991AFBD8B300F3D63B /* ORKReactionTimeViewController.h */,
25ECC09A1AFBD8B300F3D63B /* ORKReactionTimeViewController.m */,
25ECC09D1AFBD92D00F3D63B /* ORKReactionTimeContentView.h */,
25ECC09E1AFBD92D00F3D63B /* ORKReactionTimeContentView.m */,
25ECC0A11AFBDD2700F3D63B /* ORKReactionTimeStimulusView.h */,
25ECC0A21AFBDD2700F3D63B /* ORKReactionTimeStimulusView.m */,
);
name = "Reaction Time";
sourceTree = "<group>";
};
3FFF18341829DB1D00167070 = {
isa = PBXGroup;
children = (
@@ -815,8 +949,10 @@
B12EFF4E1AB2161500A80147 /* Audio */,
B12EFF5D1AB2177700A80147 /* Fitness */,
B12EFF5E1AB2177D00A80147 /* Spatial Span Memory */,
25ECC0921AFBD64800F3D63B /* Reaction Time */,
B12EFF5F1AB2178500A80147 /* Tapping */,
B12EFF601AB2178B00A80147 /* Walking */,
147503AC1AEE8058004B17F3 /* Tone Audiometry */,
);
path = ActiveTasks;
sourceTree = "<group>";
@@ -833,6 +969,7 @@
B12EFF3D1AB2121000A80147 /* Definitions */,
B12EFF321AB2106F00A80147 /* UIKitCategories */,
B12EFF311AB2100400A80147 /* Skin */,
BC4194261AE8451F00073D6B /* Misc */,
);
path = Common;
sourceTree = "<group>";
@@ -840,6 +977,7 @@
86C40BEB1A8D7C5C00081FAC /* Consent */ = {
isa = PBXGroup;
children = (
FA7A9D2C1B083D90005A2BEA /* Formatters */,
B12EFF451AB214E000A80147 /* Model */,
B12EFF461AB2150C00A80147 /* Visual */,
B12EFF481AB2152D00A80147 /* Sharing */,
@@ -851,16 +989,20 @@
86CC8EA61AC09383001CCD89 /* ResearchKitTests */ = {
isa = PBXGroup;
children = (
86D348001AC16175006DB02B /* ORKRecorderTests.m */,
FA7A9D351B09362D005A2BEA /* Consent */,
86CC8EA71AC09383001CCD89 /* Info.plist */,
86CC8EA81AC09383001CCD89 /* ORKAccessibilityTests.m */,
86CC8EA91AC09383001CCD89 /* ORKChoiceAnswerFormatHelperTests.m */,
86CC8EAA1AC09383001CCD89 /* ORKConsentTests.m */,
86CC8EAB1AC09383001CCD89 /* ORKDataLoggerManagerTests.m */,
86CC8EAC1AC09383001CCD89 /* ORKDataLoggerTests.m */,
86CC8EAD1AC09383001CCD89 /* ORKHKSampleTests.m */,
86D348001AC16175006DB02B /* ORKRecorderTests.m */,
86CC8EAF1AC09383001CCD89 /* ORKResultTests.m */,
BCB96C121B19C0EC002A0B96 /* ORKStepTests.m */,
BCAD50E71B0201EE0034806A /* ORKTaskTests.m */,
86CC8EB01AC09383001CCD89 /* ORKTextChoiceCellGroupTests.m */,
86CC8EA71AC09383001CCD89 /* Info.plist */,
2EBFE11C1AE1B32D00CB8254 /* ORKUIViewAccessibilityTests.m */,
2EBFE11F1AE1B74100CB8254 /* ORKVoiceEngineTests.m */,
);
path = ResearchKitTests;
sourceTree = "<group>";
@@ -887,6 +1029,7 @@
B12EFF311AB2100400A80147 /* Skin */ = {
isa = PBXGroup;
children = (
BC01B0FA1B0EB99700863803 /* ORKTintedImageView_Internal.h */,
86C40BB71A8D7C5C00081FAC /* ORKSkin.h */,
86C40BB81A8D7C5C00081FAC /* ORKSkin.m */,
86C40B7A1A8D7C5C00081FAC /* ORKDefaultFont.h */,
@@ -918,6 +1061,8 @@
86C40BB11A8D7C5C00081FAC /* ORKScaleValueLabel.m */,
86C40BAC1A8D7C5C00081FAC /* ORKScaleRangeLabel.h */,
86C40BAD1A8D7C5C00081FAC /* ORKScaleRangeLabel.m */,
B8760F291AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.h */,
B8760F2A1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.m */,
86C40BC01A8D7C5C00081FAC /* ORKSubheadlineLabel.h */,
86C40BC11A8D7C5C00081FAC /* ORKSubheadlineLabel.m */,
86C40BD31A8D7C5C00081FAC /* ORKTapCountLabel.h */,
@@ -939,8 +1084,6 @@
B12EFF321AB2106F00A80147 /* UIKitCategories */ = {
isa = PBXGroup;
children = (
86C40BE51A8D7C5C00081FAC /* UIApplication+ResearchKit.h */,
86C40BE61A8D7C5C00081FAC /* UIApplication+ResearchKit.m */,
86C40BE71A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.h */,
86C40BE81A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.m */,
86C40BE91A8D7C5C00081FAC /* UIResponder+ResearchKit.h */,
@@ -952,9 +1095,12 @@
B12EFF331AB2110300A80147 /* Task */ = {
isa = PBXGroup;
children = (
BC13CE371B0660220044153C /* ORKNavigableOrderedTask.h */,
BC13CE381B0660220044153C /* ORKNavigableOrderedTask.m */,
86C40BD51A8D7C5C00081FAC /* ORKTask.h */,
86C40B9D1A8D7C5C00081FAC /* ORKOrderedTask.h */,
86C40B9E1A8D7C5C00081FAC /* ORKOrderedTask.m */,
BC13CE3D1B0662A80044153C /* ORKOrderedTask_Internal.h */,
86C40BD71A8D7C5C00081FAC /* ORKTaskViewController.h */,
86C40BD81A8D7C5C00081FAC /* ORKTaskViewController.m */,
86C40BD91A8D7C5C00081FAC /* ORKTaskViewController_Internal.h */,
@@ -972,12 +1118,17 @@
86C40BBC1A8D7C5C00081FAC /* ORKStepViewController.h */,
86C40BBD1A8D7C5C00081FAC /* ORKStepViewController.m */,
86C40BBE1A8D7C5C00081FAC /* ORKStepViewController_Internal.h */,
BCA5C0331AEC05F20092AC8D /* ORKStepNavigationRule.h */,
BCA5C0341AEC05F20092AC8D /* ORKStepNavigationRule.m */,
BC13CE3B1B0662990044153C /* ORKStepNavigationRule_Private.h */,
BC13CE411B066A990044153C /* ORKStepNavigationRule_Internal.h */,
86C40B771A8D7C5C00081FAC /* ORKCustomStepView.h */,
86C40B781A8D7C5C00081FAC /* ORKCustomStepView.m */,
86C40B791A8D7C5C00081FAC /* ORKCustomStepView_Internal.h */,
B12EFF351AB2116400A80147 /* Instruction Step */,
B12EFF361AB2117B00A80147 /* Question Step */,
B12EFF3C1AB211FB00A80147 /* Form Step */,
D44239761AF17EE700559D96 /* Image Capture Step */,
);
name = Step;
sourceTree = "<group>";
@@ -1016,6 +1167,8 @@
86C40BA71A8D7C5C00081FAC /* ORKResult.h */,
86C40BA81A8D7C5C00081FAC /* ORKResult.m */,
86C40BA91A8D7C5C00081FAC /* ORKResult_Private.h */,
BC13CE3F1B0666FD0044153C /* ORKResultPredicate.h */,
BCFF24BC1B0798D10044EC35 /* ORKResultPredicate.m */,
);
name = Result;
sourceTree = "<group>";
@@ -1178,8 +1331,6 @@
86C40BFF1A8D7C5C00081FAC /* ORKConsentSection.h */,
86C40C001A8D7C5C00081FAC /* ORKConsentSection.m */,
86C40C011A8D7C5C00081FAC /* ORKConsentSection_Internal.h */,
86C40BFD1A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.h */,
86C40BFE1A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.m */,
86C40C021A8D7C5C00081FAC /* ORKConsentSignature.h */,
86C40C031A8D7C5C00081FAC /* ORKConsentSignature.m */,
);
@@ -1261,6 +1412,7 @@
86C40C0E1A8D7C5C00081FAC /* ORKVisualConsentTransitionAnimator.h */,
86C40C0F1A8D7C5C00081FAC /* ORKVisualConsentTransitionAnimator.m */,
B12EFF441AB214B400A80147 /* Tinted Animations */,
BCFB2EAF1AE70E4E0070B5D0 /* ORKConsentSceneViewController_Internal.h */,
);
name = "Consent Views";
sourceTree = "<group>";
@@ -1496,6 +1648,7 @@
children = (
86C40B4D1A8D7C5B00081FAC /* ORKVoiceEngine.h */,
86C40B4E1A8D7C5B00081FAC /* ORKVoiceEngine.m */,
2EBFE11E1AE1B68800CB8254 /* ORKVoiceEngine_Internal.h */,
);
name = "Speech Synthesis";
sourceTree = "<group>";
@@ -1545,6 +1698,52 @@
path = Localized;
sourceTree = "<group>";
};
BC4194261AE8451F00073D6B /* Misc */ = {
isa = PBXGroup;
children = (
BC4194271AE8453A00073D6B /* ORKObserver.h */,
BC4194281AE8453A00073D6B /* ORKObserver.m */,
);
name = Misc;
sourceTree = "<group>";
};
D44239761AF17EE700559D96 /* Image Capture Step */ = {
isa = PBXGroup;
children = (
D44239771AF17F5100559D96 /* ORKImageCaptureStep.h */,
D44239781AF17F5100559D96 /* ORKImageCaptureStep.m */,
D442397B1AF17F7600559D96 /* ORKImageCaptureStepViewController.h */,
D442397C1AF17F7600559D96 /* ORKImageCaptureStepViewController.m */,
D45852081AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.h */,
D45852091AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.m */,
D42FEFB61AF7557000A124F8 /* ORKImageCaptureView.h */,
D42FEFB71AF7557000A124F8 /* ORKImageCaptureView.m */,
);
name = "Image Capture Step";
sourceTree = "<group>";
};
FA7A9D2C1B083D90005A2BEA /* Formatters */ = {
isa = PBXGroup;
children = (
FA7A9D2D1B083DD3005A2BEA /* ORKConsentSectionFormatter.h */,
FA7A9D2E1B083DD3005A2BEA /* ORKConsentSectionFormatter.m */,
FA7A9D311B0843A9005A2BEA /* ORKConsentSignatureFormatter.h */,
FA7A9D321B0843A9005A2BEA /* ORKConsentSignatureFormatter.m */,
);
name = Formatters;
sourceTree = "<group>";
};
FA7A9D351B09362D005A2BEA /* Consent */ = {
isa = PBXGroup;
children = (
86CC8EAA1AC09383001CCD89 /* ORKConsentTests.m */,
FA7A9D2A1B082688005A2BEA /* ORKConsentDocumentTests.m */,
FA7A9D361B09365F005A2BEA /* ORKConsentSectionFormatterTests.m */,
FA7A9D381B0969A7005A2BEA /* ORKConsentSignatureFormatterTests.m */,
);
name = Consent;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -1552,35 +1751,43 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
BCA5C0351AEC05F20092AC8D /* ORKStepNavigationRule.h in Headers */,
BC13CE391B0660220044153C /* ORKNavigableOrderedTask.h in Headers */,
86C40C921A8D7C5C00081FAC /* ORKAudioRecorder.h in Headers */,
86C40D8E1A8D7C5C00081FAC /* ORKStep.h in Headers */,
618DA04E1A93D0D600E63AA8 /* ORKAccessibility.h in Headers */,
86B781BB1AA668ED00688151 /* ORKTimeIntervalPicker.h in Headers */,
86C40C6A1A8D7C5C00081FAC /* CMDeviceMotion+ORKJSONDictionary.h in Headers */,
86C40CE41A8D7C5C00081FAC /* ORKAnswerFormat.h in Headers */,
25ECC0951AFBD68300F3D63B /* ORKReactionTimeStep.h in Headers */,
86C40D0A1A8D7C5C00081FAC /* ORKCustomStepView.h in Headers */,
86C40DCE1A8D7C5C00081FAC /* ORKTaskViewController_Internal.h in Headers */,
25ECC09F1AFBD92D00F3D63B /* ORKReactionTimeContentView.h in Headers */,
86C40C361A8D7C5C00081FAC /* ORKSpatialSpanGame.h in Headers */,
86C40CAC1A8D7C5C00081FAC /* ORKRecorder.h in Headers */,
865EA1681ABA1AA10037C68E /* ORKPicker.h in Headers */,
86C40CC81A8D7C5C00081FAC /* ORKFormItemCell.h in Headers */,
86C40DF21A8D7C5C00081FAC /* ORKConsentReviewController.h in Headers */,
86C40C961A8D7C5C00081FAC /* ORKDataLogger.h in Headers */,
BC13CE421B066A990044153C /* ORKStepNavigationRule_Internal.h in Headers */,
86C40D781A8D7C5C00081FAC /* ORKScaleSlider.h in Headers */,
86C40D241A8D7C5C00081FAC /* ORKFormStepViewController.h in Headers */,
86C40D6A1A8D7C5C00081FAC /* ORKResult.h in Headers */,
86C40DD61A8D7C5C00081FAC /* ORKUnitLabel.h in Headers */,
86C40D9C1A8D7C5C00081FAC /* ORKSubheadlineLabel.h in Headers */,
147503BB1AEE807C004B17F3 /* ORKToneAudiometryStepViewController.h in Headers */,
86C40D441A8D7C5C00081FAC /* ORKInstructionStepViewController.h in Headers */,
86C40D841A8D7C5C00081FAC /* ORKSelectionTitleLabel.h in Headers */,
86C40E141A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.h in Headers */,
BC13CE3C1B0662990044153C /* ORKStepNavigationRule_Private.h in Headers */,
86C40D3C1A8D7C5C00081FAC /* ORKImageChoiceLabel.h in Headers */,
BC4194291AE8453A00073D6B /* ORKObserver.h in Headers */,
86C40C661A8D7C5C00081FAC /* CMAccelerometerData+ORKJSONDictionary.h in Headers */,
86C40DE61A8D7C5C00081FAC /* UIApplication+ResearchKit.h in Headers */,
25ECC0A31AFBDD2700F3D63B /* ORKReactionTimeStimulusView.h in Headers */,
86C40D701A8D7C5C00081FAC /* ORKRoundTappingButton.h in Headers */,
865EA1621AB8DF750037C68E /* ORKDateTimePicker.h in Headers */,
86C40DA01A8D7C5C00081FAC /* ORKSurveyAnswerCell.h in Headers */,
86C40D941A8D7C5C00081FAC /* ORKStepViewController.h in Headers */,
B8760F2B1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.h in Headers */,
86C40C221A8D7C5C00081FAC /* ORKCountdownStep.h in Headers */,
86C40DB61A8D7C5C00081FAC /* ORKSurveyAnswerCellForText.h in Headers */,
86C40E281A8D7C5C00081FAC /* ORKSignatureView.h in Headers */,
@@ -1593,14 +1800,17 @@
86C40D201A8D7C5C00081FAC /* ORKFormStep.h in Headers */,
86C40C761A8D7C5C00081FAC /* HKSample+ORKJSONDictionary.h in Headers */,
86C40CEA1A8D7C5C00081FAC /* ORKAnswerTextField.h in Headers */,
B12EA0191B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.h in Headers */,
B183A4A21A8535D100C76870 /* ResearchKit_Private.h in Headers */,
86C40CE81A8D7C5C00081FAC /* ORKAnswerFormat_Internal.h in Headers */,
86C40D021A8D7C5C00081FAC /* ORKContinueButton.h in Headers */,
86C40D681A8D7C5C00081FAC /* ORKQuestionStepViewController_Private.h in Headers */,
86C40D121A8D7C5C00081FAC /* ORKDefines.h in Headers */,
86C40D401A8D7C5C00081FAC /* ORKInstructionStep.h in Headers */,
147503B71AEE807C004B17F3 /* ORKToneAudiometryContentView.h in Headers */,
86C40D981A8D7C5C00081FAC /* ORKStepViewController_Internal.h in Headers */,
86B89ABB1AB3BECC001626A4 /* ORKStepHeaderView.h in Headers */,
D42FEFB81AF7557000A124F8 /* ORKImageCaptureView.h in Headers */,
86C40D1A1A8D7C5C00081FAC /* ORKFormItem_Internal.h in Headers */,
86C40E1C1A8D7C5C00081FAC /* ORKConsentSection_Internal.h in Headers */,
86C40C7A1A8D7C5C00081FAC /* ORKAccelerometerRecorder.h in Headers */,
@@ -1631,10 +1841,12 @@
86C40D7C1A8D7C5C00081FAC /* ORKScaleValueLabel.h in Headers */,
86C40E2C1A8D7C5C00081FAC /* ORKVisualConsentStep.h in Headers */,
86C40CB81A8D7C5C00081FAC /* ORKVoiceEngine.h in Headers */,
FA7A9D331B0843A9005A2BEA /* ORKConsentSignatureFormatter.h in Headers */,
86C40C5A1A8D7C5C00081FAC /* ORKWalkingTaskStep.h in Headers */,
86C40E361A8D7C5C00081FAC /* ORKVisualConsentTransitionAnimator.h in Headers */,
86AD910D1AB7AE4100361FEB /* ORKNavigationContainerView_Internal.h in Headers */,
86C40CEE1A8D7C5C00081FAC /* ORKAnswerTextView.h in Headers */,
B12EA0151B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.h in Headers */,
86C40C421A8D7C5C00081FAC /* ORKSpatialSpanMemoryStep.h in Headers */,
86C40C6E1A8D7C5C00081FAC /* CMMotionActivity+ORKJSONDictionary.h in Headers */,
B11C54991A9EEF8800265E61 /* ORKConsentSharingStep.h in Headers */,
@@ -1643,11 +1855,15 @@
86C40C841A8D7C5C00081FAC /* ORKActiveStepTimer.h in Headers */,
86B781BD1AA668ED00688151 /* ORKValuePicker.h in Headers */,
86C40DE21A8D7C5C00081FAC /* ORKVerticalContainerView_Internal.h in Headers */,
BC01B0FB1B0EB99700863803 /* ORKTintedImageView_Internal.h in Headers */,
86B89ABE1AB3BFDB001626A4 /* ORKStepHeaderView_Internal.h in Headers */,
86C40C1E1A8D7C5C00081FAC /* ORKAudioStepViewController.h in Headers */,
147503AF1AEE8071004B17F3 /* ORKAudioGenerator.h in Headers */,
86AD91141AB7B97E00361FEB /* ORKQuestionStepView.h in Headers */,
86C40C621A8D7C5C00081FAC /* CLLocation+ORKJSONDictionary.h in Headers */,
86C40D801A8D7C5C00081FAC /* ORKSelectionSubTitleLabel.h in Headers */,
D458520A1AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.h in Headers */,
D44239791AF17F5100559D96 /* ORKImageCaptureStep.h in Headers */,
86C40CB21A8D7C5C00081FAC /* ORKRecorder_Private.h in Headers */,
86C40C881A8D7C5C00081FAC /* ORKActiveStepTimerView.h in Headers */,
86C40C161A8D7C5C00081FAC /* ORKAudioContentView.h in Headers */,
@@ -1656,6 +1872,7 @@
86C40CF61A8D7C5C00081FAC /* ORKBorderedButton.h in Headers */,
86C40D4A1A8D7C5C00081FAC /* ORKLabel.h in Headers */,
861D11A91AA691BB003C98A7 /* ORKScaleSliderView.h in Headers */,
BC13CE3E1B0662A80044153C /* ORKOrderedTask_Internal.h in Headers */,
86C40C3E1A8D7C5C00081FAC /* ORKSpatialSpanMemoryContentView.h in Headers */,
86C40CC01A8D7C5C00081FAC /* ORKCompletionStep.h in Headers */,
86C40DF61A8D7C5C00081FAC /* ORKConsentSignatureController.h in Headers */,
@@ -1663,6 +1880,7 @@
86C40D281A8D7C5C00081FAC /* ORKFormTextView.h in Headers */,
86C40DEE1A8D7C5C00081FAC /* UIResponder+ResearchKit.h in Headers */,
86C40E041A8D7C5C00081FAC /* ORKConsentLearnMoreViewController.h in Headers */,
25ECC09B1AFBD8B300F3D63B /* ORKReactionTimeViewController.h in Headers */,
86C40D061A8D7C5C00081FAC /* ORKCountdownLabel.h in Headers */,
86C40C2A1A8D7C5C00081FAC /* ORKFitnessContentView.h in Headers */,
86C40DC21A8D7C5C00081FAC /* ORKTapCountLabel.h in Headers */,
@@ -1675,11 +1893,13 @@
86C40C821A8D7C5C00081FAC /* ORKActiveStep_Internal.h in Headers */,
86C40D481A8D7C5C00081FAC /* ORKInstructionStepViewController_Internal.h in Headers */,
86C40D341A8D7C5C00081FAC /* ORKHelpers.h in Headers */,
FA7A9D2F1B083DD3005A2BEA /* ORKConsentSectionFormatter.h in Headers */,
86C40E341A8D7C5C00081FAC /* ORKVisualConsentStepViewController_Internal.h in Headers */,
86C40D381A8D7C5C00081FAC /* ORKHTMLPDFWriter.h in Headers */,
86C40D561A8D7C5C00081FAC /* ORKOrderedTask.h in Headers */,
86C40C4E1A8D7C5C00081FAC /* ORKTappingContentView.h in Headers */,
86C40CA01A8D7C5C00081FAC /* ORKHealthQuantityTypeRecorder.h in Headers */,
BC13CE401B0666FD0044153C /* ORKResultPredicate.h in Headers */,
86C40CFA1A8D7C5C00081FAC /* ORKCaption1Label.h in Headers */,
86C40E081A8D7C5C00081FAC /* ORKConsentReviewStep.h in Headers */,
86C40C901A8D7C5C00081FAC /* ORKActiveStepViewController_Internal.h in Headers */,
@@ -1704,12 +1924,14 @@
86C40D6E1A8D7C5C00081FAC /* ORKResult_Private.h in Headers */,
86C40D161A8D7C5C00081FAC /* ORKErrors.h in Headers */,
861D11B51AA7D073003C98A7 /* ORKTextChoiceCellGroup.h in Headers */,
147503B91AEE807C004B17F3 /* ORKToneAudiometryStep.h in Headers */,
86C40C9A1A8D7C5C00081FAC /* ORKDataLogger_Private.h in Headers */,
861D11AD1AA7951F003C98A7 /* ORKChoiceAnswerFormatHelper.h in Headers */,
86C40C461A8D7C5C00081FAC /* ORKSpatialSpanMemoryStepViewController.h in Headers */,
86C40C521A8D7C5C00081FAC /* ORKTappingIntervalStep.h in Headers */,
86C40D8A1A8D7C5C00081FAC /* ORKSkin.h in Headers */,
86C40DFE1A8D7C5C00081FAC /* ORKConsentDocument.h in Headers */,
D442397D1AF17F7600559D96 /* ORKImageCaptureStepViewController.h in Headers */,
86C40C4A1A8D7C5C00081FAC /* ORKSpatialSpanTargetView.h in Headers */,
86C40C1A1A8D7C5C00081FAC /* ORKAudioStep.h in Headers */,
);
@@ -1900,7 +2122,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if [ ! -x /usr/local/bin/appledoc ]; then\n echo \"error: appledoc is required for building ResearchKit's documentation. See http://appledoc.gentlebytes.com\" 1>&2\n exit 1\nfi\n\necho \"warning: warnings are a result of https://github.com/tomaz/appledoc/issues/348\"\n\n/usr/local/bin/appledoc --print-settings --publish-docset --install-docset --output \"${BUILT_PRODUCTS_DIR}/docs/\" --include \"docs/ActiveTasks\" --include \"docs/InformedConsent\" --include \"docs/Overview\" --include \"docs/Survey\" --ignore \"docs/templates\" --templates \"docs/templates\" \"${BUILT_PRODUCTS_DIR}/ResearchKit.framework\" \"docs\"\n\necho \"warning: Opening documentation in browser...\"\nopen \"$HOME/Library/Developer/Shared/Documentation/DocSets/org.researchkit.ResearchKit.docset/Contents/Resources/Documents/index.html\"";
shellScript = "if [ ! -x /usr/local/bin/appledoc ]; then\n echo \"error: appledoc is required for building ResearchKit's documentation. See http://appledoc.gentlebytes.com\" 1>&2\n exit 1\nfi\n\n/usr/local/bin/appledoc --print-settings --publish-docset --install-docset --output \"${BUILT_PRODUCTS_DIR}/docs/\" --include \"docs/ActiveTasks\" --include \"docs/InformedConsent\" --include \"docs/Overview\" --include \"docs/Survey\" --ignore \"docs/templates\" --templates \"docs/templates\" \"${BUILT_PRODUCTS_DIR}/ResearchKit.framework\" \"docs\"\n\necho \"note: Opening documentation in browser...\"\nopen \"$HOME/Library/Developer/Shared/Documentation/DocSets/org.researchkit.ResearchKit.docset/Contents/Resources/Documents/index.html\"";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -1912,10 +2134,17 @@
files = (
86CC8EB71AC09383001CCD89 /* ORKDataLoggerTests.m in Sources */,
86CC8EBA1AC09383001CCD89 /* ORKResultTests.m in Sources */,
FA7A9D391B0969A7005A2BEA /* ORKConsentSignatureFormatterTests.m in Sources */,
86CC8EB81AC09383001CCD89 /* ORKHKSampleTests.m in Sources */,
BCB96C131B19C0EC002A0B96 /* ORKStepTests.m in Sources */,
86CC8EB51AC09383001CCD89 /* ORKConsentTests.m in Sources */,
2EBFE11D1AE1B32D00CB8254 /* ORKUIViewAccessibilityTests.m in Sources */,
86CC8EB41AC09383001CCD89 /* ORKChoiceAnswerFormatHelperTests.m in Sources */,
2EBFE1201AE1B74100CB8254 /* ORKVoiceEngineTests.m in Sources */,
BCAD50E81B0201EE0034806A /* ORKTaskTests.m in Sources */,
86CC8EBB1AC09383001CCD89 /* ORKTextChoiceCellGroupTests.m in Sources */,
FA7A9D2B1B082688005A2BEA /* ORKConsentDocumentTests.m in Sources */,
FA7A9D371B09365F005A2BEA /* ORKConsentSectionFormatterTests.m in Sources */,
86D348021AC161B0006DB02B /* ORKRecorderTests.m in Sources */,
86CC8EB61AC09383001CCD89 /* ORKDataLoggerManagerTests.m in Sources */,
86CC8EB31AC09383001CCD89 /* ORKAccessibilityTests.m in Sources */,
@@ -1930,7 +2159,9 @@
86C40E2E1A8D7C5C00081FAC /* ORKVisualConsentStep.m in Sources */,
86C40CA61A8D7C5C00081FAC /* ORKLocationRecorder.m in Sources */,
86C40CB61A8D7C5C00081FAC /* ORKTouchRecorder.m in Sources */,
B12EA0161B0D73A500F9F554 /* ORKToneAudiometryPracticeStep.m in Sources */,
86C40DC41A8D7C5C00081FAC /* ORKTapCountLabel.m in Sources */,
25ECC0A01AFBD92D00F3D63B /* ORKReactionTimeContentView.m in Sources */,
86C40D4C1A8D7C5C00081FAC /* ORKLabel.m in Sources */,
86C40C9E1A8D7C5C00081FAC /* ORKDeviceMotionRecorder.m in Sources */,
86C40D961A8D7C5C00081FAC /* ORKStepViewController.m in Sources */,
@@ -1942,6 +2173,7 @@
86C40C381A8D7C5C00081FAC /* ORKSpatialSpanGame.m in Sources */,
86C40C481A8D7C5C00081FAC /* ORKSpatialSpanMemoryStepViewController.m in Sources */,
86C40CDA1A8D7C5C00081FAC /* ORKTextFieldView.m in Sources */,
B8760F2C1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.m in Sources */,
86C40D821A8D7C5C00081FAC /* ORKSelectionSubTitleLabel.m in Sources */,
86C40DCC1A8D7C5C00081FAC /* ORKTaskViewController.m in Sources */,
86C40E061A8D7C5C00081FAC /* ORKConsentLearnMoreViewController.m in Sources */,
@@ -1949,9 +2181,12 @@
86C40C801A8D7C5C00081FAC /* ORKActiveStep.m in Sources */,
86C40D721A8D7C5C00081FAC /* ORKRoundTappingButton.m in Sources */,
86C40E2A1A8D7C5C00081FAC /* ORKSignatureView.m in Sources */,
BCFF24BD1B0798D10044EC35 /* ORKResultPredicate.m in Sources */,
25ECC0A41AFBDD2700F3D63B /* ORKReactionTimeStimulusView.m in Sources */,
86C40CBA1A8D7C5C00081FAC /* ORKVoiceEngine.m in Sources */,
861D11B61AA7D073003C98A7 /* ORKTextChoiceCellGroup.m in Sources */,
86C40CCA1A8D7C5C00081FAC /* ORKFormItemCell.m in Sources */,
147503B81AEE807C004B17F3 /* ORKToneAudiometryContentView.m in Sources */,
86C40CBE1A8D7C5C00081FAC /* UITouch+ORKJSONDictionary.m in Sources */,
618DA0521A93D0D600E63AA8 /* ORKAccessibilityFunctions.m in Sources */,
86C40DB81A8D7C5C00081FAC /* ORKSurveyAnswerCellForText.m in Sources */,
@@ -1972,28 +2207,35 @@
86C40D001A8D7C5C00081FAC /* ORKChoiceViewCell.m in Sources */,
86C40C4C1A8D7C5C00081FAC /* ORKSpatialSpanTargetView.m in Sources */,
86C40D9E1A8D7C5C00081FAC /* ORKSubheadlineLabel.m in Sources */,
D42FEFB91AF7557000A124F8 /* ORKImageCaptureView.m in Sources */,
86C40C401A8D7C5C00081FAC /* ORKSpatialSpanMemoryContentView.m in Sources */,
147503BC1AEE807C004B17F3 /* ORKToneAudiometryStepViewController.m in Sources */,
86AD910B1AB7AD1E00361FEB /* ORKNavigationContainerView.m in Sources */,
865EA1631AB8DF750037C68E /* ORKDateTimePicker.m in Sources */,
86C40C781A8D7C5C00081FAC /* HKSample+ORKJSONDictionary.m in Sources */,
86C40D421A8D7C5C00081FAC /* ORKInstructionStep.m in Sources */,
86C40C2C1A8D7C5C00081FAC /* ORKFitnessContentView.m in Sources */,
D458520B1AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.m in Sources */,
86C40E1A1A8D7C5C00081FAC /* ORKConsentSection.m in Sources */,
86C40C241A8D7C5C00081FAC /* ORKCountdownStep.m in Sources */,
86C40CA21A8D7C5C00081FAC /* ORKHealthQuantityTypeRecorder.m in Sources */,
86C40DC01A8D7C5C00081FAC /* ORKTableViewCell.m in Sources */,
BC41942A1AE8453A00073D6B /* ORKObserver.m in Sources */,
86C40C681A8D7C5C00081FAC /* CMAccelerometerData+ORKJSONDictionary.m in Sources */,
86C40C701A8D7C5C00081FAC /* CMMotionActivity+ORKJSONDictionary.m in Sources */,
147503B01AEE8071004B17F3 /* ORKAudioGenerator.m in Sources */,
86C40D7E1A8D7C5C00081FAC /* ORKScaleValueLabel.m in Sources */,
B12EA01A1B0D76AD00F9F554 /* ORKToneAudiometryPracticeStepViewController.m in Sources */,
86C40D901A8D7C5C00081FAC /* ORKStep.m in Sources */,
86C40D2E1A8D7C5C00081FAC /* ORKHeadlineLabel.m in Sources */,
FA7A9D341B0843A9005A2BEA /* ORKConsentSignatureFormatter.m in Sources */,
86C40CFC1A8D7C5C00081FAC /* ORKCaption1Label.m in Sources */,
86C40E001A8D7C5C00081FAC /* ORKConsentDocument.m in Sources */,
D442397A1AF17F5100559D96 /* ORKImageCaptureStep.m in Sources */,
86C40CDE1A8D7C5C00081FAC /* ORKTintedImageView.m in Sources */,
86B781BC1AA668ED00688151 /* ORKTimeIntervalPicker.m in Sources */,
86B781BE1AA668ED00688151 /* ORKValuePicker.m in Sources */,
86B89ABC1AB3BECC001626A4 /* ORKStepHeaderView.m in Sources */,
86C40DE81A8D7C5C00081FAC /* UIApplication+ResearchKit.m in Sources */,
861D11AA1AA691BB003C98A7 /* ORKScaleSliderView.m in Sources */,
86C40C141A8D7C5C00081FAC /* ORKActiveStepQuantityView.m in Sources */,
86C40C6C1A8D7C5C00081FAC /* CMDeviceMotion+ORKJSONDictionary.m in Sources */,
@@ -2005,18 +2247,21 @@
86C40C201A8D7C5C00081FAC /* ORKAudioStepViewController.m in Sources */,
86C40D081A8D7C5C00081FAC /* ORKCountdownLabel.m in Sources */,
86C40E121A8D7C5C00081FAC /* ORKConsentSceneViewController.m in Sources */,
D442397E1AF17F7600559D96 /* ORKImageCaptureStepViewController.m in Sources */,
86C40CAE1A8D7C5C00081FAC /* ORKRecorder.m in Sources */,
86C40DAC1A8D7C5C00081FAC /* ORKSurveyAnswerCellForNumber.m in Sources */,
86C40C541A8D7C5C00081FAC /* ORKTappingIntervalStep.m in Sources */,
86C40D6C1A8D7C5C00081FAC /* ORKResult.m in Sources */,
86C40CD21A8D7C5C00081FAC /* ORKInstructionStepView.m in Sources */,
86C40D181A8D7C5C00081FAC /* ORKErrors.m in Sources */,
25ECC09C1AFBD8B300F3D63B /* ORKReactionTimeViewController.m in Sources */,
86C40DB01A8D7C5C00081FAC /* ORKSurveyAnswerCellForScale.m in Sources */,
86C40C281A8D7C5C00081FAC /* ORKCountdownStepViewController.m in Sources */,
86C40C641A8D7C5C00081FAC /* CLLocation+ORKJSONDictionary.m in Sources */,
86C40D041A8D7C5C00081FAC /* ORKContinueButton.m in Sources */,
86C40DEC1A8D7C5C00081FAC /* UIBarButtonItem+ORKBarButtonItem.m in Sources */,
86C40CAA1A8D7C5C00081FAC /* ORKPedometerRecorder.m in Sources */,
BCA5C0361AEC05F20092AC8D /* ORKStepNavigationRule.m in Sources */,
86C40D761A8D7C5C00081FAC /* ORKScaleRangeLabel.m in Sources */,
86C40C741A8D7C5C00081FAC /* CMPedometerData+ORKJSONDictionary.m in Sources */,
86AD91151AB7B97E00361FEB /* ORKQuestionStepView.m in Sources */,
@@ -2038,8 +2283,9 @@
86C40C8E1A8D7C5C00081FAC /* ORKActiveStepViewController.m in Sources */,
B183A5011A8535D100C76870 /* (null) in Sources */,
86C40CE61A8D7C5C00081FAC /* ORKAnswerFormat.m in Sources */,
25ECC0961AFBD68300F3D63B /* ORKReactionTimeStep.m in Sources */,
BC13CE3A1B0660220044153C /* ORKNavigableOrderedTask.m in Sources */,
B11C54A11A9EF4A700265E61 /* ORKConsentSharingStepViewController.m in Sources */,
86C40E161A8D7C5C00081FAC /* ORKConsentSection+AssetLoading.m in Sources */,
86C40DA81A8D7C5C00081FAC /* ORKSurveyAnswerCellForImageSelection.m in Sources */,
86C40CCE1A8D7C5C00081FAC /* ORKImageSelectionView.m in Sources */,
86C40D461A8D7C5C00081FAC /* ORKInstructionStepViewController.m in Sources */,
@@ -2050,6 +2296,8 @@
86C40CC61A8D7C5C00081FAC /* ORKCompletionStepViewController.m in Sources */,
86C40D661A8D7C5C00081FAC /* ORKQuestionStepViewController.m in Sources */,
86C40DF41A8D7C5C00081FAC /* ORKConsentReviewController.m in Sources */,
147503BA1AEE807C004B17F3 /* ORKToneAudiometryStep.m in Sources */,
FA7A9D301B083DD3005A2BEA /* ORKConsentSectionFormatter.m in Sources */,
86C40D2A1A8D7C5C00081FAC /* ORKFormTextView.m in Sources */,
86C40DD41A8D7C5C00081FAC /* ORKTextButton.m in Sources */,
86C40C981A8D7C5C00081FAC /* ORKDataLogger.m in Sources */,
@@ -2264,6 +2512,7 @@
PRODUCT_NAME = ResearchKit;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -2290,6 +2539,7 @@
PRODUCT_NAME = ResearchKit;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
+1 -2
View File
@@ -28,8 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Shared header for accessibility functionality.
// Shared header for accessibility functionality.
#import "UIView+ORKAccessibility.h"
#import "ORKAccessibilityFunctions.h"
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKDefines.h"
#import "ORKHelpers.h"
@class ORKScaleSlider;
// Used to properly format values from the ORKScaleSlider.
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
#import "ORKAccessibilityFunctions.h"
#import "ORKAnswerFormat_Internal.h"
@@ -35,6 +36,7 @@
#import "ORKScaleSliderView.h"
#import "UIView+ORKAccessibility.h"
NSString *ORKAccessibilityFormatScaleSliderValue(CGFloat value, ORKScaleSlider *slider) {
ORKScaleSliderView *sliderView = (ORKScaleSliderView *)[slider ork_superviewOfType:[ORKScaleSliderView class]];
if (!slider || !sliderView) {
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (ORKAccessibility)
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "UIView+ORKAccessibility.h"
@implementation UIView (ORKAccessibility)
- (UIView *)ork_superviewOfType:(Class)aClass {
@@ -40,8 +42,7 @@
id superview = [self superview];
if (superview == nil) {
return nil;
}
else if ([superview isKindOfClass:aClass]) {
} else if ([superview isKindOfClass:aClass]) {
return superview;
}
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <CoreLocation/CoreLocation.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface CLLocation (ORKJSONDictionary)
@@ -28,13 +28,14 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "CLLocation+ORKJSONDictionary.h"
#import "ORKHelpers.h"
@implementation CLLocation (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary
{
- (NSDictionary *)ork_JSONDictionary {
CLLocationCoordinate2D coord = self.coordinate;
CLLocationDistance altitude = self.altitude;
CLLocationAccuracy horizAccuracy = self.horizontalAccuracy;
@@ -44,32 +45,27 @@
NSDate *timestamp = self.timestamp;
CLFloor *floor = self.floor;
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:ORKStringFromDateISO8601(timestamp) forKey:@"timestamp"];
NSMutableDictionary *dictionary = [@{@"timestamp" : ORKStringFromDateISO8601(timestamp)} mutableCopy];
if (horizAccuracy >= 0)
{
dict[@"coordinate"] = @{ @"latitude" : [NSDecimalNumber numberWithDouble:coord.latitude], @"longitude" : [NSDecimalNumber numberWithDouble:coord.longitude]};
dict[@"horizontalAccuracy"] = [NSDecimalNumber numberWithDouble:horizAccuracy];
if (horizAccuracy >= 0) {
dictionary[@"coordinate"] = @{ @"latitude" : [NSDecimalNumber numberWithDouble:coord.latitude], @"longitude" : [NSDecimalNumber numberWithDouble:coord.longitude]};
dictionary[@"horizontalAccuracy"] = [NSDecimalNumber numberWithDouble:horizAccuracy];
}
if (vertAccuracy >= 0)
{
dict[@"altitude"] = [NSDecimalNumber numberWithDouble:altitude];
dict[@"verticalAccuracy"] = [NSDecimalNumber numberWithDouble:vertAccuracy];
if (vertAccuracy >= 0) {
dictionary[@"altitude"] = [NSDecimalNumber numberWithDouble:altitude];
dictionary[@"verticalAccuracy"] = [NSDecimalNumber numberWithDouble:vertAccuracy];
}
if (course >= 0)
{
dict[@"course"] = [NSDecimalNumber numberWithDouble:course];
if (course >= 0) {
dictionary[@"course"] = [NSDecimalNumber numberWithDouble:course];
}
if (speed >= 0)
{
dict[@"speed"] = [NSDecimalNumber numberWithDouble:speed];
if (speed >= 0) {
dictionary[@"speed"] = [NSDecimalNumber numberWithDouble:speed];
}
if (floor)
{
dict[@"floor"] = @(floor.level);
if (floor) {
dictionary[@"floor"] = @(floor.level);
}
return dict;
return dictionary;
}
@end
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface CMAccelerometerData (ORKJSONDictionary)
@@ -31,16 +31,16 @@
#import "CMAccelerometerData+ORKJSONDictionary.h"
@implementation CMAccelerometerData (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary
{
NSDictionary *dict = @{@"timestamp": [NSDecimalNumber numberWithDouble:self.timestamp],
@"x" : [NSDecimalNumber numberWithDouble:self.acceleration.x],
@"y" : [NSDecimalNumber numberWithDouble:self.acceleration.y],
@"z" : [NSDecimalNumber numberWithDouble:self.acceleration.z]
};
return dict;
- (NSDictionary *)ork_JSONDictionary {
NSDictionary *dictionary = @{@"timestamp": [NSDecimalNumber numberWithDouble:self.timestamp],
@"x" : [NSDecimalNumber numberWithDouble:self.acceleration.x],
@"y" : [NSDecimalNumber numberWithDouble:self.acceleration.y],
@"z" : [NSDecimalNumber numberWithDouble:self.acceleration.z]
};
return dictionary;
}
@end
@@ -32,6 +32,7 @@
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface CMDeviceMotion (ORKJSONDictionary)
@@ -31,17 +31,17 @@
#import "CMDeviceMotion+ORKJSONDictionary.h"
@implementation CMDeviceMotion (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary
{
- (NSDictionary *)ork_JSONDictionary {
CMQuaternion attitude = self.attitude.quaternion;
CMRotationRate rotationRate = self.rotationRate;
CMAcceleration gravity = self.gravity;
CMAcceleration userAccel = self.userAcceleration;
CMCalibratedMagneticField field = self.magneticField;
NSDictionary *dict = @{@"timestamp": [NSDecimalNumber numberWithDouble:self.timestamp],
NSDictionary *dictionary = @{@"timestamp": [NSDecimalNumber numberWithDouble:self.timestamp],
@"attitude" : @{
@"x" : [NSDecimalNumber numberWithDouble:attitude.x],
@"y" : [NSDecimalNumber numberWithDouble:attitude.y],
@@ -70,7 +70,7 @@
@"accuracy" : [NSDecimalNumber numberWithDouble:field.accuracy]
}
};
return dict;
return dictionary;
}
@end
@@ -32,6 +32,7 @@
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface CMMotionActivity (ORKJSONDictionary)
@@ -32,57 +32,49 @@
#import "CMMotionActivity+ORKJSONDictionary.h"
#import "ORKHelpers.h"
static NSString * const kActivityUnknown = @"unknown";
static NSString * const kActivityStationary = @"stationary";
static NSString * const kActivityWalking = @"walking";
static NSString * const kActivityRunning = @"running";
static NSString * const kActivityAutomotive = @"automotive";
static NSString * const kStartDateKey = @"startDate";
static NSString * const kEndDateKey = @"endDate";
static NSString *stringFromActivityConfidence(CMMotionActivityConfidence confidence)
{
static NSString *const kActivityUnknown = @"unknown";
static NSString *const kActivityStationary = @"stationary";
static NSString *const kActivityWalking = @"walking";
static NSString *const kActivityRunning = @"running";
static NSString *const kActivityAutomotive = @"automotive";
static NSString *const kStartDateKey = @"startDate";
static NSString *const kEndDateKey = @"endDate";
static NSString *stringFromActivityConfidence(CMMotionActivityConfidence confidence) {
NSDictionary *confidences = @{@(CMMotionActivityConfidenceHigh) : @"high",
@(CMMotionActivityConfidenceMedium) : @"medium",
@(CMMotionActivityConfidenceLow) : @"low"};
return confidences[@(confidence)];
}
static NSArray *activityArray(CMMotionActivity *activity)
{
NSMutableArray *ret = [NSMutableArray array];
if (activity.unknown)
{
[ret addObject:kActivityUnknown];
static NSArray *activityArray(CMMotionActivity *activity) {
NSMutableArray *array = [NSMutableArray array];
if (activity.unknown) {
[array addObject:kActivityUnknown];
}
if (activity.stationary)
{
[ret addObject:kActivityStationary];
if (activity.stationary) {
[array addObject:kActivityStationary];
}
if (activity.walking)
{
[ret addObject:kActivityWalking];
if (activity.walking) {
[array addObject:kActivityWalking];
}
if (activity.running)
{
[ret addObject:kActivityRunning];
if (activity.running) {
[array addObject:kActivityRunning];
}
if (activity.automotive)
{
[ret addObject:kActivityAutomotive];
if (activity.automotive) {
[array addObject:kActivityAutomotive];
}
return ret;
return array;
}
static NSString * const kActivityKey = @"activity";
static NSString *const kActivityKey = @"activity";
static NSString * const kConfidenceKey = @"confidence";
static NSString *const kConfidenceKey = @"confidence";
@implementation CMMotionActivity (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary
{
- (NSDictionary *)ork_JSONDictionary {
return @{kConfidenceKey : stringFromActivityConfidence(self.confidence),
kActivityKey : activityArray(self),
kStartDateKey : ORKStringFromDateISO8601(self.startDate)};
@@ -32,13 +32,13 @@
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface CMPedometerData (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary;
@end
NS_ASSUME_NONNULL_END
@@ -33,18 +33,17 @@
#import "ORKHelpers.h"
#import <CoreMotion/CoreMotion.h>
@implementation CMPedometerData (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary
{
NSMutableDictionary *dict = [@{@"startDate": ORKStringFromDateISO8601(self.startDate),
@"endDate": ORKStringFromDateISO8601(self.endDate)
} mutableCopy];
for (NSString *key in @[@"numberOfSteps", @"distance", @"floorsAscended", @"floorsDescended"])
{
[dict setValue:[self valueForKey:key] forKey:key];
- (NSDictionary *)ork_JSONDictionary {
NSMutableDictionary *dictionary = [@{@"startDate": ORKStringFromDateISO8601(self.startDate),
@"endDate": ORKStringFromDateISO8601(self.endDate)
} mutableCopy];
for (NSString *key in @[@"numberOfSteps", @"distance", @"floorsAscended", @"floorsDescended"]) {
[dictionary setValue:[self valueForKey:key] forKey:key];
}
return dict;
return dictionary;
}
@end
@@ -32,6 +32,7 @@
#import <HealthKit/HealthKit.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_OPTIONS(NSInteger, ORKSampleJSONOptions) {
@@ -41,8 +42,7 @@ typedef NS_OPTIONS(NSInteger, ORKSampleJSONOptions) {
};
/**
* JSON serialization aid for HKSample.
*
JSON serialization aid for HKSample.
*/
@interface HKSample (ORKJSONDictionary)
@@ -52,8 +52,7 @@ typedef NS_OPTIONS(NSInteger, ORKSampleJSONOptions) {
/**
* JSON serialization aid for HKCorrelation.
*
JSON serialization aid for HKCorrelation.
*/
@interface HKCorrelation (ORKJSONDictionary)
@@ -32,6 +32,7 @@
#import "HKSample+ORKJSONDictionary.h"
#import "ORKHelpers.h"
static NSString *const kHKSampleIdentifierKey = @"type"; // For compatibility with Health XML export
static NSString *const kHKUUIDKey = @"uuid";
static NSString *const kHKSampleStartDateKey = @"startDate";
@@ -43,108 +44,102 @@ static NSString *const kHKUnitKey = @"unit";
static NSString *const kHKCorrelatedObjectsKey = @"objects";
// static NSString *const kHKSourceIdentifierKey = @"sourceBundleIdentifier";
@interface HKCategorySample (ORKJSONDictionary)
@end
@interface HKQuantitySample (ORKJSONDictionary)
@end
@implementation HKSample (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit
{
NSMutableDictionary *mdict = [NSMutableDictionary dictionaryWithCapacity:12];
- (NSMutableDictionary *)ork_JSONMutableDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:12];
// Type identification
HKSampleType *sampleType = [self sampleType];
mdict[kHKSampleIdentifierKey] = [sampleType identifier];
mutableDictionary[kHKSampleIdentifierKey] = [sampleType identifier];
// consider adding @"class" : NSStringFromClass(sampleType) ?
// Start and end dates
NSDate *startDate = [self startDate];
if (startDate)
{
mdict[kHKSampleStartDateKey] = ORKStringFromDateISO8601(startDate);
if (startDate) {
mutableDictionary[kHKSampleStartDateKey] = ORKStringFromDateISO8601(startDate);
}
NSDate *endDate = [self endDate];
if (endDate)
{
mdict[kHKSampleEndDateKey] = ORKStringFromDateISO8601(endDate);
if (endDate) {
mutableDictionary[kHKSampleEndDateKey] = ORKStringFromDateISO8601(endDate);
}
if (unit)
{
mdict[kHKUnitKey] = [unit unitString];
if (unit) {
mutableDictionary[kHKUnitKey] = [unit unitString];
}
if ((options & ORKSampleIncludeUUID))
{
if ((options & ORKSampleIncludeUUID)) {
NSUUID *uuid = [self UUID];
if (uuid)
{
mdict[kHKUUIDKey] = [uuid UUIDString];
if (uuid) {
mutableDictionary[kHKUUIDKey] = [uuid UUIDString];
}
}
if ( (options & ORKSampleIncludeMetadata) && [self.metadata count] > 0)
{
if ( (options & ORKSampleIncludeMetadata) && [self.metadata count] > 0) {
NSMutableDictionary *metadata = [self.metadata mutableCopy];
for (NSString *k in metadata)
{
for (NSString *k in metadata) {
id obj = metadata[k];
if ([obj isKindOfClass:[NSDate class]])
{
if ([obj isKindOfClass:[NSDate class]]) {
metadata[k] = ORKStringFromDateISO8601(obj);
}
}
mdict[kHKMetadataKey] = metadata;
mutableDictionary[kHKMetadataKey] = metadata;
}
if (options & ORKSampleIncludeSource)
{
if (options & ORKSampleIncludeSource) {
HKSource *source = [self source];
if (source.name)
{
mdict[kHKSourceKey] = source.name;
if (source.name) {
mutableDictionary[kHKSourceKey] = source.name;
}
}
return mdict;
return mutableDictionary;
}
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
return [self ork_JSONMutableDictionaryWithOptions:options unit:unit];
}
@end
@interface HKCategorySample (ORKJSONDictionary)
@end
@implementation HKCategorySample (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit
{
NSMutableDictionary *dict = [[super ork_JSONDictionaryWithOptions:options unit:unit] mutableCopy];
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
NSMutableDictionary *dictionary = [self ork_JSONMutableDictionaryWithOptions:options unit:unit];
NSInteger value = [self value];
dict[kHKSampleValue] = @(value);
dictionary[kHKSampleValue] = @(value);
return dict;
return dictionary;
}
@end
@interface HKQuantitySample (ORKJSONDictionary)
@end
@implementation HKQuantitySample (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit
{
NSMutableDictionary *dict = [[super ork_JSONDictionaryWithOptions:options unit:unit] mutableCopy];
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
NSMutableDictionary *dictionary = [self ork_JSONMutableDictionaryWithOptions:options unit:unit];
HKQuantity *quantity = [self quantity];
double value = [quantity doubleValueForUnit:unit];
dict[kHKSampleValue] = @(value);
dictionary[kHKSampleValue] = @(value);
return dict;
return dictionary;
}
@end
@@ -152,29 +147,22 @@ static NSString *const kHKCorrelatedObjectsKey = @"objects";
@implementation HKCorrelation (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options sampleTypes:(NSArray *)sampleTypes units:(NSArray *)units
{
NSMutableDictionary *mdict = (NSMutableDictionary *)[self ork_JSONDictionaryWithOptions:options unit:nil];
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options sampleTypes:(NSArray *)sampleTypes units:(NSArray *)units {
NSMutableDictionary *mutableDictionary = [self ork_JSONMutableDictionaryWithOptions:options unit:nil];
// The correlated objects
NSMutableArray *correlatedObjects = [NSMutableArray arrayWithCapacity:[sampleTypes count]];
for (HKSample *sample in self.objects)
{
for (HKSample *sample in self.objects) {
NSUInteger idx = [sampleTypes indexOfObject:sample.sampleType];
if (idx == NSNotFound)
{
if (idx == NSNotFound) {
continue;
}
[correlatedObjects addObject:[sample ork_JSONDictionaryWithOptions:options unit:units[idx]]];
}
mdict[kHKCorrelatedObjectsKey] = correlatedObjects;
mutableDictionary[kHKCorrelatedObjectsKey] = correlatedObjects;
return mdict;
return mutableDictionary;
}
@end
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
/**
@@ -49,16 +51,18 @@ ORK_CLASS_AVAILABLE
/**
Returns an initialized accelerometer recorder using the specified frequency.
@param frequency The frequency of accelerometer data collected from CoreMotion, in hertz (Hz).
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param frequency The frequency of accelerometer data collected from CoreMotion, in hertz (Hz).
@param step The step that requested this recorder.
@param outputDirectory The directory in which the accelerometer data should be stored.
@return An initialized accelerometer recorder.
*/
- (instancetype)initWithFrequency:(double)frequency
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory;
- (instancetype)initWithIdentifier:(NSString *)identifer
frequency:(double)frequency
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory;
@end
NS_ASSUME_NONNULL_END
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKAccelerometerRecorder.h"
#import "ORKDataLogger.h"
#import "CMAccelerometerData+ORKJSONDictionary.h"
@@ -37,36 +38,34 @@
#import "ORKHelpers.h"
@interface ORKAccelerometerRecorder()
{
@interface ORKAccelerometerRecorder () {
ORKDataLogger *_logger;
NSError *_recordingError;
}
@property (nonatomic, strong) CMMotionManager *motionManager;
@property (nonatomic) NSTimeInterval uptime;
@end
@implementation ORKAccelerometerRecorder
- (instancetype)initWithFrequency:(double)frequency step:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory
{
self = [super initWithStep:step outputDirectory:outputDirectory];
if (self)
{
- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)frequency step:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier step:step outputDirectory:outputDirectory];
if (self) {
self.frequency = frequency;
self.continuesInBackground = YES;
}
return self;
}
- (void)dealloc
{
- (void)dealloc {
[_logger finishCurrentLog];
}
- (NSString *)recorderType
{
- (NSString *)recorderType {
return @"accel";
}
@@ -83,8 +82,8 @@
}
- (void)start {
[super start];
self.motionManager = [self createMotionManager];
if (! _logger) {
@@ -96,8 +95,7 @@
}
}
if (! self.motionManager || ! self.motionManager.accelerometerAvailable)
{
if (! self.motionManager || ! self.motionManager.accelerometerAvailable) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}];
@@ -131,7 +129,7 @@
}
- (NSDictionary *)userInfo {
return @{ @"frequency" : @(self.frequency) };;
return @{ @"frequency" : @(self.frequency) };
}
- (void)stop {
@@ -150,28 +148,24 @@
[super stop];
}
- (void)doStopRecording
{
- (void)doStopRecording {
if (self.isRecording) {
[self.motionManager stopAccelerometerUpdates];
self.motionManager = nil;
}
}
- (void)finishRecordingWithError:(NSError *)error
{
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:nil];
}
- (void)reset
{
- (void)reset {
[super reset];
_logger = nil;
}
- (BOOL)isRecording {
return self.motionManager.accelerometerActive;
}
@@ -180,67 +174,65 @@
return @"application/json";
}
@end
@interface ORKAccelerometerRecorderConfiguration()
@interface ORKAccelerometerRecorderConfiguration ()
@end
@implementation ORKAccelerometerRecorderConfiguration
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
- (instancetype)initWithFrequency:(double)freq {
self = [self ork_init];
- (instancetype)initWithIdentifier:(NSString *)identifier {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use subclass designated initializer" userInfo:nil];
}
- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)frequency {
self = [super initWithIdentifier:identifier];
if (self) {
_frequency = freq;
_frequency = frequency;
}
return self;
}
#pragma clang diagnostic pop
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory
{
return [[ORKAccelerometerRecorder alloc] initWithFrequency:self.frequency step:step outputDirectory:outputDirectory];
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKAccelerometerRecorder alloc] initWithIdentifier:self.identifier
frequency:self.frequency
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self)
{
if (self) {
ORK_DECODE_DOUBLE(aDecoder, frequency);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_DOUBLE(aCoder, frequency);
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
(self.frequency == castObject.frequency)) ;
(self.frequency == castObject.frequency));
}
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionCoreMotionAccelerometer;
}
@end
+1 -16
View File
@@ -33,6 +33,7 @@
#import <ResearchKit/ORKStep.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/**
@@ -100,7 +101,6 @@ automatically navigates forward when the timer expires.
*/
@property (nonatomic) BOOL shouldSpeakCountDown;
/**
A Boolean value indicating whether to start the count down timer automatically when the step starts, or
require the user to take some explicit action to start the step, such as tapping a button.
@@ -193,7 +193,6 @@ The default value of this property is `NO`.
*/
@property (nonatomic, copy, nullable) NSArray *recorderConfigurations;
/**
The set of HealthKit types the step requests for reading. (read-only)
@@ -206,20 +205,6 @@ The default value of this property is `NO`.
*/
@property (nonatomic, readonly, nullable) NSSet *requestedHealthKitTypesForReading;
/**
The set of access permissions required for the step. (read-only)
The permission mask is used by the task view controller to determine the types of
access to request from users when they complete the initial instruction steps
in a task. If your step requires access to APIs that limit access, include
the permissions you require in this mask.
By default, the property scans the recorders and collates the permissions
required by the recorders. Subclasses may override this implementation.
*/
@property (nonatomic, readonly) ORKPermissionMask requestedPermissions;
@end
NS_ASSUME_NONNULL_END
+12 -26
View File
@@ -36,10 +36,10 @@
#import "ORKActiveStepViewController.h"
#import "ORKRecorder_Private.h"
@implementation ORKActiveStep
+ (Class)stepViewControllerClass
{
+ (Class)stepViewControllerClass {
return [ORKActiveStepViewController class];
}
@@ -53,25 +53,23 @@
- (BOOL)hasTitle {
NSString *title = self.title;
return ( title != nil && title.length > 0);
return (title != nil && title.length > 0);
}
- (BOOL)hasText {
NSString *text = self.text;
return ( text != nil && text.length > 0);
return (text != nil && text.length > 0);
}
- (BOOL)hasVoice {
return ( _spokenInstruction != nil && _spokenInstruction.length > 0);
return (_spokenInstruction != nil && _spokenInstruction.length > 0);
}
- (BOOL)isRestorable {
return NO;
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
@@ -83,8 +81,7 @@
return self;
}
- (instancetype)copyWithZone:(NSZone *)zone
{
- (instancetype)copyWithZone:(NSZone *)zone {
ORKActiveStep *step = [super copyWithZone:zone];
step.stepDuration = self.stepDuration;
step.shouldStartTimerAutomatically = self.shouldStartTimerAutomatically;
@@ -102,12 +99,9 @@
return step;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self)
{
if (self ) {
ORK_DECODE_DOUBLE(aDecoder, stepDuration);
ORK_DECODE_BOOL(aDecoder, shouldStartTimerAutomatically);
ORK_DECODE_BOOL(aDecoder, shouldSpeakCountDown);
@@ -125,8 +119,7 @@
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_DOUBLE(aCoder, stepDuration);
ORK_ENCODE_BOOL(aCoder, shouldStartTimerAutomatically);
@@ -143,8 +136,6 @@
ORK_ENCODE_OBJ(aCoder, recorderConfigurations);
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
@@ -162,13 +153,9 @@
(self.shouldVibrateOnStart == castObject.shouldVibrateOnStart) &&
(self.shouldVibrateOnFinish == castObject.shouldVibrateOnFinish) &&
(self.shouldContinueOnFinish == castObject.shouldContinueOnFinish) &&
(self.shouldUseNextAsSkipButton == castObject.shouldUseNextAsSkipButton)) ;
(self.shouldUseNextAsSkipButton == castObject.shouldUseNextAsSkipButton));
}
- (NSSet *)requestedHealthKitTypesForReading {
NSMutableSet *set = [NSMutableSet set];
for (ORKRecorderConfiguration *config in self.recorderConfigurations) {
@@ -178,11 +165,10 @@
}
}
return set;
}
- (ORKPermissionMask)requestedPermissions {
ORKPermissionMask mask = ORKPermissionNone;
ORKPermissionMask mask = [super requestedPermissions];
for (ORKRecorderConfiguration *config in self.recorderConfigurations) {
mask |= [config requestedPermissionMask];
}
@@ -28,15 +28,18 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit_Private.h>
#import "ORKLabel.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKQuantityLabel : ORKLabel
@end
@interface ORKActiveStepQuantityView : UIView
@property (nonatomic, strong, nullable) NSString *title;
@@ -44,13 +47,12 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, nullable) UIImage *image;
@property (nonatomic) BOOL enabled;
@property (nonatomic, readonly, strong, nullable) UILabel *titleLabel;
@property (nonatomic, readonly, strong, nullable) UILabel *valueLabel;
@property (nonatomic, strong, readonly, nullable) UILabel *titleLabel;
@property (nonatomic, strong, readonly, nullable) UILabel *valueLabel;
@end
@interface ORKQuantityPairView : UIView
@property (nonatomic, strong, nullable) ORKActiveStepQuantityView *leftView;
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKActiveStepQuantityView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
@@ -44,12 +45,13 @@
@end
@implementation ORKActiveStepQuantityView
{
@implementation ORKActiveStepQuantityView {
ORKSubheadlineLabel *_titleLabel;
ORKQuantityLabel *_valueLabel;
ORKTintedImageView *_imageView;
UIView *_valueHolder;
NSLayoutConstraint *_zeroWidthConstraint;
}
- (instancetype)initWithFrame:(CGRect)frame {
@@ -82,8 +84,8 @@
view.isAccessibilityElement = NO;
}
[self setupConstraints];
[self setNeedsUpdateConstraints];
}
return self;
}
@@ -109,69 +111,95 @@
_imageView.image = image;
}
- (void)updateConstraints {
[self removeConstraints:[self constraints]];
- (void)setupConstraints {
const CGFloat TitleBaselineToValueBaseline = 40;
const CGFloat ValueBaselineToBottom = 36;
if (! _enabled) {
NSLayoutConstraint *zeroWidthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0];
zeroWidthConstraint.priority = UILayoutPriorityRequired-1;
[self addConstraint:zeroWidthConstraint];
}
NSDictionary *views = NSDictionaryOfVariableBindings(_titleLabel, _valueLabel, _imageView);
NSMutableArray *additionalConstraints = [NSMutableArray array];
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_titleLabel]" options:0 metrics:nil views:views]];
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_titleLabel]|" options:0 metrics:nil views:views]];
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imageView]-10-[_valueLabel]|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:views]];
NSDictionary *views = NSDictionaryOfVariableBindings(_titleLabel, _valueLabel, _imageView);
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_titleLabel]"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_titleLabel]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imageView]-10-[_valueLabel]|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:views]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_titleLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1 constant:TitleBaselineToValueBaseline]];
multiplier:1.0
constant:TitleBaselineToValueBaseline]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_valueLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1 constant:ValueBaselineToBottom]];
multiplier:1.0
constant:ValueBaselineToBottom]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1 constant:0]];
multiplier:1.0
constant:0.0]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:_valueHolder
attribute:NSLayoutAttributeTop
multiplier:1 constant:0]];
multiplier:1.0
constant:0.0]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:_valueHolder
attribute:NSLayoutAttributeBottom
multiplier:1 constant:0]];
multiplier:1.0
constant:0.0]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1 constant:0]];
multiplier:1.0
constant:0.0]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeRight
multiplier:1 constant:0]];
multiplier:1.0
constant:0.0]];
for (NSLayoutConstraint *constraint in additionalConstraints) {
constraint.priority = UILayoutPriorityDefaultHigh;
constraint.priority = UILayoutPriorityRequired-2;
}
[self addConstraints:additionalConstraints];
[NSLayoutConstraint activateConstraints:additionalConstraints];
NSLayoutConstraint *zeroWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
zeroWidthConstraint.priority = UILayoutPriorityRequired-1;
_zeroWidthConstraint = zeroWidthConstraint;
_zeroWidthConstraint.active = !_enabled;
}
- (void)updateConstraints {
_zeroWidthConstraint.active = !_enabled;
[super updateConstraints];
}
@@ -195,10 +223,9 @@
@end
@implementation ORKQuantityPairView
{
@implementation ORKQuantityPairView {
UIView *_metricKeyline;
NSArray *_constraints;
}
- (instancetype)initWithFrame:(CGRect)frame {
@@ -215,59 +242,88 @@
[self setKeylineHidden:NO];
_metricKeyline.backgroundColor = [UIColor ork_midGrayTintColor];
[self addSubview:_leftView];
[self addSubview:_rightView];
[self addSubview:_metricKeyline];
[self setNeedsUpdateConstraints];
[self setupConstraints];
}
return self;
}
- (void)updateConstraints {
- (void)setupConstraints {
if (_constraints) {
[self removeConstraints:_constraints];
_constraints = nil;
}
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_leftView, _rightView, _metricKeyline);
// Leave space for the keyline between these views, and then constrain it to be 1px wide and go from top to bottom baseline of metric views.
CGFloat scale = [[UIScreen mainScreen] scale];
NSArray *vertConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_leftView]|" options:(NSLayoutFormatOptions)0 metrics:nil views:views];
NSArray *vertConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_leftView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views];
[constraints addObjectsFromArray:vertConstraints];
NSArray *horizConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_leftView]-s-[_rightView]-|" options:NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom|NSLayoutFormatDirectionLeftToRight metrics:@{@"s":@(1/scale)} views:views];
NSArray *horizConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_leftView]-s-[_rightView]-|"
options:NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom|NSLayoutFormatDirectionLeftToRight
metrics:@{ @"s": @(1/scale) }
views:views];
for (NSLayoutConstraint *constraint in horizConstraints) {
constraint.priority = UILayoutPriorityDefaultHigh+1;
}
[constraints addObjectsFromArray:horizConstraints];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_leftView][_metricKeyline(==s)]" options:NSLayoutFormatAlignAllTop|NSLayoutFormatDirectionLeftToRight metrics:@{@"s":@(1/scale)} views:views]];
// Ensure baseline alignment of title and value
[constraints addObject:[NSLayoutConstraint constraintWithItem:_leftView.titleLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_rightView.titleLabel
attribute:NSLayoutAttributeFirstBaseline
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_leftView.valueLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_rightView.valueLabel
attribute:NSLayoutAttributeFirstBaseline
multiplier:1.0
constant:0.0]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_leftView][_metricKeyline(==s)]"
options:NSLayoutFormatAlignAllTop|NSLayoutFormatDirectionLeftToRight
metrics:@{ @"s": @(1/scale) }
views:views]];
NSLayoutConstraint *keylineBottom = [NSLayoutConstraint constraintWithItem:_metricKeyline
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_leftView.valueLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1 constant:0];
multiplier:1.0
constant:0.0];
[constraints addObject:keylineBottom];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:10000];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
maxWidthConstraint.priority = UILayoutPriorityRequired-2;
[constraints addObject:maxWidthConstraint];
// This constraint should be beaten out by the full-width-coverage and zero-width constraints if only one of the views is enabled.
NSLayoutConstraint *equalWidthConstraint = [NSLayoutConstraint constraintWithItem:_leftView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_rightView attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
NSLayoutConstraint *equalWidthConstraint = [NSLayoutConstraint constraintWithItem:_leftView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:_rightView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0];
equalWidthConstraint.priority = UILayoutPriorityDefaultLow;
[constraints addObject:equalWidthConstraint];
[self addConstraints:constraints];
_constraints = constraints;
[super updateConstraints];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)setKeylineHidden:(BOOL)keylineHidden {
@@ -276,4 +332,3 @@
}
@end
+2 -1
View File
@@ -28,16 +28,17 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <Foundation/Foundation.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKActiveStepTimer;
typedef void (^ORKActiveStepTimerHandler)(ORKActiveStepTimer *timer, BOOL finished);
@interface ORKActiveStepTimer : NSObject
- (instancetype)initWithDuration:(NSTimeInterval)duration interval:(NSTimeInterval)interval runtime:(NSTimeInterval)runtime handler:(ORKActiveStepTimerHandler)handler;
+6 -10
View File
@@ -28,24 +28,23 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKActiveStepTimer.h"
#include <mach/mach.h>
#include <mach/mach_time.h>
#import <UIKit/UIKit.h>
static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
static mach_timebase_info_data_t sTimebaseInfo;
if ( sTimebaseInfo.denom == 0 ) {
(void) mach_timebase_info(&sTimebaseInfo);
}
uint64_t elapsedNano = delta * sTimebaseInfo.numer / sTimebaseInfo.denom;
return elapsedNano * 1.0 / NSEC_PER_SEC;
}
@implementation ORKActiveStepTimer
{
@implementation ORKActiveStepTimer {
uint64_t _startTime;
NSTimeInterval _preExistingRuntime;
dispatch_queue_t _queue;
@@ -54,7 +53,6 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
uint32_t _isRunning;
}
- (instancetype)initWithDuration:(NSTimeInterval)duration interval:(NSTimeInterval)interval runtime:(NSTimeInterval)runtime handler:(ORKActiveStepTimerHandler)handler {
self = [super init];
if (self) {
@@ -158,10 +156,10 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
return;
}
UIBackgroundTaskIdentifier ident = _backgroundTaskIdentifier;
UIBackgroundTaskIdentifier identifier = _backgroundTaskIdentifier;
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] endBackgroundTask:ident];
[[UIApplication sharedApplication] endBackgroundTask:identifier];
});
}
@@ -178,7 +176,6 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
}
- (void)queue_resume {
if (_timer != NULL) {
// Already resumed
return;
@@ -211,7 +208,7 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
_startTime = mach_absolute_time();
dispatch_source_set_timer(_timer,
dispatch_time(DISPATCH_TIME_NOW, timeUntilNextFire * NSEC_PER_SEC),
_interval * NSEC_PER_SEC ,
_interval * NSEC_PER_SEC,
0.05 * NSEC_PER_SEC);
dispatch_resume(_timer);
}
@@ -239,5 +236,4 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
[self queue_releaseBackgroundTask];
}
@end
@@ -28,13 +28,14 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
#import <UIKit/UIKit.h>
#import <ResearchKit/ResearchKit_Private.h>
#import "ORKCustomStepView_Internal.h"
#import "ORKCountdownLabel.h"
#import "ORKTextButton.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKActiveStepTimerView : ORKActiveStepCustomView
@@ -46,4 +47,4 @@ NS_ASSUME_NONNULL_BEGIN
@end
NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_END
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKActiveStepTimerView.h"
#import "ORKActiveStepTimer.h"
#import "ORKHelpers.h"
@@ -41,18 +42,14 @@
#import "ORKStepViewController_Internal.h"
@implementation ORKActiveStepTimerView
{
@implementation ORKActiveStepTimerView {
BOOL _started;
BOOL _registeredForNotifications;
}
- (instancetype)initWithFrame:(CGRect)frame
{
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self)
{
if (self) {
// Count Down
{
_countDownLabel = [ORKCountdownLabel new];
@@ -61,10 +58,8 @@
[self addSubview:_countDownLabel];
}
// Count down start button
{
_startTimerButton = [ORKTextButton new];
[_startTimerButton setTitle:ORKLocalizedString(@"BUTTON_START_TIMER", nil) forState:UIControlStateNormal];
[_startTimerButton addTarget:self action:@selector(startTimerButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
@@ -76,16 +71,14 @@
_countDownLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
}
return self;
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
ORKActiveStepViewController *vc = self.activeStepViewController;
if (vc) {
[self updateDisplay:vc];
ORKActiveStepViewController *viewController = self.activeStepViewController;
if (viewController) {
[self updateDisplay:viewController];
}
}
@@ -93,7 +86,7 @@
if (registered == _registeredForNotifications) {
return;
}
registered = _registeredForNotifications;
NSNotificationCenter *nfc = [NSNotificationCenter defaultCenter];
if (registered) {
@@ -107,9 +100,7 @@
[self setRegisteredForNotifications:(self.window != nil)];
}
- (void)setStep:(ORKActiveStep *)step
{
- (void)setStep:(ORKActiveStep *)step {
_step = step;
_countDownLabel.hidden = !(_step.hasCountDown);
BOOL hasTimerButton = (_step.hasCountDown && _step.shouldStartTimerAutomatically == NO);
@@ -121,19 +112,16 @@
[self setNeedsUpdateConstraints];
}
- (void)startTimerButtonTapped:(id)sender
{
- (void)startTimerButtonTapped:(id)sender {
[self.activeStepViewController start];
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, _countDownLabel);
}
- (void)updateDisplay:(ORKActiveStepViewController *)viewController {
NSInteger countDownValue = (NSInteger)round(viewController.timeRemaining);
[_countDownLabel setCountDownValue:countDownValue];
}
- (void)resetStep:(ORKActiveStepViewController *)viewController {
self.step = (ORKActiveStep *)viewController.step;
}
@@ -147,8 +135,7 @@
- (void)resumeStep:(ORKActiveStepViewController *)viewController {
self.step = (ORKActiveStep *)viewController.step;
if ([viewController timerActive])
{
if ([viewController timerActive]) {
_startTimerButton.alpha = 0;
[self updateDisplay:viewController];
}
@@ -157,44 +144,57 @@
- (void)finishStep:(ORKActiveStepViewController *)viewController {
}
- (void)setNeedsUpdateConstraints
{
- (void)setNeedsUpdateConstraints {
[NSLayoutConstraint deactivateConstraints:[self constraints]];
[super setNeedsUpdateConstraints];
}
- (void)updateConstraints
{
- (void)updateConstraints {
NSDictionary *dictionary = NSDictionaryOfVariableBindings(_countDownLabel, _startTimerButton);
NSDictionary *metrics = @{@"CS" : @(2)};
ORKEnableAutoLayoutForViews([dictionary allValues]);
for (UIView *v in [dictionary allValues])
{
[self addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
for (UIView *view in [dictionary allValues]) {
[self addConstraint:[NSLayoutConstraint
constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
[self addConstraint:[NSLayoutConstraint
constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
}
if (! _countDownLabel.hidden)
{
if (! _countDownLabel.hidden) {
NSMutableString *verticalLayout = [NSMutableString new];
[verticalLayout appendString:@"V:|[_countDownLabel]"];
if (! _startTimerButton.hidden)
{
if (! _startTimerButton.hidden) {
[verticalLayout appendString:@"-CS-[_startTimerButton]"];
}
[verticalLayout appendString:@"|"];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalLayout options:NSLayoutFormatAlignAllCenterX metrics:metrics views:dictionary]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalLayout
options:NSLayoutFormatAlignAllCenterX
metrics:metrics
views:dictionary]];
} else {
[self addConstraint:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:0]];
}
else
{
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0]];
}
[super updateConstraints];
}
@end
@@ -35,7 +35,6 @@
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKActiveStepViewController` class is the base class for displaying `ORKActiveStep`
subclasses. The predefined active tasks defined in `ORKOrderedTask` all make use
@@ -105,10 +104,8 @@ ORK_CLASS_AVAILABLE
*/
@property (nonatomic, strong, readonly, nullable) NSArray *recorders;
/// @name Active step life cycle
/**
A Boolean value that indicates whether the step has finished. (read-only)
@@ -118,8 +115,7 @@ ORK_CLASS_AVAILABLE
In addition, when a step is finished, all recorders are stopped.
*/
@property (nonatomic, assign, getter=isFinished, readonly) BOOL finished;
@property (nonatomic, assign, readonly, getter=isFinished) BOOL finished;
/**
A Boolean value that indicates whether the step has started. (read-only)
@@ -140,7 +136,6 @@ ORK_CLASS_AVAILABLE
*/
- (void)stepDidFinish;
/**
A Boolean value that indicates whether to suspend the step if the app is not
active or the screen is off.
@@ -48,7 +48,8 @@
#import "ORKStepHeaderView_Internal.h"
#import "ORKActiveStepView.h"
@interface ORKActiveStepViewController (){
@interface ORKActiveStepViewController () {
ORKActiveStepView *_activeStepView;
ORKActiveStepTimer *_activeStepTimer;
@@ -76,10 +77,8 @@
_timerUpdateInterval = 1;
}
return self;
}
- (void)applicationWillResignActive:(NSNotification *)notification {
if (self.suspendIfInactive) {
[self suspend];
@@ -100,8 +99,7 @@
return _activeStepView;
}
- (void)viewDidLoad
{
- (void)viewDidLoad {
[super viewDidLoad];
_activeStepView = [[ORKActiveStepView alloc] initWithFrame:self.view.bounds];
@@ -119,8 +117,8 @@
[self prepareStep];
}
- (void)stepDidChange
{
- (void)stepDidChange {
[super stepDidChange];
_activeStepView.activeStep = [self activeStep];
[self updateContinueButtonItem];
@@ -129,20 +127,17 @@
[self prepareStep];
}
- (UIView *)customViewContainer
{
__unused UIView *v = [self view];
- (UIView *)customViewContainer {
__unused UIView *view = [self view];
return _activeStepView.customViewContainer;
}
- (UIImageView *)imageView
{
__unused UIView *v = [self view];
- (ORKTintedImageView *)imageView {
__unused UIView *view = [self view];
return _activeStepView.imageView;
}
- (void)setCustomView:(UIView *)customView
{
- (void)setCustomView:(UIView *)customView {
_customView = customView;
[_activeStepView setStepView:_customView];
}
@@ -154,21 +149,16 @@
[self.taskViewController setRegisteredScrollView:_activeStepView];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
ORK_Log_Debug(@"%@",self);
// Wait for animation complete
dispatch_async(dispatch_get_main_queue(), ^{
if ([[self activeStep] shouldStartTimerAutomatically])
{
if ([[self activeStep] shouldStartTimerAutomatically]) {
[self start];
}
});
}
- (void)viewWillDisappear:(BOOL)animated {
@@ -187,22 +177,18 @@
[self updateContinueButtonItem];
}
- (void)setLearnMoreButtonItem:(UIBarButtonItem *)learnMoreButtonItem
{
- (void)setLearnMoreButtonItem:(UIBarButtonItem *)learnMoreButtonItem {
[super setLearnMoreButtonItem:learnMoreButtonItem];
_activeStepView.headerView.learnMoreButtonItem = self.learnMoreButtonItem;
}
- (void)setSkipButtonItem:(UIBarButtonItem *)skipButtonItem
{
- (void)setSkipButtonItem:(UIBarButtonItem *)skipButtonItem {
[super setSkipButtonItem:skipButtonItem];
_activeStepView.continueSkipContainer.skipButtonItem = skipButtonItem;
}
- (void)setFinished:(BOOL)finished
{
- (void)setFinished:(BOOL)finished {
_finished = finished;
_activeStepView.continueSkipContainer.continueEnabled = finished;
}
@@ -215,28 +201,21 @@
#pragma mark - transition
- (void)recordersDidChange {
}
- (void)recordersWillStart {
}
- (void)recordersWillStop {
}
- (void)prepareRecorders
{
- (void)prepareRecorders {
// Stop any existing recorders
[self recordersWillStop];
for (ORKRecorder *recorder in self.recorders)
{
for (ORKRecorder *recorder in self.recorders) {
recorder.delegate = nil;
[recorder stop];
}
NSMutableArray *recorders = [NSMutableArray array];
for (ORKRecorderConfiguration * provider in self.activeStep.recorderConfigurations) {
@@ -249,7 +228,6 @@
[recorders addObject:recorder];
}
self.recorders = recorders;
[self recordersDidChange];
@@ -261,8 +239,7 @@
}
- (void)prepareStep {
if (self.activeStep==nil) {
if (self.activeStep == nil) {
return;
}
@@ -271,13 +248,10 @@
ORK_Log_Debug(@"%@", self);
_activeStepView.activeStep = self.activeStep;
if ([self.activeStep hasCountDown])
{
if ([self.activeStep hasCountDown]) {
ORKActiveStepTimerView *timerView = [ORKActiveStepTimerView new];
_activeStepView.activeCustomView = timerView;
}
else
{
} else {
_activeStepView.activeCustomView = nil;
}
_activeStepView.activeCustomView.activeStepViewController = self;
@@ -291,7 +265,6 @@
[self recordersWillStart];
// Start recorders
for (ORKRecorder *recorder in self.recorders) {
[recorder viewController:self willStartStepWithView:self.customViewContainer];
[recorder start];
}
@@ -304,8 +277,7 @@
}
}
- (void)playSound
{
- (void)playSound {
if (_alertSoundURL == nil) {
_alertSoundURL = [NSURL URLWithString:@"/System/Library/Audio/UISounds/short_low_high.caf"];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)(_alertSoundURL), &_alertSound);
@@ -321,14 +293,11 @@
[self startRecorders];
if (self.activeStep.shouldVibrateOnStart) {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
}
if (self.activeStep.shouldPlaySoundOnStart) {
[self playSound];
}
@@ -337,7 +306,7 @@
// Let VO speak "Step x of y" before the instruction.
// If VO is not running, the text is spoken immediately.
ORKAccessibilityPerformBlockAfterDelay(1.5, ^{
[[ORKVoiceEngine sharedVoiceEngine] speakText:(NSString *__nonnull)self.activeStep.spokenInstruction];
[[ORKVoiceEngine sharedVoiceEngine] speakText:self.activeStep.spokenInstruction];
});
}
}
@@ -366,7 +335,6 @@
[_activeStepView.activeCustomView resumeStep:self];
}
- (void)finish {
ORK_Log_Debug(@"%@",self);
if (self.finished) {
@@ -405,14 +373,12 @@
_activeStepTimer = nil;
}
- (void)startTimer
{
- (void)startTimer {
[self resetTimer];
NSTimeInterval stepDuration = self.activeStep.stepDuration;
if (stepDuration > 0) {
__weak typeof(self) weakSelf = self;
_activeStepTimer = [[ORKActiveStepTimer alloc] initWithDuration:stepDuration
interval:_timerUpdateInterval
@@ -426,7 +392,6 @@
}
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished {
if (finished) {
[self finish];
}
@@ -462,14 +427,12 @@
#pragma mark - action handlers
- (void)stepDidFinish
{
- (void)stepDidFinish {
}
#pragma mark - ORKRecorderDelegate
- (void)recorder:(ORKRecorder *)recorder didCompleteWithResult:(ORKResult *)result {
_recorderResults = [_recorderResults arrayByAddingObject:result];
[self notifyDelegateOnResultChange];
}
@@ -492,25 +455,21 @@
}
}
static NSString *const _ORKFinishedRestoreKey = @"finished";
static NSString *const _ORKRecorderResultsRestoreKey = @"recorderResults";
static NSString * const _ORKFinishedRestoreKey = @"finished";
static NSString * const _ORKRecorderResultsRestoreKey = @"recorderResults";
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
[super encodeRestorableStateWithCoder:coder];
[coder encodeBool:_finished forKey:_ORKFinishedRestoreKey];
[coder encodeObject:_recorderResults forKey:_ORKRecorderResultsRestoreKey];
}
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
[super decodeRestorableStateWithCoder:coder];
self.finished = [coder decodeBoolForKey:_ORKFinishedRestoreKey];
_recorderResults = [coder decodeObjectOfClass:[NSArray class] forKey:_ORKRecorderResultsRestoreKey];
}
@end
@@ -29,20 +29,20 @@
*/
#import "ORKActiveStepViewController.h"
#import "ORKActiveStepTimer.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKActiveStepView;
@interface ORKActiveStepViewController ()
/**
* The customViewContainer allows custom view to be its subview.
* @note When ORKTouchRecorder is present, its gesture recognizer attaches to customViewContainer.
The customViewContainer allows custom view to be its subview.
@note When ORKTouchRecorder is present, its gesture recognizer attaches to customViewContainer.
*/
@property (nonatomic, strong, readonly, nullable) UIView *customViewContainer;
@@ -50,10 +50,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) NSTimeInterval timeRemaining;
@property (nonatomic, readonly) BOOL timerActive;
@property (nonatomic, assign) NSTimeInterval timerUpdateInterval;
@property (nonatomic, assign, getter=isStarted) BOOL started;
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished; // Let subclass receive timer fires
@@ -61,6 +59,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)applicationWillResignActive:(NSNotification *)notification;
- (void)applicationDidBecomeActive:(NSNotification *)notification;
- (void)stopRecorders;
@end
@@ -28,12 +28,14 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKActiveStep.h>
@interface ORKActiveStep ()
/**
* Convenience methods.
Convenience methods.
*/
- (BOOL)startsFinished;
- (BOOL)hasCountDown;
@@ -41,5 +43,4 @@
- (BOOL)hasText;
- (BOOL)hasVoice;
@end
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKAudioContentView : ORKActiveStepCustomView
@@ -38,6 +40,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, copy, nullable) UIColor *keyColor;
@property (nonatomic, copy, nullable) UIColor *alertColor;
@property (nonatomic, assign) BOOL failed;
@property (nonatomic, assign, getter=isFinished) BOOL finished;
@property (nonatomic, assign) NSTimeInterval timeLeft;
+80 -55
View File
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKAudioContentView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
@@ -35,6 +36,7 @@
#import "ORKHeadlineLabel.h"
#import "ORKAccessibility.h"
// The central blue region.
static const CGFloat GraphViewBlueZoneHeight = 170;
@@ -53,6 +55,7 @@ static const CGFloat GraphViewRedZoneHeight = 25;
@end
static const CGFloat kValueLineWidth = 4.5;
static const CGFloat kValueLineMargin = 1.5;
@@ -61,17 +64,23 @@ static const CGFloat kValueLineMargin = 1.5;
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
NSLayoutConstraint *c1 = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:CGFLOAT_MAX];
c1.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *c2 = [NSLayoutConstraint constraintWithItem:self
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:CGFLOAT_MAX];
constraint1.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:CGFLOAT_MAX];
c2.priority = UILayoutPriorityFittingSizeLevel;
[NSLayoutConstraint activateConstraints:@[c1,c2]];
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:CGFLOAT_MAX];
constraint2.priority = UILayoutPriorityFittingSizeLevel;
[NSLayoutConstraint activateConstraints:@[constraint1, constraint2]];
#if TARGET_IPHONE_SIMULATOR
_values = @[@(0.2),@(0.6),@(0.55), @(0.1), @(0.75), @(0.7)];
@@ -101,39 +110,39 @@ static const CGFloat kValueLineMargin = 1.5;
}
- (void)drawRect:(CGRect)rect {
CGRect r = self.bounds;
CGRect bounds = self.bounds;
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor);
CGContextFillRect(ctx, r);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, bounds);
CGFloat scale = [self.window.screen scale];
CGFloat midY = CGRectGetMidY(r);
CGFloat maxX = CGRectGetMaxX(r);
CGFloat halfHeight = r.size.height/2;
CGContextSaveGState(ctx);
CGFloat midY = CGRectGetMidY(bounds);
CGFloat maxX = CGRectGetMaxX(bounds);
CGFloat halfHeight = bounds.size.height/2;
CGContextSaveGState(context);
{
UIBezierPath *centerLine = [UIBezierPath new];
[centerLine moveToPoint:(CGPoint){.x=0,.y=midY}];
[centerLine addLineToPoint:(CGPoint){.x=maxX,.y=midY}];
CGContextSetLineWidth(ctx, 1/scale);
CGContextSetLineWidth(context, 1/scale);
[_keyColor setStroke];
CGFloat lengths[2] = {3,3};
CGContextSetLineDash(ctx, 0, lengths, 2);
CGContextSetLineDash(context, 0, lengths, 2);
[centerLine stroke];
}
CGContextRestoreGState(ctx);
CGContextRestoreGState(context);
CGFloat lineStep = kValueLineMargin + kValueLineWidth;
CGContextSaveGState(ctx);
CGContextSaveGState(context);
{
CGFloat x = maxX - lineStep/2;
CGContextSetLineWidth(ctx, kValueLineWidth);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(context, kValueLineWidth);
CGContextSetLineCap(context, kCGLineCapRound);
UIBezierPath *path1 = [UIBezierPath new];
path1.lineCapStyle = kCGLineCapRound;
@@ -143,16 +152,16 @@ static const CGFloat kValueLineMargin = 1.5;
for (NSNumber *value in [_values reverseObjectEnumerator]) {
CGFloat floatValue = [value doubleValue];
UIBezierPath *p = nil;
UIBezierPath *path = nil;
if (floatValue > _alertThreshold) {
p = path1;
path = path1;
[_alertColor setStroke];
} else {
p = path2;
path = path2;
[_keyColor setStroke];
}
[p moveToPoint:(CGPoint){.x=x,.y=midY-floatValue*halfHeight}];
[p addLineToPoint:(CGPoint){.x=x,.y=midY+floatValue*halfHeight}];
[path moveToPoint:(CGPoint){.x=x,.y=midY-floatValue*halfHeight}];
[path addLineToPoint:(CGPoint){.x=x,.y=midY+floatValue*halfHeight}];
x -= lineStep;
@@ -169,29 +178,29 @@ static const CGFloat kValueLineMargin = 1.5;
[path2 stroke];
}
CGContextRestoreGState(ctx);
CGContextRestoreGState(context);
}
@end
@interface ORKAudioTimerLabel : ORKLabel
@end
@implementation ORKAudioTimerLabel
+ (UIFont *)defaultFont {
UIFontDescriptor *descriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline];
UIFontDescriptor *alternativeDescriptor = ORKFontDescriptorForLightStylisticAlternative(descriptor);
return [UIFont fontWithDescriptor:alternativeDescriptor size:[alternativeDescriptor pointSize]+4];
}
@end
@interface ORKAudioContentView()
@interface ORKAudioContentView ()
@property (nonatomic, strong) ORKHeadlineLabel *alertLabel;
@property (nonatomic, strong) UILabel *timerLabel;
@@ -199,8 +208,8 @@ static const CGFloat kValueLineMargin = 1.5;
@end
@implementation ORKAudioContentView
{
@implementation ORKAudioContentView {
NSArray *_constraints;
NSMutableArray *_samples;
UIColor *_keyColor;
@@ -209,8 +218,7 @@ static const CGFloat kValueLineMargin = 1.5;
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
CGFloat margin = ORKStandardMarginForView(self);
self.layoutMargins = (UIEdgeInsets){.left=2*margin,.right=2*margin};
self.layoutMargins = ORKStandardFullScreenLayoutMarginsForView(self);
self.alertLabel = [ORKHeadlineLabel new];
_alertLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -243,6 +251,12 @@ static const CGFloat kValueLineMargin = 1.5;
[self applyKeyColor];
}
-(void)setFailed:(BOOL)failed {
_failed = failed;
_alertLabel.text = failed ? ORKLocalizedString(@"AUDIO_GENERIC_ERROR_LABEL", nil) : ORKLocalizedString(@"AUDIO_TOO_LOUD_LABEL", nil);
[self updateAlertLabelHidden];
}
- (void)setFinished:(BOOL)finished {
_finished = finished;
[self updateAlertLabelHidden];
@@ -265,7 +279,6 @@ static const CGFloat kValueLineMargin = 1.5;
- (void)setAlertColor:(UIColor *)alertColor {
_alertColor = alertColor;
_alertLabel.textColor = alertColor;
_graphView.alertColor = alertColor;
}
@@ -281,21 +294,34 @@ static const CGFloat kValueLineMargin = 1.5;
NSDictionary *views = NSDictionaryOfVariableBindings(_timerLabel, _alertLabel, _graphView);
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_graphView]-[_alertLabel]|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
options:0
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_alertLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1 constant:0]];
multiplier:1
constant:0]];
const CGFloat sideMargin = self.layoutMargins.left + (2 * ORKStandardLeftMarginForTableViewCell(self));
const CGFloat innerMargin = 2;
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_graphView]-2-[_timerLabel]-|"
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-sideMargin-[_graphView]-innerMargin-[_timerLabel]-sideMargin-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil views:views]];
metrics:@{@"sideMargin": @(sideMargin), @"innerMargin": @(innerMargin)}
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_graphView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:(GraphViewBlueZoneHeight+GraphViewRedZoneHeight*2)]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_graphView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:(GraphViewBlueZoneHeight+GraphViewRedZoneHeight*2)]];
_constraints = constraints;
[NSLayoutConstraint activateConstraints:constraints];
@@ -317,17 +343,16 @@ static const CGFloat kValueLineMargin = 1.5;
static NSDateComponentsFormatter *_formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSDateComponentsFormatter *fmt = [NSDateComponentsFormatter new];
fmt.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
fmt.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
fmt.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
_formatter = fmt;
NSDateComponentsFormatter *formatter = [NSDateComponentsFormatter new];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
_formatter = formatter;
});
NSString *s = [_formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = s;
_timerLabel.hidden = (s == nil);
NSString *string = [_formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = string;
_timerLabel.hidden = (string == nil);
}
- (void)updateGraphSamples {
@@ -337,8 +362,8 @@ static const CGFloat kValueLineMargin = 1.5;
- (void)updateAlertLabelHidden {
NSNumber *sample = [_samples lastObject];
BOOL hide = _finished || !([sample doubleValue] > _alertThreshold);
_alertLabel.hidden = hide;
BOOL show = (! _finished && ([sample doubleValue] > _alertThreshold)) || _failed;
_alertLabel.hidden = !show;
}
- (void)setSamples:(NSArray *)samples {
+107
View File
@@ -0,0 +1,107 @@
/*
Copyright (c) 2015, Shazino SAS. 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.
---
This software is based on the original source by Matt Gallagher.
http://www.cocoawithlove.com/2010/10/ios-tone-generator-introduction-to.html
Copyright (c) 2009-2011 Matt Gallagher. All rights reserved.
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software. Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import <ResearchKit/ORKRecorder.h>
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKAudioGenerator` class represents an audio tone generator.
*/
ORK_CLASS_AVAILABLE
@interface ORKAudioGenerator : NSObject
/**
Plays a tone at a specific frequency in stereo.
The sound is a "pure" sinusoid tone.
@param frequency The audio frequency in hertz.
*/
- (void)playSoundAtFrequency:(double)frequency;
/**
Plays a tone at a specific frequency on a specific channel, with a fade-in effect.
The sound is a "pure" sinusoid tone.
The fade-in effect is applied linearly for the peak amplitude, from a 0 to 1 factor.
@param frequency The audio frequency in hertz.
@param channel The audio channel (left or right).
@param duration The fade-in duration.
*/
- (void)playSoundAtFrequency:(double)frequency
onChannel:(ORKAudioChannel)channel
fadeInDuration:(NSTimeInterval)duration;
/**
Stops the audio being played.
*/
- (void)stop;
/**
Returns the peak audio volume being currently played, in decibels (dB).
@return The current audio volume in decibels.
*/
- (double)volumeInDecibels;
/**
Returns the peak audio volume amplitude being currently played (from 0 to 1).
@return The current audio volume amplitude.
*/
- (double)volumeAmplitude;
@end
NS_ASSUME_NONNULL_END
+284
View File
@@ -0,0 +1,284 @@
/*
Copyright (c) 2015, Shazino SAS. 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.
---
This software is based on the original source by Matt Gallagher.
http://www.cocoawithlove.com/2010/10/ios-tone-generator-introduction-to.html
Copyright (c) 2009-2011 Matt Gallagher. All rights reserved.
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software. Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import "ORKAudioGenerator.h"
@import AudioToolbox;
@interface ORKAudioGenerator () {
@public
AudioComponentInstance _toneUnit;
@public
double _frequency;
double _theta;
ORKAudioChannel _activeChannel;
BOOL _playsStereo;
double _fadeInFactor;
NSTimeInterval _fadeInDuration;
}
- (void)setupAudioSession;
- (void)createToneUnit;
- (void)play;
- (void)handleInterruption:(id)sender;
@end
const double ORKSineWaveToneGeneratorAmplitudeDefault = 0.03f;
const double ORKSineWaveToneGeneratorSampleRateDefault = 44100.0f;
OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
// Fixed amplitude is good enough for our purposes
const double amplitude = ORKSineWaveToneGeneratorAmplitudeDefault;
// Get the tone parameters out of the view controller
ORKAudioGenerator *audioGenerator = (__bridge ORKAudioGenerator *)inRefCon;
double theta = audioGenerator->_theta;
double theta_increment = 2.0 * M_PI * audioGenerator->_frequency / ORKSineWaveToneGeneratorSampleRateDefault;
double fadeInFactor = audioGenerator->_fadeInFactor;
// This is a mono tone generator so we only need the first buffer
Float32 *bufferActive = (Float32 *)ioData->mBuffers[audioGenerator->_activeChannel].mData;
Float32 *bufferNonActive = (Float32 *)ioData->mBuffers[1 - audioGenerator->_activeChannel].mData;
// Generate the samples
for (UInt32 frame = 0; frame < inNumberFrames; frame++) {
double bufferValue = sin(theta) * amplitude * pow(10, 2 * fadeInFactor - 2);
bufferActive[frame] = bufferValue;
if (audioGenerator->_playsStereo) {
bufferNonActive[frame] = bufferValue;
}
else {
bufferNonActive[frame] = 0;
}
theta += theta_increment;
if (theta > 2.0 * M_PI) {
theta -= 2.0 * M_PI;
}
fadeInFactor += 1/(ORKSineWaveToneGeneratorSampleRateDefault * audioGenerator->_fadeInDuration);
if (fadeInFactor >= 1) {
fadeInFactor = 1;
}
}
// Store the theta back in the view controller
audioGenerator->_theta = theta;
audioGenerator->_fadeInFactor = fadeInFactor;
return noErr;
}
@implementation ORKAudioGenerator
- (instancetype)init {
self = [super init];
if (self) {
[self setupAudioSession];
// Automatically stop and then restart audio playback when the app resigns active.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
}
return self;
}
- (void)dealloc {
[self stop];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
if (_toneUnit) {
__unused OSErr err = AudioOutputUnitStart(_toneUnit);
NSAssert1(err == noErr, @"Error starting unit: %hd", err);
}
}
- (void)applicationWillResignActive:(NSNotification *)notification {
if (_toneUnit) {
__unused OSErr err = AudioOutputUnitStop(_toneUnit);
NSAssert1(err == noErr, @"Error stopping unit: %hd", err);
}
}
- (double)volumeInDecibels {
return 20 * log(self.volumeAmplitude);
}
- (double)volumeAmplitude {
return ORKSineWaveToneGeneratorAmplitudeDefault * pow(10, 2 * _fadeInFactor - 2);
}
- (void)playSoundAtFrequency:(double)playFrequency {
_frequency = playFrequency;
_fadeInFactor = 0;
_fadeInDuration = 0.5;
_playsStereo = YES;
[self play];
}
- (void)playSoundAtFrequency:(double)playFrequency
onChannel:(ORKAudioChannel)playChannel
fadeInDuration:(NSTimeInterval)duration {
_frequency = playFrequency;
_activeChannel = playChannel;
_fadeInFactor = 0;
_fadeInDuration = duration;
_playsStereo = NO;
[self play];
}
- (void)play {
if (!_toneUnit) {
[self createToneUnit];
// Stop changing parameters on the unit
OSErr err = AudioUnitInitialize(_toneUnit);
NSAssert1(err == noErr, @"Error initializing unit: %hd", err);
// Start playback
err = AudioOutputUnitStart(_toneUnit);
NSAssert1(err == noErr, @"Error starting unit: %hd", err);
}
}
- (void)stop {
if (_toneUnit) {
AudioOutputUnitStop(_toneUnit);
AudioUnitUninitialize(_toneUnit);
AudioComponentInstanceDispose(_toneUnit);
_toneUnit = nil;
}
}
- (void)setupAudioSession {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
BOOL ok;
NSError *setCategoryError = nil;
ok = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
NSAssert1(ok, @"Audio error %@", setCategoryError);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleInterruption:)
name:AVAudioSessionInterruptionNotification
object:audioSession];
}
- (void)createToneUnit {
// Configure the search parameters to find the default playback output unit
// (called the kAudioUnitSubType_RemoteIO on iOS but
// kAudioUnitSubType_DefaultOutput on Mac OS X)
AudioComponentDescription defaultOutputDescription;
defaultOutputDescription.componentType = kAudioUnitType_Output;
defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
defaultOutputDescription.componentFlags = 0;
defaultOutputDescription.componentFlagsMask = 0;
// Get the default playback output unit
AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription);
NSAssert(defaultOutput, @"Can't find default output");
// Create a new unit based on this that we'll use for output
OSErr err = AudioComponentInstanceNew(defaultOutput, &_toneUnit);
NSAssert1(_toneUnit, @"Error creating unit: %hd", err);
// Set our tone rendering function on the unit
AURenderCallbackStruct input;
input.inputProc = ORKAudioGeneratorRenderTone;
input.inputProcRefCon = (__bridge void *)(self);
err = AudioUnitSetProperty(_toneUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input));
NSAssert1(err == noErr, @"Error setting callback: %hd", err);
// Set the format to 32 bit, single channel, floating point, linear PCM
const int four_bytes_per_float = 4;
const int eight_bits_per_byte = 8;
AudioStreamBasicDescription streamFormat;
streamFormat.mSampleRate = ORKSineWaveToneGeneratorSampleRateDefault;
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
streamFormat.mBytesPerPacket = four_bytes_per_float;
streamFormat.mFramesPerPacket = 1;
streamFormat.mBytesPerFrame = four_bytes_per_float;
streamFormat.mChannelsPerFrame = 2;
streamFormat.mBitsPerChannel = four_bytes_per_float * eight_bits_per_byte;
err = AudioUnitSetProperty (_toneUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&streamFormat,
sizeof(AudioStreamBasicDescription));
NSAssert1(err == noErr, @"Error setting stream format: %hd", err);
}
- (void)handleInterruption:(id)sender {
[self stop];
}
@end
+12 -8
View File
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKRecorder.h>
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
@@ -58,20 +60,22 @@ ORK_CLASS_AVAILABLE
Passed to AVAudioRecorder`'s `-initWithURL:settings:error:`
For information on the settings available for an audio recorder, see "AV Foundation Audio Settings Constants".
*/
@property (nonatomic, copy, readonly, nullable) NSDictionary *recorderSettings;
@property (nonatomic, copy, readonly) NSDictionary *recorderSettings;
/**
Returns an initialized audio recorder using the specified settings, step, and output directory.
@param recorderSettings The settings for the recording session.
@param step The step that requested this recording.
@param outputDirectory The directory in which the audio output should be stored.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param recorderSettings The settings for the recording session.
@param step The step that requested this recorder.
@param outputDirectory The directory in which the audio output should be stored.
@return An initialized audio recorder.
*/
- (instancetype)initWithRecorderSettings:(NSDictionary *)recorderSettings
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier
recorderSettings:(nullable NSDictionary *)recorderSettings
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
/**
Reference to the audio recorder being used.
+69 -87
View File
@@ -28,12 +28,14 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKAudioRecorder.h"
#import "ORKHelpers.h"
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
#import "ORKDefines_Private.h"
@interface ORKAudioRecorder ()
@property (nonatomic, strong) AVAudioRecorder *audioRecorder;
@@ -42,41 +44,34 @@
@end
@implementation ORKAudioRecorder
- (void)dealloc
{
- (void)dealloc {
ORK_Log_Debug(@"Remove audiorecorder %p", self);
[_audioRecorder stop];
_audioRecorder = nil;
}
+ (NSDictionary *)defaultRecorderSettings
{
return [NSDictionary
dictionaryWithObjectsAndKeys:
@(kAudioFormatMPEG4AAC), AVFormatIDKey,
@(AVAudioQualityMin), AVEncoderAudioQualityKey,
@(2), AVNumberOfChannelsKey,
@(44100.0), AVSampleRateKey,
nil];
+ (NSDictionary *)defaultRecorderSettings {
return @{AVFormatIDKey : @(kAudioFormatMPEG4AAC),
AVEncoderAudioQualityKey : @(AVAudioQualityMin),
AVNumberOfChannelsKey : @(2),
AVSampleRateKey : @(44100.0)};
}
- (instancetype)initWithRecorderSettings:(NSDictionary *)recorderSettings
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory
{
self = [super initWithStep:step outputDirectory:outputDirectory];
- (instancetype)initWithIdentifier:(NSString *)identifier
recorderSettings:(NSDictionary *)recorderSettings
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier step:step outputDirectory:outputDirectory];
if (self) {
self.continuesInBackground = YES;
if (! recorderSettings)
{
if (! recorderSettings) {
recorderSettings = [[self class] defaultRecorderSettings];
}
if (! [recorderSettings isKindOfClass:[NSDictionary class]])
{
if (! [recorderSettings isKindOfClass:[NSDictionary class]]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"recorderSettings should be a dictionary" userInfo:recorderSettings];
}
self.recorderSettings = recorderSettings;
@@ -85,7 +80,9 @@
}
- (void)start {
if (self.outputDirectory == nil) {
@throw [NSException exceptionWithName:NSDestinationInvalidException reason:@"audioRecorder requires an output directory" userInfo:nil];
}
// Only create the file when we should actually start recording.
if (! _audioRecorder) {
@@ -103,7 +100,6 @@
return;
}
ORK_Log_Debug(@"Create audioRecorder %p", self);
_audioRecorder = [[AVAudioRecorder alloc]
initWithURL:soundFileURL
@@ -115,16 +111,14 @@
}
#if ! TARGET_IPHONE_SIMULATOR
if (!_audioRecorder.recording)
{
if (!_audioRecorder.recording) {
[_audioRecorder prepareToRecord];
}
#endif
}
#if ! TARGET_IPHONE_SIMULATOR
if (!_audioRecorder.recording)
{
if (!_audioRecorder.recording) {
[_audioRecorder prepareToRecord];
[_audioRecorder record];
}
@@ -136,7 +130,6 @@
- (void)stop {
if (! _audioRecorder) {
// Error has already been returned.
return;
}
@@ -161,43 +154,39 @@
unsigned int recorderFormat = [recorderSettings[AVFormatIDKey] unsignedIntValue];
NSString *contentType = @"audio";
switch (recorderFormat)
{
case kAudioFormatLinearPCM:
{
switch (recorderFormat) {
case kAudioFormatLinearPCM: {
int numBits = [recorderSettings[AVLinearPCMBitDepthKey] intValue] ? : 16;
contentType = [NSString stringWithFormat:@"audio/L%d", numBits];
break;
}
case kAudioFormatAC3:
case kAudioFormatAC3: {
contentType = @"audio/ac3";
break;
}
case kAudioFormatMPEG4AAC:
case kAudioFormatMPEG4CELP:
case kAudioFormatMPEG4HVXC:
case kAudioFormatMPEG4TwinVQ:
case kAudioFormatAppleLossless:
case kAudioFormatAppleLossless: {
contentType = @"audio/m4a";
break;
case kAudioFormatULaw:
}
case kAudioFormatULaw: {
contentType = @"audio/basic";
break;
}
}
return contentType;
}
- (NSString *)recorderType
{
- (NSString *)recorderType {
return @"audio";
}
- (void)doStopRecording
{
- (void)doStopRecording {
if (self.isRecording) {
#if ! TARGET_IPHONE_SIMULATOR
#if !TARGET_IPHONE_SIMULATOR
[_audioRecorder stop];
[self applyFileProtection:ORKFileProtectionComplete toFileAtURL:[self recordingFileURL]];
@@ -205,48 +194,44 @@
}
}
- (void)finishRecordingWithError:(NSError *)error
{
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
- (NSString *)extension
{
- (NSString *)extension {
NSDictionary *recorderSettings = [self recorderSettings];
unsigned int recorderFormat = [recorderSettings[AVFormatIDKey] unsignedIntValue];
NSString *extension = @"au";
switch (recorderFormat)
{
switch (recorderFormat) {
case kAudioFormatLinearPCM:
{
extension = @"pcm";
break;
}
case kAudioFormatAC3:
case kAudioFormatAC3: {
extension = @"ac3";
break;
}
case kAudioFormatMPEG4AAC:
case kAudioFormatMPEG4CELP:
case kAudioFormatMPEG4HVXC:
case kAudioFormatMPEG4TwinVQ:
case kAudioFormatAppleLossless:
case kAudioFormatAppleLossless: {
extension = @"m4a";
break;
}
}
return extension;
}
- (NSURL *)recordingFileURL
{
- (NSURL *)recordingFileURL {
return [[self recordingDirectoryURL] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", [self logName], [self extension]]];
}
- (BOOL)recreateFileWithError:(NSError * __autoreleasing *)error
{
- (BOOL)recreateFileWithError:(NSError * __autoreleasing *)error {
NSURL *url = [self recordingFileURL];
if (! url) {
if (error) {
@@ -255,34 +240,34 @@
return NO;
}
NSFileManager *fm = [NSFileManager defaultManager];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (! [fm createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:error]) {
if (! [fileManager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:error]) {
return NO;
}
if ([fm fileExistsAtPath:[url path]]) {
if (! [fm removeItemAtPath:[url path] error:error]) {
if ([fileManager fileExistsAtPath:[url path]]) {
if (! [fileManager removeItemAtPath:[url path] error:error]) {
return NO;
}
}
[fm createFileAtPath:[url path] contents:nil attributes:nil];
[fm setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(ORKFileProtectionCompleteUnlessOpen)} ofItemAtPath:[url path] error:error];
[fileManager createFileAtPath:[url path] contents:nil attributes:nil];
[fileManager setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(ORKFileProtectionCompleteUnlessOpen)} ofItemAtPath:[url path] error:error];
return YES;
}
- (void)reset {
[_audioRecorder stop];
_audioRecorder = nil;
[super reset];
}
@end
@interface ORKAudioRecorderConfiguration ()
@end
@@ -290,13 +275,15 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
- (instancetype)initWithRecorderSettings:(NSDictionary *)recorderSettings
{
self = [self ork_init];
if (self)
{
if (recorderSettings && ! [recorderSettings isKindOfClass:[NSDictionary class]])
{
- (instancetype)initWithIdentifier:(NSString *)identifier {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use subclass designated initializer" userInfo:nil];
}
- (instancetype)initWithIdentifier:(NSString *)identifier
recorderSettings:(NSDictionary *)recorderSettings {
self = [super initWithIdentifier:identifier];
if (self) {
if (recorderSettings && ! [recorderSettings isKindOfClass:[NSDictionary class]]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"recorderSettings should be a dictionary" userInfo:recorderSettings];
}
_recorderSettings = recorderSettings;
@@ -306,31 +293,27 @@
#pragma clang diagnostic pop
- (ORKRecorder *)recorderForStep:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory
{
return [[ORKAudioRecorder alloc] initWithRecorderSettings:(NSDictionary *__nonnull)self.recorderSettings
step:step
outputDirectory:outputDirectory];
outputDirectory:(NSURL *)outputDirectory {
return [[ORKAudioRecorder alloc] initWithIdentifier:self.identifier
recorderSettings:self.recorderSettings
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self)
{
if (self) {
ORK_DECODE_OBJ_CLASS(aDecoder, recorderSettings, NSDictionary);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_OBJ(aCoder, recorderSettings);
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
@@ -339,12 +322,11 @@
__typeof(self) castObject = object;
return (isParentSame &&
ORKEqualObjects(self.recorderSettings, castObject.recorderSettings)) ;
ORKEqualObjects(self.recorderSettings, castObject.recorderSettings));
}
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionAudioRecording;
}
@end
@end
+3 -3
View File
@@ -28,15 +28,15 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKAudioStep : ORKActiveStep
@property (nonatomic, assign) NSTimeInterval duration;
@end
NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_END
+11 -41
View File
@@ -28,69 +28,39 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKAudioStep.h"
#import "ORKAudioStepViewController.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
@implementation ORKAudioStep
+ (Class)stepViewControllerClass {
return [ORKAudioStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
NSTimeInterval const ORKAudioTaskMinimumDuration = 5.0;
if ( self.duration < ORKAudioTaskMinimumDuration)
{
if ( self.stepDuration < ORKAudioTaskMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKAudioTaskMinimumDuration)] userInfo:nil];
}
}
- (instancetype)copyWithZone:(NSZone *)zone
{
ORKAudioStep *step = [super copyWithZone:zone];
step.duration = self.duration;
return step;
}
- (BOOL)startsFinished {
return NO;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
ORK_DECODE_DOUBLE(aDecoder, duration);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[super encodeWithCoder:aCoder];
ORK_ENCODE_DOUBLE(aCoder, duration);
}
+ (BOOL)supportsSecureCoding
{
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
(self.duration == castObject.duration)) ;
}
@end
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@@ -37,4 +39,4 @@ ORK_CLASS_AVAILABLE
@end
NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_END
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKAudioStepViewController.h"
#import "ORKAudioContentView.h"
#import "ORKActiveStepViewController_Internal.h"
@@ -41,22 +42,22 @@
#import "ORKActiveStepView.h"
#import "ORKCustomStepView_Internal.h"
@interface ORKAudioStepViewController ()
@property (nonatomic, strong) AVAudioRecorder *avAudioRecorder;
@end
@implementation ORKAudioStepViewController
{
@implementation ORKAudioStepViewController {
ORKAudioContentView *_audioContentView;
ORKAudioRecorder *_audioRecorder;
ORKActiveStepTimer *_timer;
NSError *_audioRecorderError;
}
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
// Continue audio recording in the background
@@ -68,15 +69,13 @@
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_audioContentView = [ORKAudioContentView new];
_audioContentView.timeLeft = self.audioStep.duration;
_audioContentView.timeLeft = self.audioStep.stepDuration;
self.activeStepView.activeCustomView = _audioContentView;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self start];
}
@@ -93,7 +92,6 @@
break;
}
}
_audioRecorder = audioRecorder;
[self audioRecorderDidChange];
}
@@ -103,26 +101,26 @@
}
- (void)doSample {
if (_audioRecorderError) {
return;
}
[_avAudioRecorder updateMeters];
float value = [_avAudioRecorder averagePowerForChannel:0];
// Assume value is in range roughly -60dB to 0dB
float clampedValue = MAX(value/60.0, -1) + 1;
[_audioContentView addSample:@(clampedValue)];
_audioContentView.timeLeft = [_timer duration] - [_timer runtime];
}
- (void)startNewTimerIfNeeded {
if (! _timer) {
NSTimeInterval duration = self.audioStep.duration;
NSTimeInterval duration = self.audioStep.stepDuration;
__weak typeof(self) weakSelf = self;
_timer = [[ORKActiveStepTimer alloc] initWithDuration:duration interval:duration/100 runtime:0 handler:^(ORKActiveStepTimer *timer, BOOL finished) {
typeof(self) strongSelf = weakSelf;
[strongSelf doSample];
if (finished) {
[self finish];
[strongSelf finish];
}
}];
[_timer resume];
@@ -130,16 +128,15 @@
_audioContentView.finished = NO;
}
- (void)start {
[super start];
[self audioRecorderDidChange];
[_timer reset];
_timer = nil;
[self startNewTimerIfNeeded];
}
- (void)suspend {
[super suspend];
[_timer pause];
@@ -147,13 +144,18 @@
[_audioContentView addSample:@(0)];
}
}
- (void)resume {
[super resume];
[self audioRecorderDidChange];
[self startNewTimerIfNeeded];
[_timer resume];
}
- (void)finish {
if (_audioRecorderError) {
return;
}
[super finish];
[_timer reset];
_timer = nil;
@@ -166,7 +168,12 @@
- (void)setAvAudioRecorder:(AVAudioRecorder *)recorder {
_avAudioRecorder = nil;
_avAudioRecorder = recorder;
}
- (void) recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error {
[super recorder:recorder didFailWithError:error];
_audioRecorderError = error;
_audioContentView.failed = YES;
}
@end
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit.h>
#import <ResearchKit/ORKActiveStep.h>
/**
The `ORKCountdownStep` class represents a step that displays a label and a
countdown for a time equal to its duration.
+5 -6
View File
@@ -28,18 +28,18 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKCountdownStep.h"
#import "ORKCountdownStepViewController.h"
@implementation ORKCountdownStep
+ (Class)stepViewControllerClass
{
+ (Class)stepViewControllerClass {
return [ORKCountdownStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier
{
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldStartTimerAutomatically = YES;
@@ -56,8 +56,7 @@
NSTimeInterval const ORKCountdownStepMinimumDuration = 3.0;
if ( self.stepDuration < ORKCountdownStepMinimumDuration)
{
if ( self.stepDuration < ORKCountdownStepMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKCountdownStepMinimumDuration)] userInfo:nil];
}
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit_Private.h>
/**
The `ORKCountdownStepViewController` class represents the step view controller that corresponds to an `ORKCountdownStep`.
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKCountdownStepViewController.h"
#import "ORKCustomStepView_Internal.h"
#import "ORKActiveStepViewController_internal.h"
@@ -41,6 +42,7 @@
#import "ORKAccessibility.h"
#import "ORKActiveStepView.h"
@interface ORKCountDownViewLabel : ORKLabel
@end
@@ -51,6 +53,7 @@
}
@end
@interface ORKCountdownView : ORKActiveStepCustomView
@property (nonatomic, strong) ORKSubheadlineLabel *textLabel;
@@ -61,15 +64,14 @@
@end
@implementation ORKCountdownView {
CAShapeLayer *_circleLayer;
}
- (instancetype)init
{
- (instancetype)init {
self = [super init];
if (self) {
_textLabel = [ORKSubheadlineLabel new];
_textLabel.textAlignment = NSTextAlignmentCenter;
_textLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -93,9 +95,18 @@
NSDictionary *views = NSDictionaryOfVariableBindings(_textLabel, _timeLabel, _progressView);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_textLabel]-(>=0)-[_progressView(==d)]|" options:NSLayoutFormatDirectionLeadingToTrailing|NSLayoutFormatAlignAllCenterX metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_textLabel]-(>=0)-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_progressView(==d)]-(>=0)-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_textLabel]-(>=0)-[_progressView(==d)]|"
options:NSLayoutFormatDirectionLeadingToTrailing|NSLayoutFormatAlignAllCenterX
metrics:metrics
views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_textLabel]-(>=0)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_progressView(==d)]-(>=0)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:views]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
@@ -134,13 +145,11 @@
_circleLayer.strokeColor = self.tintColor.CGColor;
_circleLayer.lineWidth = 1;
[_progressView.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
[_progressView.layer addSublayer:_circleLayer];
_textLabel.isAccessibilityElement = NO;
_timeLabel.isAccessibilityElement = NO;
}
return self;
}
@@ -150,7 +159,6 @@
}
- (void)startAnimateWithDuration:(NSTimeInterval)duration {
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = duration*2;
animation.removedOnCompletion = YES;
@@ -158,7 +166,6 @@
animation.keyTimes = @[@(0.0), @(0.5), @(1.0)];
animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[_circleLayer addAnimation:animation forKey:@"drawCircleAnimation"];
}
#pragma mark Accessibility
@@ -184,12 +191,12 @@
@end
@implementation ORKCountdownStepViewController {
NSInteger _countDown;
}
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = NO;
@@ -226,7 +233,6 @@
}
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished {
_countDown = MAX((_countDown-1), 0);
[self updateCountdownLabel];
@@ -240,17 +246,13 @@
[super countDownTimerFired:timer finished:finished];
}];
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, ORKLocalizedString(@"AX_ANNOUNCE_BEGIN_TASK", nil));
}
else {
} else {
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, [@(_countDown) stringValue]);
[super countDownTimerFired:timer finished:finished];
}
}
else
{
} else {
[super countDownTimerFired:timer finished:finished];
}
}
@end
+36 -17
View File
@@ -32,6 +32,7 @@
#import <Foundation/Foundation.h>
#import <ResearchKit/ORKDefines.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKDataLogger;
@@ -94,14 +95,12 @@ ORK_CLASS_AVAILABLE
/**
Returns a data logger with an `ORKJSONLogFormatter`.
@param url The URL of the directory in which to place log files.
@param logName The prefix on the log file name in an ASCII string. Note that
the string must not contain the hyphen character ("-"), because a hyphen is used as a separator in the log naming scheme.
@param delegate The initial delegate. May be `nil`.
@param url The URL of the directory in which to place log files.
@param logName The prefix on the log file name in an ASCII string. Note that the string must not contain the hyphen character ("-"), because a hyphen is used as a separator in the log naming scheme.
@param delegate The initial delegate. May be `nil`.
*/
+ (ORKDataLogger *)JSONDataLoggerWithDirectory:(NSURL *)url logName:(NSString *)logName delegate:(nullable id<ORKDataLoggerDelegate>)delegate;
/**
Returns an initialized data logger using the specified URL, log name, formatter, and delegate.
@@ -110,6 +109,7 @@ ORK_CLASS_AVAILABLE
the string must not contain the hyphen character ("-"), because a hyphen is used as a separator in the log naming scheme.
@param formatter The type of formatter to use for the log, such as `ORKJSONLogFormatter`.
@param delegate The initial delegate. May be `nil`.
@return An initialized data logger.
*/
- (instancetype)initWithDirectory:(NSURL *)url logName:(NSString *)logName formatter:(ORKLogFormatter *)formatter delegate:(nullable id<ORKDataLoggerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
@@ -160,7 +160,8 @@ ORK_CLASS_AVAILABLE
than through this object.
@param block The block to call during enumeration.
@param error Any error detected during the enumeration
@param error Any error detected during the enumeration.
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
@@ -174,7 +175,8 @@ ORK_CLASS_AVAILABLE
than through this object.
@param block The block to call during enumeration.
@param error Any error detected during the enumeration
@param error Any error detected during the enumeration.
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
@@ -188,7 +190,8 @@ ORK_CLASS_AVAILABLE
than through this object.
@param block The block to call during enumeration.
@param error Any error detected during the enumeration
@param error Any error detected during the enumeration.
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
@@ -204,6 +207,7 @@ ORK_CLASS_AVAILABLE
@param object Should be an object of a class that is accepted by the logFormatter.
@param error Error output, if the append fails.
@return `YES` if appending succeeds; otherwise, `NO`.
*/
- (BOOL)append:(id)object error:(NSError * __autoreleasing *)error;
@@ -216,6 +220,7 @@ ORK_CLASS_AVAILABLE
@param objects An array of objects of a class that is accepted by the logFormatter.
@param error Error output, if the append fails.
@return `YES` if appending succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * __nullable __autoreleasing *)error;
@@ -224,6 +229,7 @@ ORK_CLASS_AVAILABLE
Checks whether a file has been marked as uploaded.
@param url The URL to check.
@return `YES` if the uploaded attribute has been set on the file and the file exists; otherwise,
`NO`.
*/
@@ -240,6 +246,7 @@ ORK_CLASS_AVAILABLE
@param uploaded A Boolean value that indicates whether to mark the file uploaded or not uploaded.
@param url The URL to mark.
@param error The error that occurred, if the operation fails.
@return `YES` if adding or removing the attribute succeeded; otherwise, `NO`.
*/
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * __nullable __autoreleasing *)error;
@@ -253,6 +260,7 @@ ORK_CLASS_AVAILABLE
@param fileURLs The array of files that should be removed.
@param error The error that occurred, if the operation fails.
@return `YES` if removing the files succeeded; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray *)fileURLs withError:(NSError * __nullable __autoreleasing *)error;
@@ -261,13 +269,14 @@ ORK_CLASS_AVAILABLE
Removes all files managed by this logger (files that have the `logName` prefix).
@param error The error that occurred, if operation fails.
@return `YES` if removing the files succeeded.; otherwise, `NO`.
*/
- (BOOL)removeAllFilesWithError:(NSError *__nullable __autoreleasing *)error;
@end
/**
The `ORKLogFormatter` class represents the base (default) log formatter, which appends data
blindly to a log file.
@@ -285,6 +294,7 @@ ORK_CLASS_AVAILABLE
Returns a Boolean value that indicates whether the log formatter can serialize the specified type of object.
@param c The class of object to serialize.
@return `YES` if the log formatter can serialize this object class; otherwise, `NO`.
*/
- (BOOL)canAcceptLogObjectOfClass:(Class)c;
@@ -293,6 +303,7 @@ ORK_CLASS_AVAILABLE
Returns a Boolean value that indicates whether the log formatter can serialize the specified type of object.
@param object The object to serialize.
@return `YES` if the log formatter can serialize `object`; otherwise, `NO`
*/
- (BOOL)canAcceptLogObject:(id)object;
@@ -304,6 +315,7 @@ ORK_CLASS_AVAILABLE
@param fileHandle The file handle to which to write.
@param error The error output, on failure.
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * __nullable __autoreleasing *)error;
@@ -314,6 +326,7 @@ ORK_CLASS_AVAILABLE
@param object The object to write.
@param fileHandle The file handle to which to write.
@param error The error output, on failure.
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * __nullable __autoreleasing *)error;
@@ -324,12 +337,14 @@ ORK_CLASS_AVAILABLE
@param objects The objects to write.
@param fileHandle The file handle to which to write.
@param error The error output, on failure.
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * __nullable __autoreleasing *)error;
@end
/**
The `ORKJSONLogFormatter` class represents a log formatter for producing JSON output.
@@ -352,7 +367,6 @@ ORK_CLASS_AVAILABLE
The `ORKDataLoggerManagerDelegate` protocol defines methods a delegate can implement to receive notifications
when the data loggers managed by a `ORKDataLoggerManager` reach a certain file size threshold.
*/
ORK_CLASS_AVAILABLE
@protocol ORKDataLoggerManagerDelegate <NSObject>
@@ -377,6 +391,7 @@ ORK_CLASS_AVAILABLE
@end
/**
The `ORKDataLoggerManager` class represents a manager for multiple `ORKDataLogger` instances,
which tracks the total size of log files produced and can notify its delegate
@@ -415,6 +430,7 @@ ORK_CLASS_AVAILABLE
@param directory The file URL of the directory where the data loggers should coexist.
@param delegate The delegate to receive notifications.
@return An initialized data logger manager.
*/
- (instancetype)initWithDirectory:(NSURL *)directory delegate:(nullable id<ORKDataLoggerManagerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
@@ -440,6 +456,7 @@ ORK_CLASS_AVAILABLE
This method throws an exception if a logger already exists with the specified log name.
@param logName The log name prefix for the data logger.
@return The `ORKDataLogger` object that was added.
*/
- (ORKDataLogger *)addJSONDataLoggerForLogName:(NSString *)logName;
@@ -449,6 +466,7 @@ ORK_CLASS_AVAILABLE
@param logName The log name prefix for the data logger.
@param formatter The log formatter instance to use for this logger.
@return The `ORKDataLogger` object that was added, or the existing one if one already existed for
that log name.
*/
@@ -458,6 +476,7 @@ ORK_CLASS_AVAILABLE
Retrieves the already existing data logger for a log name.
@param logName The log name prefix for the data logger.
@return The `ORKDataLogger` object that was retrieved, or `nil` if one already existed for that log name.
*/
- (nullable ORKDataLogger *)dataLoggerForLogName:(NSString *)logName;
@@ -479,6 +498,7 @@ ORK_CLASS_AVAILABLE
@param block The block to call during enumeration.
@param error The error, on failure.
@return `YES` if the enumeration succeeds; otherwise, `NO`.
*/
- (BOOL)enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
@@ -489,8 +509,9 @@ ORK_CLASS_AVAILABLE
Use this method to indicate that the specified files should no longer be marked uploaded (for example, because
the upload did not succeed).
@param fileURLs The array of file URLs that should no longer be marked uploaded.
@param fileURLs The array of file URLs that should no longer be marked uploaded.
@param error The error, on failure.
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)unmarkUploadedFiles:(NSArray *)fileURLs error:(NSError * __nullable __autoreleasing *)error;
@@ -502,8 +523,9 @@ ORK_CLASS_AVAILABLE
that may relate to any of the data loggers. It is an error to pass a URL which would not
belong to one of the loggers managed by this manager.
@param fileURLs The array of file URLs that should be removed.
@param fileURLs The array of file URLs that should be removed.
@param error The error, on failure.
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray *)fileURLs error:(NSError * __nullable __autoreleasing *)error;
@@ -514,16 +536,13 @@ ORK_CLASS_AVAILABLE
This method removes uploaded logs first, followed by the oldest log files across
all of the data loggers, until the total usage falls below a threshold.
@param bytes The threshold down to which to remove old log files. File
removal stops when the total bytes managed by all the data
loggers reaches this threshold.
@param bytes The threshold down to which to remove old log files. File removal stops when the total bytes managed by all the data loggers reaches this threshold.
@param error The error, on failure.
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError * __nullable __autoreleasing *)error;
@end
NS_ASSUME_NONNULL_END
File diff suppressed because it is too large Load Diff
@@ -31,25 +31,32 @@
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
/*
Exposing a minimal set of extra facilities to permit unit testing.
*/
@interface ORKDataLogger ()
@interface ORKDataLogger()
- (nullable NSFileHandle *)fileHandle;
@end
@protocol ORKDataLoggerExtendedDelegate <ORKDataLoggerDelegate>
@optional
- (void)dataLoggerThresholdsDidChange:(ORKDataLogger *)dataLogger;
@end
@interface NSURL (ORKDataLogger)
- (BOOL)ork_isUploaded;
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError * __autoreleasing *)error;
@end
NS_ASSUME_NONNULL_END
@@ -30,6 +30,18 @@
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class CMDeviceMotion;
@protocol ORKDeviceMotionRecorderDelegate <ORKRecorderDelegate>
@optional
- (void)deviceMotionRecorderDidUpdateWithMotion:(CMDeviceMotion *)motion;
@end
/**
The `ORKDeviceMotionRecorder` class represents a recorder that requests and collects device motion data from CoreMotion at a fixed frequency.
@@ -40,18 +52,25 @@ ORK_CLASS_AVAILABLE
@interface ORKDeviceMotionRecorder : ORKRecorder
/**
* The frequency of motion data collection from CoreMotion in hertz (Hz).
The frequency of motion data collection from CoreMotion in hertz (Hz).
*/
@property (nonatomic, readonly) double frequency;
/**
Returns an initialized device motion recorder using the specified frequency.
@param frequency The frequency of motion data collection from CoreMotion in hertz (Hz).
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param frequency The frequency of motion data collection from CoreMotion in hertz (Hz).
@param step The step that requested this recorder.
@param outputDirectory The directory in which the device motion data should be stored.
@return An initialized motion data recorder.
*/
- (instancetype)initWithFrequency:(double)frequency
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier
frequency:(double)frequency
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKDeviceMotionRecorder.h"
#import "ORKHelpers.h"
#import "ORKRecorder_Internal.h"
@@ -36,12 +37,13 @@
#import <CoreMotion/CoreMotion.h>
#import "CMDeviceMotion+ORKJSONDictionary.h"
@interface ORKDeviceMotionRecorder()
{
@interface ORKDeviceMotionRecorder () {
ORKDataLogger *_logger;
}
@property (nonatomic, strong) CMMotionManager *motionManager;
@property (nonatomic) NSTimeInterval uptime;
@end
@@ -49,35 +51,28 @@
@implementation ORKDeviceMotionRecorder
- (instancetype)initWithFrequency:(double)frequency
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory
{
self = [super initWithStep:step
outputDirectory:(NSURL *)outputDirectory];
if (self)
{
- (instancetype)initWithIdentifier:(NSString *)identifier
frequency:(double)frequency
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier
step:step
outputDirectory:outputDirectory];
if (self) {
self.frequency = frequency;
self.continuesInBackground = YES;
}
return self;
}
- (void)dealloc
{
- (void)dealloc {
[_logger finishCurrentLog];
}
- (void)setFrequency:(double)frequency
{
if (frequency <= 0)
{
- (void)setFrequency:(double)frequency {
if (frequency <= 0) {
_frequency = 1;
}
else
{
} else {
_frequency = frequency;
}
}
@@ -87,7 +82,6 @@
}
- (void)start {
[super start];
if (! _logger) {
@@ -114,6 +108,10 @@
if (data)
{
success = [_logger append:[data ork_JSONDictionary] error:&error];
id delegate = self.delegate;
if ([delegate respondsToSelector:@selector(deviceMotionRecorderDidUpdateWithMotion:)]) {
[delegate deviceMotionRecorderDidUpdateWithMotion:data];
}
}
if (!success)
{
@@ -124,13 +122,10 @@
}];
}
- (NSString *)recorderType
{
- (NSString *)recorderType {
return @"deviceMotion";
}
- (void)stop {
[self doStopRecording];
[_logger finishCurrentLog];
@@ -146,16 +141,14 @@
[super stop];
}
- (void)doStopRecording
{
- (void)doStopRecording {
if (self.isRecording) {
[self.motionManager stopDeviceMotionUpdates];
self.motionManager = nil;
}
}
- (void)finishRecordingWithError:(NSError *)error
{
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
@@ -168,8 +161,7 @@
return @"application/json";
}
- (void)reset
{
- (void)reset {
[super reset];
_logger = nil;
@@ -178,7 +170,8 @@
@end
@interface ORKDeviceMotionRecorderConfiguration()
@interface ORKDeviceMotionRecorderConfiguration ()
@end
@@ -186,8 +179,12 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
- (instancetype)initWithFrequency:(double)freq {
self = [super ork_init];
- (instancetype)initWithIdentifier:(NSString *)identifier {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use subclass designated initializer" userInfo:nil];
}
- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)freq {
self = [super initWithIdentifier:identifier];
if (self) {
_frequency = freq;
}
@@ -195,32 +192,27 @@
}
#pragma clang diagnostic pop
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory
{
return [[ORKDeviceMotionRecorder alloc] initWithFrequency:self.frequency
step:step
outputDirectory:(NSURL *)outputDirectory];
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKDeviceMotionRecorder alloc] initWithIdentifier:self.identifier
frequency:self.frequency
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self)
{
if (self) {
ORK_DECODE_DOUBLE(aDecoder, frequency);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_DOUBLE(aCoder, frequency);
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
@@ -229,7 +221,7 @@
__typeof(self) castObject = object;
return (isParentSame &&
(self.frequency == castObject.frequency)) ;
(self.frequency == castObject.frequency));
}
- (ORKPermissionMask)requestedPermissionMask {
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKFitnessContentView : ORKActiveStepCustomView
+95 -35
View File
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKFitnessContentView.h"
#import "ORKHelpers.h"
#import <CoreMotion/CoreMotion.h>
@@ -35,11 +36,11 @@
#import "ORKActiveStepQuantityView.h"
#import "ORKTintedImageView.h"
// #define LAYOUT_TEST 1
// #define LAYOUT_DEBUG 1
@interface ORKFitnessContentView()
{
@interface ORKFitnessContentView () {
ORKQuantityLabel *_timerLabel;
ORKQuantityPairView *_quantityPairView;
UIView *_imageSpacer1;
@@ -54,6 +55,7 @@
@end
@implementation ORKFitnessContentView
- (ORKActiveStepQuantityView *)distanceView {
@@ -104,11 +106,14 @@
self.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.2];
_quantityPairView.backgroundColor = [[UIColor orangeColor] colorWithAlphaComponent:0.2];
#endif
[self setDistanceInMeters:0];
[self heartRateView].title = ORKLocalizedString(@"FITNESS_HEARTRATE_TITLE", nil);
[self addSubview:_quantityPairView];
[self addSubview:_imageView];
[self addSubview:_timerLabel];
[self setNeedsUpdateConstraints];
[self setupConstraints];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localeDidChange:) name:NSCurrentLocaleDidChangeNotification object:nil];
@@ -125,7 +130,6 @@
_lengthFormatter = [NSLengthFormatter new];
_lengthFormatter.numberFormatter.maximumFractionDigits = 1;
_lengthFormatter.numberFormatter.maximumSignificantDigits = 3;
}
- (void)localeDidChange:(NSNotification *)notification {
@@ -133,9 +137,6 @@
[self setDistanceInMeters:_distanceInMeters];
}
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
_screenType = ORKGetScreenTypeForWindow(newWindow);
@@ -149,40 +150,94 @@
_topConstraint.constant = (CaptionBaselineToTimerTop - CaptionBaselineToStepViewTop);
}
- (void)updateConstraints {
if (_constraints) {
[self removeConstraints:_constraints];
_constraints = nil;
}
- (void)setupConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_timerLabel, _imageView, _quantityPairView, _imageSpacer1, _imageSpacer2);
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_timerLabel][_imageSpacer1(>=0)][_imageView]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
_topConstraint = [NSLayoutConstraint constraintWithItem:_timerLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1 constant:0];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_timerLabel][_imageSpacer1(>=0)][_imageView]"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
_topConstraint = [NSLayoutConstraint constraintWithItem:_timerLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:0];
[self updateConstraintConstants];
[constraints addObject:_topConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timerLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timerLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[constraints addObject:[NSLayoutConstraint
constraintWithItem:_timerLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timerLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_imageView][_imageSpacer2(>=0)][_quantityPairView]|" options:0 metrics:nil views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer2 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_imageSpacer2 attribute:NSLayoutAttributeHeight multiplier:1 constant:0]];
NSLayoutConstraint *c1 = [NSLayoutConstraint constraintWithItem:_imageSpacer1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:1000];
c1.priority = UILayoutPriorityDefaultLow-1;
[constraints addObject:c1];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_imageView][_imageSpacer2(>=0)][_quantityPairView]|"
options:0
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_imageSpacer2
attribute:NSLayoutAttributeHeight
multiplier:1
constant:0]];
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:1000];
constraint1.priority = UILayoutPriorityDefaultLow-1;
[constraints addObject:constraint1];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_quantityPairView]|" options:(NSLayoutFormatOptions)0 metrics:nil views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_quantityPairView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:10000];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:ORKScreenMetricMaxDimension];
maxWidthConstraint.priority = UILayoutPriorityRequired-1;
[constraints addObject:maxWidthConstraint];
[self addConstraints:constraints];
_constraints = constraints;
[super updateConstraints];
}
- (void)setImage:(UIImage *)image {
@@ -191,9 +246,15 @@
_imageRatioConstraint.active = NO;
CGSize sz = image.size;
if (sz.width > 0 && sz.height > 0) {
_imageRatioConstraint = [NSLayoutConstraint constraintWithItem:_imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_imageView attribute:NSLayoutAttributeWidth multiplier:sz.height/sz.width constant:0];
CGSize size = image.size;
if (size.width > 0 && size.height > 0) {
_imageRatioConstraint = [NSLayoutConstraint constraintWithItem:_imageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_imageView
attribute:NSLayoutAttributeWidth
multiplier:size
.height/size.width constant:0];
_imageRatioConstraint.active = YES;
}
}
@@ -213,7 +274,6 @@
- (void)setHeartRate:(NSString *)heartRate {
_heartRate = heartRate;
[self heartRateView].value = heartRate;
[self heartRateView].title = ORKLocalizedString(@"FITNESS_HEARTRATE_TITLE", nil);
}
- (void)updateKeylineVisible {
+2
View File
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit.h>
#import <ResearchKit/ORKActiveStep.h>
/**
Fitness step.
+12 -8
View File
@@ -28,30 +28,36 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKFitnessStep.h"
#import "ORKFitnessStepViewController.h"
@implementation ORKFitnessStep
+ (Class)stepViewControllerClass {
return [ORKFitnessStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
NSTimeInterval const ORKFitnessStepMinimumDuration = 5.0;
if ( self.stepDuration < ORKFitnessStepMinimumDuration)
{
if ( self.stepDuration < ORKFitnessStepMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"rest duration can not be shorter than %@ seconds.", @(ORKFitnessStepMinimumDuration)] userInfo:nil];
}
}
- (instancetype)copyWithZone:(NSZone *)zone
{
- (instancetype)copyWithZone:(NSZone *)zone {
ORKFitnessStep *step = [super copyWithZone:zone];
return step;
}
@@ -60,6 +66,4 @@
return NO;
}
@end
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit_Private.h>
/**
Step view controller corresponding to `ORKFitnessStep`.
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKFitnessStepViewController.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
@@ -41,20 +42,18 @@
#import "ORKActiveStepView.h"
@interface ORKFitnessStepViewController () <ORKHealthQuantityTypeRecorderDelegate,ORKPedometerRecorderDelegate>
{
@interface ORKFitnessStepViewController () <ORKHealthQuantityTypeRecorderDelegate,ORKPedometerRecorderDelegate> {
NSInteger _intendedSteps;
ORKFitnessContentView *_contentView;
NSNumberFormatter *_hrFormatter;
}
@end
@implementation ORKFitnessStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = NO;
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKHealthQuantityTypeRecorder;
@@ -37,11 +39,11 @@ NS_ASSUME_NONNULL_BEGIN
@protocol ORKHealthQuantityTypeRecorderDelegate <ORKRecorderDelegate>
@optional
- (void)healthQuantityTypeRecorderDidUpdate:(ORKHealthQuantityTypeRecorder *)healthQuantityTypeRecorder;
@end
/**
The `ORKHealthQuantityTypeRecorder` class represents a recorder for collecting real time sample data from HealthKit, such as heart rate, during
an active task.
@@ -49,14 +51,28 @@ NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHealthQuantityTypeRecorder : ORKRecorder
@property (nonatomic, readonly, copy) HKQuantityType *quantityType;
@property (nonatomic, readonly, copy) HKUnit *unit;
@property (nonatomic, readonly, copy, nullable) HKQuantitySample *lastSample;
@property (nonatomic, copy, readonly) HKQuantityType *quantityType;
- (instancetype)initWithHealthQuantityType:(HKQuantityType *)quantityType
unit:(HKUnit *)unit
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
@property (nonatomic, copy, readonly) HKUnit *unit;
@property (nonatomic, copy, readonly, nullable) HKQuantitySample *lastSample;
/**
Returns an initialized health quantity type recorder using the specified quantity type and unit.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param quantityType The quantity type that should be collected during the active task.
@param unit The unit for the data that should be collected and serialized.
@param step The step that requested this recorder.
@param outputDirectory The directory in which the HealthKit data should be stored.
@return An initialized health quantity type recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier
healthQuantityType:(HKQuantityType *)quantityType
unit:(HKUnit *)unit
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
@end
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHealthQuantityTypeRecorder.h"
#import "ORKHelpers.h"
#import "ORKDataLogger.h"
@@ -35,8 +36,8 @@
#import "ORKRecorder_Internal.h"
#import "HKSample+ORKJSONDictionary.h"
@interface ORKHealthQuantityTypeRecorder()
{
@interface ORKHealthQuantityTypeRecorder () {
ORKDataLogger *_logger;
BOOL _isRecording;
HKHealthStore *_healthStore;
@@ -46,23 +47,20 @@
HKQuantitySample *_lastSample;
}
@property (nonatomic, strong) NSError *recordingError;
@end
@implementation ORKHealthQuantityTypeRecorder
- (instancetype)initWithHealthQuantityType:(HKQuantityType *)quantityType
unit:(HKUnit *)unit
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory
{
self = [super initWithStep:step
outputDirectory:(NSURL *)outputDirectory];
if (self)
{
- (instancetype)initWithIdentifier:(NSString *)identifier
healthQuantityType:(HKQuantityType *)quantityType
unit:(HKUnit *)unit
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier
step:step
outputDirectory:outputDirectory];
if (self) {
NSParameterAssert(quantityType != nil);
NSParameterAssert(unit != nil);
// Quantity type and unit are immutable, so should be equivalent to -copy
@@ -74,9 +72,7 @@
return self;
}
- (void)dealloc
{
- (void)dealloc {
[_logger finishCurrentLog];
}
@@ -89,7 +85,6 @@
if (delegate && [delegate respondsToSelector:@selector(healthQuantityTypeRecorderDidUpdate:)]) {
[delegate healthQuantityTypeRecorderDidUpdate:self];
}
}
static const NSInteger _HealthAnchoredQueryLimit = 100;
@@ -123,19 +118,15 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
// Do another fetch immediately rather than wait for an observation
[self doFetchNewData];
}
});
}
- (void)doFetchNewData {
if (! _healthStore || ! _isRecording) {
return;
}
NSAssert(_samplePredicate != nil, @"Sample predicate should be non-nil if recording");
__weak typeof(self) weakSelf = self;
HKAnchoredObjectQuery *anchoredQuery = [[HKAnchoredObjectQuery alloc]
initWithType:_quantityType
@@ -157,12 +148,9 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
[_healthStore executeQuery:anchoredQuery];
}
- (void)start {
[super start];
if (! _logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
@@ -172,8 +160,7 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
}
if (! [HKHealthStore isHealthDataAvailable])
{
if (! [HKHealthStore isHealthDataAvailable]) {
[self finishRecordingWithError:[NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}]];
@@ -230,13 +217,10 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
[_healthStore executeQuery:_observerQuery];
}
- (NSString *)recorderType
{
- (NSString *)recorderType {
return _quantityType.identifier;
}
- (void)stop {
if (! _isRecording) {
return;
@@ -251,14 +235,12 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
fileUrl = logFileUrl;
} error:&error];
[self reportFileResultWithFile:fileUrl error:error];
[super stop];
}
- (void)doStopRecording
{
- (void)doStopRecording {
if (_isRecording) {
NSAssert(_observerQuery != nil, @"Observer query should be non-nil when recording");
[_healthStore stopQuery:_observerQuery];
@@ -271,8 +253,7 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
}
- (void)finishRecordingWithError:(NSError *)error
{
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
@@ -285,8 +266,7 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
return @"application/json";
}
- (void)reset
{
- (void)reset {
[super reset];
_logger = nil;
@@ -294,15 +274,22 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
@end
@interface ORKHealthQuantityTypeRecorderConfiguration()
@interface ORKHealthQuantityTypeRecorderConfiguration ()
@end
@implementation ORKHealthQuantityTypeRecorderConfiguration
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
- (instancetype)initWithHealthQuantityType:(HKQuantityType *)quantityType unit:(HKUnit *)unit {
self = [super ork_init];
- (instancetype)initWithIdentifier:(NSString *)identifier {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use subclass designated initializer" userInfo:nil];
}
- (instancetype)initWithIdentifier:(NSString *)identifier healthQuantityType:(HKQuantityType *)quantityType unit:(HKUnit *)unit {
self = [super initWithIdentifier:identifier];
if (self) {
NSParameterAssert(quantityType != nil);
NSParameterAssert(unit != nil);
@@ -314,34 +301,29 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
#pragma clang diagnostic pop
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory
{
return [[ORKHealthQuantityTypeRecorder alloc] initWithHealthQuantityType:_quantityType
unit:_unit
step:step
outputDirectory:outputDirectory];
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKHealthQuantityTypeRecorder alloc] initWithIdentifier:self.identifier
healthQuantityType:_quantityType
unit:_unit
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self)
{
if (self) {
ORK_DECODE_OBJ_CLASS(aDecoder, quantityType, HKQuantityType);
ORK_DECODE_OBJ_CLASS(aDecoder, unit, HKUnit);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
- (void)encodeWithCoder:(NSCoder *)aCoder {
ORK_ENCODE_OBJ(aCoder, quantityType);
ORK_ENCODE_OBJ(aCoder, unit);
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
@@ -351,10 +333,9 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
__typeof(self) castObject = object;
return (isParentSame &&
ORKEqualObjects(self.quantityType, castObject.quantityType)&&
ORKEqualObjects(self.unit, castObject.unit)) ;
ORKEqualObjects(self.unit, castObject.unit));
}
- (NSSet *)requestedHealthKitTypesForReading {
return [NSSet setWithObject:_quantityType];
}
@@ -28,8 +28,12 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKLocationRecorder` class represents a recorder for collecting location data from CoreLocation.
@@ -41,4 +45,19 @@
ORK_CLASS_AVAILABLE
@interface ORKLocationRecorder : ORKRecorder
/**
Returns an initialized location recorder.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param step The step that requested this recorder.
@param outputDirectory The directory in which the location data should be stored.
@return An initialized location recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END
+24 -32
View File
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKLocationRecorder.h"
#import <CoreLocation/CoreLocation.h>
#import "CLLocation+ORKJSONDictionary.h"
@@ -35,13 +36,15 @@
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
@interface ORKLocationRecorder() <CLLocationManagerDelegate>
{
@interface ORKLocationRecorder () <CLLocationManagerDelegate> {
ORKDataLogger *_logger;
NSError *_recordingError;
BOOL _started;
}
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic) NSTimeInterval uptime;
@end
@@ -49,19 +52,15 @@
@implementation ORKLocationRecorder
- (instancetype)initWithStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory
{
self = [super initWithStep:step outputDirectory:outputDirectory];
if (self)
{
- (instancetype)initWithIdentifier:(NSString *)identifier step:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier step:step outputDirectory:outputDirectory];
if (self) {
self.continuesInBackground = YES;
}
return self;
}
- (void)dealloc
{
- (void)dealloc {
[_logger finishCurrentLog];
}
@@ -86,8 +85,7 @@
}
self.locationManager = [self createLocationManager];
if ([CLLocationManager authorizationStatus] <= kCLAuthorizationStatusDenied)
{
if ([CLLocationManager authorizationStatus] <= kCLAuthorizationStatusDenied) {
[self.locationManager requestWhenInUseAuthorization];
}
self.locationManager.pausesLocationUpdatesAutomatically = NO;
@@ -115,7 +113,6 @@
[self doStopRecording];
[_logger finishCurrentLog];
NSError *error = _recordingError;
_recordingError = nil;
__block NSURL *fileUrl = nil;
@@ -129,13 +126,11 @@
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
didUpdateLocations:(NSArray *)locations {
BOOL success = YES;
NSParameterAssert([locations count] >= 0);
NSError *error = nil;
if (locations)
{
if (locations) {
NSMutableArray *dictionaries = [NSMutableArray arrayWithCapacity:[locations count]];
[locations enumerateObjectsUsingBlock:^(CLLocation *obj, NSUInteger idx, BOOL *stop) {
NSDictionary *d = [obj ork_JSONDictionary];
@@ -144,8 +139,7 @@
success = [_logger appendObjects:dictionaries error:&error];
}
if (!success)
{
if (!success) {
dispatch_async(dispatch_get_main_queue(), ^{
_recordingError = error;
[self stop];
@@ -153,8 +147,7 @@
}
}
- (void)finishRecordingWithError:(NSError *)error
{
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:nil];
}
@@ -163,14 +156,12 @@
return [CLLocationManager locationServicesEnabled] && (self.locationManager != nil) && ([CLLocationManager authorizationStatus] > kCLAuthorizationStatusDenied);
}
- (void)reset
{
- (void)reset {
[super reset];
_logger = nil;
}
- (NSString *)mimeType {
return @"application/json";
}
@@ -178,35 +169,36 @@
@end
@interface ORKLocationRecorderConfiguration()
@interface ORKLocationRecorderConfiguration ()
@end
@implementation ORKLocationRecorderConfiguration
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKLocationRecorder alloc] initWithStep:step outputDirectory:outputDirectory];
- (instancetype)initWithIdentifier:(NSString *)identifier {
return [super initWithIdentifier:identifier];
}
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKLocationRecorder alloc] initWithIdentifier:self.identifier step:step outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
return self;
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
return isParentSame;
}
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionCoreLocation;
}
+16 -3
View File
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKPedometerRecorder;
@@ -37,11 +39,11 @@ NS_ASSUME_NONNULL_BEGIN
@protocol ORKPedometerRecorderDelegate <ORKRecorderDelegate>
@optional
- (void)pedometerRecorderDidUpdate:(ORKPedometerRecorder *)pedometerRecorder;
@end
/**
A recorder that requests and collects device motion data from CoreMotion at a fixed frequency.
@@ -52,13 +54,24 @@ ORK_CLASS_AVAILABLE
@interface ORKPedometerRecorder : ORKRecorder
@property (nonatomic, readonly, nullable) NSDate *lastUpdateDate;
@property (nonatomic, readonly) NSInteger totalNumberOfSteps;
// Negative if an invalid value.
@property (nonatomic, readonly) NSInteger totalDistance;
- (instancetype)initWithStep:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
/**
Returns an initialized pedometer recorder.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param step The step that requested this recorder.
@param outputDirectory The directory in which the pedometer data should be stored.
@return An initialized pedometer recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
@end
+31 -55
View File
@@ -28,49 +28,43 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKPedometerRecorder.h"
#import "ORKDataLogger.h"
#import "CMPedometerData+ORKJSONDictionary.h"
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
@interface ORKPedometerRecorder()
{
@interface ORKPedometerRecorder () {
ORKDataLogger *_logger;
BOOL _isRecording;
}
@property (nonatomic, strong) CMPedometer *pedometer;
@property (nonatomic, strong) NSError *recordingError;
@end
@implementation ORKPedometerRecorder
- (instancetype)initWithStep:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory
{
self = [super initWithStep:step
outputDirectory:(NSURL *)outputDirectory];
if (self)
{
- (instancetype)initWithIdentifier:(NSString *)identifier
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier
step:step
outputDirectory:outputDirectory];
if (self) {
self.continuesInBackground = YES;
}
return self;
}
- (void)dealloc
{
- (void)dealloc {
[_logger finishCurrentLog];
}
- (void)updateStatisticsWithData:(CMPedometerData *)pedometerData {
_lastUpdateDate = pedometerData.endDate;
_totalNumberOfSteps = [pedometerData.numberOfSteps integerValue];
if (pedometerData.distance) {
@@ -90,7 +84,6 @@
}
- (void)start {
[super start];
_lastUpdateDate = nil;
@@ -108,8 +101,7 @@
self.pedometer = [self createPedometer];
if (! [[self.pedometer class] isStepCountingAvailable])
{
if (! [[self.pedometer class] isStepCountingAvailable]) {
[self finishRecordingWithError:[NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}]];
@@ -121,16 +113,14 @@
[self.pedometer startPedometerUpdatesFromDate:[NSDate date] withHandler:^(CMPedometerData *pedometerData, NSError *error) {
BOOL success = NO;
if (pedometerData)
{
if (pedometerData) {
success = [_logger append:[pedometerData ork_JSONDictionary] error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
__typeof(self) strongSelf = weakSelf;
[strongSelf updateStatisticsWithData:pedometerData];
});
}
if (!success || error)
{
if (!success || error) {
dispatch_async(dispatch_get_main_queue(), ^{
__typeof(self) strongSelf = weakSelf;
[strongSelf finishRecordingWithError:error];
@@ -139,13 +129,10 @@
}];
}
- (NSString *)recorderType
{
- (NSString *)recorderType {
return @"pedometer";
}
- (void)stop {
[self doStopRecording];
[_logger finishCurrentLog];
@@ -154,17 +141,15 @@
__block NSURL *fileUrl = nil;
[_logger enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
fileUrl = logFileUrl;
} error:&error];
}
error:&error];
[self reportFileResultWithFile:fileUrl error:error];
[super stop];
}
- (void)doStopRecording
{
- (void)doStopRecording {
if (_isRecording) {
[self.pedometer stopPedometerUpdates];
_isRecording = NO;
@@ -172,8 +157,7 @@
}
}
- (void)finishRecordingWithError:(NSError *)error
{
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
@@ -186,8 +170,7 @@
return @"application/json";
}
- (void)reset
{
- (void)reset {
[super reset];
_logger = nil;
@@ -196,47 +179,40 @@
@end
@interface ORKPedometerRecorderConfiguration()
@interface ORKPedometerRecorderConfiguration ()
@end
@implementation ORKPedometerRecorderConfiguration
- (instancetype)init {
self = [super ork_init];
return self;
- (instancetype)initWithIdentifier:(NSString *)identifier {
return [super initWithIdentifier:identifier];
}
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory
{
return [[ORKPedometerRecorder alloc] initWithStep:step
outputDirectory:outputDirectory];
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKPedometerRecorder alloc] initWithIdentifier:self.identifier
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
return self;
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
return (isParentSame) ;
return (isParentSame);
}
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionCoreMotionActivity;
}
@end
@@ -0,0 +1,45 @@
/*
Copyright (c) 2015, James Cox. 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 "ORKCustomStepView_Internal.h"
@interface ORKReactionTimeContentView : ORKActiveStepCustomView
- (void)setStimulusHidden:(BOOL)hidden;
- (void)startSuccessAnimationWithDuration:(NSTimeInterval)duration completion:(nullable void (^)(void))completion;
- (void)startFailureAnimationWithDuration:(NSTimeInterval)duration completion:(nullable void (^)(void))completion;
- (void)resetAfterDelay:(NSTimeInterval)delay completion:(nullable void (^)(void))completion;
@end
@@ -0,0 +1,113 @@
/*
Copyright (c) 2015, James Cox. 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 "ORKReactionTimeContentView.h"
#import "ORKReactionTimeStimulusView.h"
#import "ORKNavigationContainerView.h"
@interface ORKReactionTimeContentView ()
@property (nonatomic, strong) ORKReactionTimeStimulusView *stimulusView;
@end
@implementation ORKReactionTimeContentView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.translatesAutoresizingMaskIntoConstraints = NO;
[self addStimulusView];
}
return self;
}
- (void)startSuccessAnimationWithDuration:(NSTimeInterval)duration completion:(void (^)(void))completion {
[_stimulusView startSuccessAnimationWithDuration:duration completion:completion];
}
- (void)startFailureAnimationWithDuration:(NSTimeInterval)duration completion:(void (^)(void))completion {
[_stimulusView startFailureAnimationWithDuration:duration completion:completion];
}
- (void)resetAfterDelay:(NSTimeInterval)delay completion:(nullable void (^)(void))completion {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_stimulusView.hidden = YES;
if (completion) {
completion();
}
});
}
- (void)addStimulusView {
if (!_stimulusView) {
_stimulusView = [ORKReactionTimeStimulusView new];
_stimulusView.translatesAutoresizingMaskIntoConstraints = NO;
_stimulusView.backgroundColor = self.tintColor;
[self addSubview:_stimulusView];
[self setUpStimulusViewConstraints];
}
}
- (void)setStimulusHidden:(BOOL)hidden {
_stimulusView.hidden = hidden;
}
- (void)setUpStimulusViewConstraints {
NSMutableArray *constraints = [NSMutableArray array];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_stimulusView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_stimulusView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:8.0]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_stimulusView]-(>=0)-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:NSDictionaryOfVariableBindings(_stimulusView)]];
[NSLayoutConstraint activateConstraints:constraints];
}
@end
@@ -0,0 +1,59 @@
/*
Copyright (c) 2015, James Cox. 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 <ResearchKit/ResearchKit.h>
#import <AudioToolbox/AudioServices.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKReactionTimeStep : ORKActiveStep
@property (nonatomic, assign) NSTimeInterval maximumStimulusInterval;
@property (nonatomic, assign) NSTimeInterval minimumStimulusInterval;
@property (nonatomic, assign) NSTimeInterval timeout;
@property (nonatomic, assign) NSInteger numberOfAttempts;
@property (nonatomic, assign) double thresholdAcceleration;
@property (nonatomic, assign) SystemSoundID successSound;
@property (nonatomic, assign) SystemSoundID timeoutSound;
@property (nonatomic, assign) SystemSoundID failureSound;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,146 @@
/*
Copyright (c) 2015, James Cox. 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 "ORKReactionTimeStep.h"
#import "ORKReactionTimeViewController.h"
#import "ORKHelpers.h"
@implementation ORKReactionTimeStep
+ (Class)stepViewControllerClass {
return [ORKReactionTimeViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
self.shouldContinueOnFinish = YES;
return self;
}
- (instancetype)copyWithZone:(NSZone *)zone {
ORKReactionTimeStep *step = [super copyWithZone:zone];
step.maximumStimulusInterval = self.maximumStimulusInterval;
step.minimumStimulusInterval = self.minimumStimulusInterval;
step.thresholdAcceleration = self.thresholdAcceleration;
step.timeout = self.timeout;
step.numberOfAttempts = self.numberOfAttempts;
step.successSound = self.successSound;
step.timeoutSound = self.timeoutSound;
step.failureSound = self.failureSound;
return step;
}
- (void)validateParameters {
[super validateParameters];
if (self.minimumStimulusInterval <= 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:@"minimumStimulusInterval must be greater than zero"
userInfo:nil];
}
if (self.maximumStimulusInterval < self.minimumStimulusInterval) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:@"maximumStimulusInterval can not be less than minimumStimulusInterval"
userInfo:nil];
}
if (self.thresholdAcceleration <= 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:@"thresholdAcceleration must be greater than zero"
userInfo:nil];
}
if (self.timeout <= 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:@"timeout must be greater than zero"
userInfo:nil];
}
if (self.numberOfAttempts <= 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:@"numberOfAttempts must be greater than zero"
userInfo:nil];
}
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_DOUBLE(aDecoder, maximumStimulusInterval);
ORK_DECODE_DOUBLE(aDecoder, minimumStimulusInterval);
ORK_DECODE_DOUBLE(aDecoder, thresholdAcceleration);
ORK_DECODE_DOUBLE(aDecoder, timeout);
ORK_DECODE_UINT32(aDecoder, successSound);
ORK_DECODE_UINT32(aDecoder, timeoutSound);
ORK_DECODE_UINT32(aDecoder, failureSound);
ORK_DECODE_INTEGER(aDecoder, numberOfAttempts);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_DOUBLE(aCoder, maximumStimulusInterval);
ORK_ENCODE_DOUBLE(aCoder, minimumStimulusInterval);
ORK_ENCODE_DOUBLE(aCoder, thresholdAcceleration);
ORK_ENCODE_DOUBLE(aCoder, timeout);
ORK_ENCODE_UINT32(aCoder, successSound);
ORK_ENCODE_UINT32(aCoder, timeoutSound);
ORK_ENCODE_UINT32(aCoder, failureSound);
ORK_ENCODE_INTEGER(aCoder, numberOfAttempts);
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
(self.maximumStimulusInterval == castObject.maximumStimulusInterval) &&
(self.minimumStimulusInterval == castObject.minimumStimulusInterval) &&
(self.thresholdAcceleration == castObject.thresholdAcceleration) &&
(self.timeout == castObject.timeout) &&
(self.successSound == castObject.successSound) &&
(self.timeoutSound == castObject.timeoutSound) &&
(self.failureSound == castObject.failureSound) &&
(self.numberOfAttempts == castObject.numberOfAttempts));
}
- (BOOL)allowsBackNavigation {
return NO;
}
- (BOOL)startsFinished {
return NO;
}
@end
@@ -0,0 +1,43 @@
/*
Copyright (c) 2015, James Cox. 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 "ORKCustomStepView_Internal.h"
@interface ORKReactionTimeStimulusView : UIView
- (void)reset;
- (void)startSuccessAnimationWithDuration:(NSTimeInterval)duration completion:(nullable void(^)(void))completion;
- (void)startFailureAnimationWithDuration:(NSTimeInterval)duration completion:(nullable void(^)(void))completion;
@end
@@ -0,0 +1,165 @@
/*
Copyright (c) 2015, James Cox. 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 "ORKReactionTimeStimulusView.h"
@implementation ORKReactionTimeStimulusView {
CAShapeLayer *_tickLayer;
CAShapeLayer *_crossLayer;
}
static const CGFloat RoundReactionTimeViewDiameter = 122;
- (instancetype)init {
self = [super init];
if (self) {
self.layer.cornerRadius = RoundReactionTimeViewDiameter * 0.5;
}
return self;
}
- (CGSize)intrinsicContentSize {
return CGSizeMake(RoundReactionTimeViewDiameter, RoundReactionTimeViewDiameter);
}
- (void)reset {
[_tickLayer removeFromSuperlayer];
[_crossLayer removeFromSuperlayer];
_tickLayer = nil;
_crossLayer = nil;
self.layer.backgroundColor = self.tintColor.CGColor;
}
- (void)startSuccessAnimationWithDuration:(NSTimeInterval)duration completion:(void(^)(void))completion {
if (self.hidden) {
if (completion) {
completion();
}
return;
}
[self addTickLayer];
[CATransaction begin];
[CATransaction setCompletionBlock:completion];
CAMediaTimingFunction *timing = [[CAMediaTimingFunction alloc] initWithControlPoints:0.180739998817444 :0 :0.577960014343262 :0.918200016021729];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[animation setTimingFunction:timing];
animation.removedOnCompletion = NO;
[animation setFillMode:kCAFillModeForwards];
animation.fromValue = @(0);
animation.toValue = @(1);
animation.duration = duration;
[_tickLayer addAnimation:animation forKey:@"strokeEnd"];
[CATransaction commit];
}
- (void)startFailureAnimationWithDuration:(NSTimeInterval)duration completion:(void(^)(void))completion {
self.hidden = NO;
self.layer.backgroundColor = [UIColor clearColor].CGColor;
[self addCrossLayer];
[CATransaction begin];
[CATransaction setCompletionBlock:completion];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[animation setFillMode:kCAFillModeForwards];
animation.fromValue = @([(CAShapeLayer *)[_crossLayer presentationLayer] strokeEnd]);
animation.toValue = @(1);
animation.duration = duration;
_crossLayer.strokeEnd = 1;
[_crossLayer addAnimation:animation forKey:@"strokeEnd"];
[CATransaction commit];
}
- (void)setHidden:(BOOL)hidden {
[self reset];
[super setHidden:hidden];
}
- (void)addCrossLayer {
_crossLayer = [self lineDrawingLayer];
_crossLayer.strokeColor = [UIColor redColor].CGColor;
_crossLayer.path = [self crossPath];
[self.layer addSublayer:_crossLayer];
}
- (void)addTickLayer {
_tickLayer = [self lineDrawingLayer];
_tickLayer.strokeColor = [UIColor whiteColor].CGColor;
_tickLayer.path = [self tickPath];
[self.layer addSublayer:_tickLayer];
}
- (CGPathRef)concealPath:(CGFloat)radius {
return [[UIBezierPath bezierPathWithArcCenter:CGPointMake(radius, radius)
radius:radius / 2
startAngle:M_PI + M_PI_2
endAngle:-M_PI_2
clockwise:NO] CGPath];
}
- (CGPathRef)tickPath {
UIBezierPath *path = [self linePath];
[path moveToPoint:(CGPoint){37,65}];
[path addLineToPoint:(CGPoint){50,78}];
[path addLineToPoint:(CGPoint){87,42}];
return path.CGPath;
}
- (CGPathRef)crossPath {
UIBezierPath *path = [self linePath];
[path moveToPoint:(CGPoint){45,78}];
[path addLineToPoint:(CGPoint){82,42}];
[path moveToPoint:(CGPoint){45,42}];
[path addLineToPoint:(CGPoint){82,78}];
return path.CGPath;
}
- (UIBezierPath *)linePath {
UIBezierPath *path = [UIBezierPath new];
path.lineCapStyle = kCGLineCapRound;
path.lineWidth = 5;
return path;
}
- (CAShapeLayer *)lineDrawingLayer {
CAShapeLayer *shapeLayer = [CAShapeLayer new];
shapeLayer.strokeEnd = 0;
shapeLayer.lineWidth = 5;
shapeLayer.lineCap = kCALineCapRound;
shapeLayer.lineJoin = kCALineJoinRound;
shapeLayer.frame = self.layer.bounds;
shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
shapeLayer.fillColor = nil;
return shapeLayer;
}
@end
@@ -0,0 +1,42 @@
/*
Copyright (c) 2015, James Cox. 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 <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKReactionTimeViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,231 @@
/*
Copyright (c) 2015, James Cox. 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 "ORKReactionTimeViewController.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKActiveStepView.h"
#import "ORKReactionTimeContentView.h"
#import "ORKReactionTimeStep.h"
#import <CoreMotion/CMDeviceMotion.h>
#import <AudioToolbox/AudioServices.h>
@implementation ORKReactionTimeViewController {
ORKReactionTimeContentView *_reactionTimeContentView;
NSMutableArray *_results;
NSTimer *_stimulusTimer;
NSTimer *_timeoutTimer;
NSTimeInterval _stimulusTimestamp;
BOOL _validResult;
BOOL _timedOut;
BOOL _shouldIndicateFailure;
}
static const NSTimeInterval OutcomeAnimationDuration = 0.3;
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self configureTitle];
_results = [NSMutableArray new];
_reactionTimeContentView = [ORKReactionTimeContentView new];
self.activeStepView.activeCustomView = _reactionTimeContentView;
self.activeStepView.stepViewFillsAvailableSpace = YES;
[_reactionTimeContentView setStimulusHidden:YES];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self start];
_shouldIndicateFailure = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
_shouldIndicateFailure = NO;
}
#pragma mark - ORKActiveStepViewController
- (void)start {
[super start];
[self startStimulusTimer];
}
#if TARGET_IPHONE_SIMULATOR
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if(event.type == UIEventSubtypeMotionShake)
{
if (_validResult) {
ORKReactionTimeResult *reactionTimeResult = [[ORKReactionTimeResult alloc] initWithIdentifier:self.step.identifier];
reactionTimeResult.timestamp = _stimulusTimestamp;
[_results addObject:reactionTimeResult];
}
[self attemptDidFinish];
}
}
#endif
- (ORKStepResult *)result {
ORKStepResult *stepResult = [super result];
stepResult.results = _results;
return stepResult;
}
- (void)applicationWillResignActive:(NSNotification *)notification {
[super applicationWillResignActive:notification];
_validResult = NO;
[_stimulusTimer invalidate];
[_timeoutTimer invalidate];
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
[super applicationDidBecomeActive:notification];
[self resetAfterDelay:0];
}
#pragma mark - ORKRecorderDelegate
- (void)recorder:(ORKRecorder *)recorder didCompleteWithResult:(ORKResult *)result {
if (_validResult) {
ORKReactionTimeResult *reactionTimeResult = [[ORKReactionTimeResult alloc] initWithIdentifier:self.step.identifier];
reactionTimeResult.timestamp = _stimulusTimestamp;
reactionTimeResult.fileResult = (ORKFileResult *)result;
[_results addObject:reactionTimeResult];
}
[self attemptDidFinish];
}
#pragma mark - ORKDeviceMotionRecorderDelegate
- (void)deviceMotionRecorderDidUpdateWithMotion:(CMDeviceMotion *)motion {
CMAcceleration v = motion.userAcceleration;
double vectorMagnitude = sqrt(((v.x * v.x) + (v.y * v.y) + (v.z * v.z)));
if (vectorMagnitude > [self reactionTimeStep].thresholdAcceleration) {
[self stopRecorders];
}
}
#pragma mark - ORKReactionTimeStepViewController
- (ORKReactionTimeStep *)reactionTimeStep {
return (ORKReactionTimeStep *)self.step;
}
- (void)configureTitle {
NSString *format = ORKLocalizedString(@"REACTION_TIME_TASK_ATTEMPTS_FORMAT", nil);
NSString *text = [NSString stringWithFormat:format, _results.count + 1, [self reactionTimeStep].numberOfAttempts];
[self.activeStepView updateTitle:ORKLocalizedString(@"REACTION_TIME_TASK_ACTIVE_STEP_TITLE", nil) text:text];
}
- (void)attemptDidFinish {
void (^completion)(void) = ^{
if ([_results count] == [self reactionTimeStep].numberOfAttempts) {
[self finish];
} else {
[self resetAfterDelay:2];
}
};
if (_validResult) {
[self indicateSuccess:completion];
} else {
[self indicateFailure:completion];
}
_validResult = NO;
_timedOut = NO;
[_stimulusTimer invalidate];
[_timeoutTimer invalidate];
}
- (void)indicateSuccess:(void(^)(void))completion {
[_reactionTimeContentView startSuccessAnimationWithDuration:OutcomeAnimationDuration completion:completion];
AudioServicesPlaySystemSound([self reactionTimeStep].successSound);
}
- (void)indicateFailure:(void(^)(void))completion {
if (!_shouldIndicateFailure) {
return;
}
[_reactionTimeContentView startFailureAnimationWithDuration:OutcomeAnimationDuration completion:completion];
SystemSoundID sound = _timedOut ? [self reactionTimeStep].timeoutSound : [self reactionTimeStep].failureSound;
AudioServicesPlayAlertSound(sound);
}
- (void)resetAfterDelay:(NSTimeInterval)delay {
__weak __typeof(self) weakSelf = self;
[_reactionTimeContentView resetAfterDelay:delay completion:^{
[weakSelf configureTitle];
[weakSelf start];
}];
}
- (void)startStimulusTimer {
_stimulusTimer = [NSTimer scheduledTimerWithTimeInterval:[self stimulusInterval] target:self selector:@selector(stimulusTimerDidFire) userInfo:nil repeats:NO];
}
- (void)stimulusTimerDidFire {
_stimulusTimestamp = [NSProcessInfo processInfo].systemUptime;
[_reactionTimeContentView setStimulusHidden:NO];
_validResult = YES;
[self startTimeoutTimer];
}
- (void)startTimeoutTimer {
NSTimeInterval timeout = [self reactionTimeStep].timeout;
if (timeout > 0) {
_timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:timeout target:self selector:@selector(timeoutTimerDidFire) userInfo:nil repeats:NO];
}
}
- (void)timeoutTimerDidFire {
_validResult = NO;
_timedOut = YES;
[self stopRecorders];
#if TARGET_IPHONE_SIMULATOR
// Device motion recorder won't work, so manually trigger didfinish
[self attemptDidFinish];
#endif
}
- (NSTimeInterval)stimulusInterval {
ORKReactionTimeStep *step = [self reactionTimeStep];
NSTimeInterval range = step.maximumStimulusInterval - step.minimumStimulusInterval;
NSTimeInterval randomFactor = ((NSTimeInterval)rand() / RAND_MAX) * range;
return randomFactor + step.minimumStimulusInterval;
}
@end
+115 -24
View File
@@ -1,5 +1,6 @@
/*
Copyright (c) 2015, Apple Inc. All rights reserved.
Copyright (c) 2015, Ricardo Sánchez-Sáez.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@@ -34,6 +35,7 @@
#import <HealthKit/HealthKit.h>
#import <ResearchKit/ORKResult.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKRecorder;
@@ -57,21 +59,35 @@ NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKRecorderConfiguration : NSObject <NSSecureCoding>
/**
The `init` method is unavailable outside the framework on `ORKRecorderConfiguration`,
/*
The `init` and `new` methods are unavailable outside the framework on `ORKRecorderConfiguration`,
because it is an abstract class.
`ORKRecorderConfiguration` classes should be initialized with custom designated
initializers on each subclass.
*/
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/**
A short string that uniquely identifies the recorder configuration within the step.
The identifier is reproduced in the results of a recorder created from this configuration. In fact, the only way to link a result
(an `ORKFileResult` object) to the recorder that generated it is to look at the value of
`identifier`. To accurately identify recorder results, you need to ensure that recorder identifiers
are unique within each step.
In some cases, it can be useful to link the recorder identifier to a unique identifier in a
database; in other cases, it can make sense to make the identifier human
readable.
*/
@property (nonatomic, copy, readonly) NSString *identifier;
/**
Returns a recorder instance using this configuration.
@param step The step for which this recorder is being created.
@param outputDirectory The directory in which all output file data should be written
(if producing `ORKFileResult` instances).
@param step The step for which this recorder is being created.
@param outputDirectory The directory in which all output file data should be written (if producing `ORKFileResult` instances).
@return A configured recorder instance.
*/
@@ -117,17 +133,25 @@ ORK_CLASS_AVAILABLE
This method is the designated initializer.
@param frequency The frequency of accelerometer data collection in samples per second (Hz).
@param identifier The unique identifier of the recorder configuration.
@param frequency The frequency of accelerometer data collection in samples per second (Hz).
@return An initialized accelerometer recorder configuration.
*/
- (instancetype)initWithFrequency:(double)frequency NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)frequency NS_DESIGNATED_INITIALIZER;
/**
Returns a new accelerometer recorder configuration initialized from data in the given unarchiver.
@param aDecoder Coder from which to initialize the accelerometer recorder configuration.
@return A new accelerometer recorder configuration.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@end
/**
The `ORKAudioRecorderConfiguration` class represents a configuration that records
audio data during an active step.
@@ -159,10 +183,20 @@ ORK_CLASS_AVAILABLE
For information on the settings available for an audio recorder, see "AV Foundation Audio Settings Constants".
@param recorderSettings The settings for the recording session.
@param identifier The unique identifier of the recorder configuration.
@param recorderSettings The settings for the recording session.
@return An initialized audio recorder configuration.
*/
- (instancetype)initWithRecorderSettings:(NSDictionary *)recorderSettings NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier recorderSettings:(NSDictionary *)recorderSettings NS_DESIGNATED_INITIALIZER;
/**
Returns a new audio recorder configuration initialized from data in the given unarchiver.
@param aDecoder Coder from which to initialize the audio recorder configuration.
@return A new audio recorder configuration.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@end
@@ -196,17 +230,25 @@ ORK_CLASS_AVAILABLE
This method is the designated initializer.
@param frequency Motion data collection frequency in samples per second (Hz).
@param identifier The unique identifier of the recorder configuration.
@param frequency Motion data collection frequency in samples per second (Hz).
@return An initialized device motion recorder configuration.
*/
- (instancetype)initWithFrequency:(double)frequency NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)frequency NS_DESIGNATED_INITIALIZER;
/**
Returns a new device motion recorder configuration initialized from data in the given unarchiver.
@param aDecoder Coder from which to initialize the device motion recorder configuration.
@return A new device motion recorder configuration.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@end
/**
The `ORKPedometerRecorderConfiguration` class represents a configuration
that records pedometer data during an active step.
@@ -228,17 +270,30 @@ ORK_CLASS_AVAILABLE
/**
Returns an initialized pedometer recorder configuration.
This method is the designated initializer.
Note that the recorder instantiates a `CMPedometer` object, so no parameters are required.
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
The recorder instantiates a `CMPedometer` object, so no additional parameters besides
the identifier are required.
This method is the designated initializer.
@param identifier The unique identifier of the recorder configuration.
@return An initialized pedometer recorder configuration.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER;
/**
Returns a new pedometer recorder configuration initialized from data in the given unarchiver.
@param aDecoder Coder from which to initialize the pedometer recorder configuration.
@return A new pedometer recorder configuration.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@end
/**
The `ORKLocationRecorderConfiguration` class represents a configuration
that records location data during an active step.
@@ -255,6 +310,8 @@ ORK_CLASS_AVAILABLE
To use a recorder, include its configuration in the `recorderConfigurations` property
of an `ORKActiveStep` object, include that step in a task, and present it with
a task view controller.
No additional parameters besides the identifier are required.
*/
ORK_CLASS_AVAILABLE
@interface ORKLocationRecorderConfiguration : ORKRecorderConfiguration
@@ -263,10 +320,20 @@ ORK_CLASS_AVAILABLE
Returns an initialized location recorder configuration.
This method is the designated initializer.
@param identifier The unique identifier of the recorder configuration.
No parameters are required.
@return An initialized location recorder configuration.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER;
/**
Returns a new location recorder configuration initialized from data in the given unarchiver.
@param aDecoder Coder from which to initialize the location recorder configuration.
@return A new location recorder configuration.
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@end
@@ -294,12 +361,21 @@ ORK_CLASS_AVAILABLE
This method is the designated initializer.
@param identifier The unique identifier of the recorder configuration.
@param quantityType The quantity type that should be collected during the active task.
@param unit The unit for the data that should be collected and serialized.
@return An initialized health quantity type recorder configuration.
*/
- (instancetype)initWithHealthQuantityType:(HKQuantityType *)quantityType unit:(HKUnit *)unit NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier healthQuantityType:(HKQuantityType *)quantityType unit:(HKUnit *)unit NS_DESIGNATED_INITIALIZER;
/**
Returns a new health quantity type recorder configuration initialized from data in the given unarchiver.
@param aDecoder Coder from which to initialize the health quantity type recorder configuration.
@return A new health quantity type recorder configuration.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
/**
@@ -307,7 +383,6 @@ ORK_CLASS_AVAILABLE
*/
@property (nonatomic, readonly, copy) HKQuantityType *quantityType;
/**
The unit in which to serialize the data from HealthKit. (read-only)
*/
@@ -315,6 +390,7 @@ ORK_CLASS_AVAILABLE
@end
/**
The `ORKRecorderDelegate` protocol defines methods that the delegate of an `ORKRecorder` object should use to handle errors and log the
completed results.
@@ -346,6 +422,7 @@ need to implement it.
@end
/**
A recorder is the runtime companion to an `ORKRecorderConfiguration` object, and is
usually generated by one.
@@ -369,12 +446,27 @@ need to implement it.
ORK_CLASS_AVAILABLE
@interface ORKRecorder : NSObject
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/// @name Configuration
@property (nonatomic, weak, nullable) id<ORKRecorderDelegate> delegate;
/**
A short string that uniquely identifies the recorder (usually assigned by the recorder configuration).
The identifier is reproduced in the results of a recorder created from this configuration. In fact, the only way to link a result
(an `ORKFileResult` object) to the recorder that generated it is to look at the value of
`identifier`. To accurately identify recorder results, you need to ensure that recorder identifiers
are unique within each step.
In some cases, it can be useful to link the recorder identifier to a unique identifier in a
database; in other cases, it can make sense to make the identifier human
readable.
*/
@property (nonatomic, copy, readonly) NSString *identifier;
/**
The step that produced this recorder, configured during initialization.
*/
@@ -425,4 +517,3 @@ ORK_CLASS_AVAILABLE
@end
NS_ASSUME_NONNULL_END
+55 -76
View File
@@ -1,5 +1,6 @@
/*
Copyright (c) 2015, Apple Inc. All rights reserved.
Copyright (c) 2015, Ricardo Sánchez-Sáez.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@@ -36,27 +37,36 @@
#import "ORKDataLogger.h"
#import "ORKDefines_Private.h"
@implementation ORKRecorderConfiguration
- (instancetype)ork_init
{
return [super init];
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super init];
if (self) {
if (nil == identifier) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"identifier cannot be nil." userInfo:nil];
}
_identifier = [identifier copy];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
return [super init];
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
ORK_DECODE_OBJ_CLASS(aDecoder, identifier, NSString);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
- (void)encodeWithCoder:(NSCoder *)aCoder {
ORK_ENCODE_OBJ(aCoder, identifier);
}
- (BOOL)isEqual:(id)object {
if ([self class] != [object class]) {
return NO;
}
return YES;
}
@@ -64,17 +74,14 @@
return 0;
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory
{
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return nil;
}
- (NSSet *)requestedHealthKitTypesForReading {
return nil;
}
@@ -82,30 +89,26 @@
return ORKPermissionNone;
}
@end
@implementation ORKRecorder
{
@implementation ORKRecorder {
UIBackgroundTaskIdentifier _backgroundTask;
NSUUID *_recorderUUID;
}
- (instancetype)init
{
- (instancetype)init {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use designated initializer" userInfo:nil];
}
- (instancetype)ork_init
{
return [super init];
}
- (instancetype)initWithStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory;
{
- (instancetype)initWithIdentifier:(NSString *)identifier step:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
self = [super init];
if (self)
{
if (self) {
if (nil == identifier) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"identifier cannot be nil." userInfo:nil];
}
_identifier = [identifier copy];
_outputDirectory = outputDirectory;
self.step = step;
_backgroundTask = NSNotFound;
@@ -115,91 +118,70 @@
}
- (void)viewController:(UIViewController *)viewController willStartStepWithView:(UIView *)view {
}
- (void)start
{
if (self.continuesInBackground)
{
- (void)start {
if (self.continuesInBackground) {
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier oldTask = _backgroundTask;
_backgroundTask = [app beginBackgroundTaskWithName:[NSString stringWithFormat:@"%@.%p",NSStringFromClass([self class]),self] expirationHandler:^{
_backgroundTask = [app beginBackgroundTaskWithName:[NSString stringWithFormat:@"%@.%p",NSStringFromClass([self class]),self]
expirationHandler:^{
[self stop];
}];
if (oldTask != NSNotFound)
{
if (oldTask != NSNotFound) {
[app endBackgroundTask:oldTask];
}
}
self.startDate = [NSDate date];
}
- (void)stop
{
- (void)stop {
[self finishRecordingWithError:nil];
[self reset];
}
- (void)finishRecordingWithError:(NSError *)error
{
- (void)finishRecordingWithError:(NSError *)error {
// NOTE. This method may be called multiple times (once when someone tries
// to finish, and another time with -stop is actually called.
if (error)
{
if (error) {
// ALWAYS report errors to the delegate, even if we think we're finished already
id<ORKRecorderDelegate> localDelegate = self.delegate;
if (localDelegate && [localDelegate respondsToSelector:@selector(recorder:didFailWithError:)])
{
if (localDelegate && [localDelegate respondsToSelector:@selector(recorder:didFailWithError:)]) {
[localDelegate recorder:self didFailWithError:error];
}
[self reset];
}
if (_backgroundTask != NSNotFound)
{
if (_backgroundTask != NSNotFound) {
// End the background task asynchronously, so whatever we're doing cleaning up the recorder has a chance to complete.
UIBackgroundTaskIdentifier ident = _backgroundTask;
UIBackgroundTaskIdentifier identifier = _backgroundTask;
_backgroundTask = NSNotFound;
// Hold the background task for a little extra to give time for the next step to kick in,
// if it is an automatic transition.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] endBackgroundTask:ident];
[[UIApplication sharedApplication] endBackgroundTask:identifier];
});
}
}
- (NSURL *)recordingDirectoryURL
{
- (NSURL *)recordingDirectoryURL {
if (! _outputDirectory) {
return nil;
}
return [NSURL fileURLWithPath:[_outputDirectory.path stringByAppendingPathComponent:[NSString stringWithFormat:@"recorder-%@",[_recorderUUID UUIDString]]]];
}
- (NSString *)recorderType
{
- (NSString *)recorderType {
return @"recorder";
}
- (NSString *)logName
{
return [NSString stringWithFormat:@"%@_%@", [self recorderType],self.step.identifier];
- (NSString *)logName {
return [NSString stringWithFormat:@"%@_%@", [self recorderType],self.identifier];
}
- (ORKDataLogger *)makeJSONDataLoggerWithError:(NSError * __autoreleasing *)error
{
- (ORKDataLogger *)makeJSONDataLoggerWithError:(NSError * __autoreleasing *)error {
NSURL *workingDir = [self recordingDirectoryURL];
if (! workingDir) {
if (error) {
@@ -211,8 +193,8 @@
return nil;
}
NSString *ident = [self logName];
NSString *logName = [ident stringByReplacingOccurrencesOfString:@"-" withString:@"_"];
NSString *identifier = [self logName];
NSString *logName = [identifier stringByReplacingOccurrencesOfString:@"-" withString:@"_"];
// Class B data protection for temporary file during active task logging.
ORKDataLogger *logger = [[ORKDataLogger alloc] initWithDirectory:workingDir logName:logName formatter:[ORKJSONLogFormatter new] delegate:nil];
@@ -221,8 +203,7 @@
return logger;
}
- (void)reset
{
- (void)reset {
_recorderUUID = [NSUUID UUID];
}
@@ -235,9 +216,9 @@
}
- (void)applyFileProtection:(ORKFileProtectionMode)fileProtection toFileAtURL:(NSURL *)url {
NSFileManager *fm = [NSFileManager defaultManager];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
if (! [fm setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(fileProtection)} ofItemAtPath:[url path] error:&error]) {
if (! [fileManager setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(fileProtection)} ofItemAtPath:[url path] error:&error]) {
ORK_Log_Debug(@"Error setting %@ on %@: %@", ORKFileProtectionFromMode(fileProtection), url, error);
}
}
@@ -247,7 +228,7 @@
id<ORKRecorderDelegate> localDelegate = self.delegate;
if (fileUrl && !error) {
if (localDelegate && [localDelegate respondsToSelector:@selector(recorder:didCompleteWithResult:)]) {
ORKFileResult *result = [[ORKFileResult alloc] initWithIdentifier:(NSString *__nonnull)self.step.identifier];
ORKFileResult *result = [[ORKFileResult alloc] initWithIdentifier:self.identifier];
result.contentType = [self mimeType];
result.fileURL = fileUrl;
result.userInfo = [self userInfo];
@@ -259,8 +240,7 @@
[self reset];
}
} else {
if (! error)
{
if (! error) {
error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFileReadNoSuchFileError
userInfo:@{NSLocalizedDescriptionKey:ORKLocalizedString(@"ERROR_RECORDER_NO_DATA", nil)}];
@@ -270,4 +250,3 @@
}
@end
@@ -31,22 +31,18 @@
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKDataLogger;
@interface ORKRecorderConfiguration()
- (instancetype)ork_init;
@interface ORKRecorderConfiguration ()
@end
@interface ORKRecorder ()
- (instancetype)ork_init;
@property (nonatomic, strong, nullable) ORKStep *step;
@property (nonatomic, strong, nullable) ORKRecorderConfiguration *configuration;
+56 -8
View File
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKStep;
@@ -41,18 +43,45 @@ NS_ASSUME_NONNULL_BEGIN
It is currently considered private, and is not used in any of the active tasks.
*/
ORK_CLASS_AVAILABLE
@interface ORKTouchRecorderConfiguration: ORKRecorderConfiguration
@interface ORKTouchRecorderConfiguration : ORKRecorderConfiguration
- (instancetype)init;
/**
Returns an initialized touch recorder configuration.
This method is the designated initializer.
@param identifier The unique identifier of the recorder configuration.
@return An initialized touch recorder configuration.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER;
/**
Returns a new touch recorder configuration initialized from data in the given unarchiver.
@param aDecoder Coder from which to initialize the touch recorder configuration.
@return A new touch recorder configuration.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@end
@interface ORKRecorder()
- (instancetype)initWithStep:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory;
@interface ORKRecorder ()
/**
Returns an initialized recorder.
This method is the designated initializer.
@param identifier The unique identifier of the recorder.
@param step The step for which this recorder is being created.
@param outputDirectory The directory in which all output file data should be written (if producing `ORKFileResult` instances).
@return An initialized recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier step:(nullable ORKStep *)step outputDirectory:(nullable NSURL *)outputDirectory;
/**
A preparation step to provide viewController and view before record starting.
@@ -87,7 +116,27 @@ ORK_CLASS_AVAILABLE
@end
@interface ORKRecorderConfiguration()
@interface ORKRecorderConfiguration ()
/**
Returns an initialized recorder configuration.
This method is the designated initializer.
@param identifier The unique identifier of the recorder configuration.
@return An initialized recorder configuration.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER;
/**
Returns a new recorder configuration initialized from data in the given unarchiver.
@param aDecoder Coder from which to initialize the recorder configuration.
@return A new recorder configuration.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
/**
Returns the permission mask indicating the permissions required for this configuration.
@@ -96,7 +145,6 @@ ORK_CLASS_AVAILABLE
*/
- (ORKPermissionMask)requestedPermissionMask;
@end
NS_ASSUME_NONNULL_END
+6 -7
View File
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <Foundation/Foundation.h>
@@ -36,7 +37,6 @@
A game consists of a subset of a permutation of the integers [0 .. gameSize-1],
which represent the sequence of targets that should be tapped.
*/
@interface ORKSpatialSpanGame : NSObject
@@ -64,12 +64,12 @@
/**
Enumerates the sequence, calling the block once for each element.
@param handler The block to be called for each element in the sequence. The `handler` block takes the following parameters:
@param handler The block to be called for each element in the sequence. The `handler` block takes the following parameters:
`step` The step in the sequence. The step starts at 0 and increments by one on each call.
`tileIndex` The index in [ 0 .. gameSize ] that corresponds to the step's element of the sequence.
`isLastStep` A Boolean value that indicates if this is the last step in the sequence.
`stop` A Boolean value that indicates if the enumeration should be terminated (pass `NO` to terminate the enumeration).
`step` The step in the sequence. The step starts at 0 and increments by one on each call.
`tileIndex` The index in [ 0 .. gameSize ] that corresponds to the step's element of the sequence.
`isLastStep` A Boolean value that indicates if this is the last step in the sequence.
`stop` A Boolean value that indicates if the enumeration should be terminated (pass `NO` to terminate the enumeration).
*/
- (void)enumerateSequenceWithHandler:(void(^)(NSInteger step, NSInteger tileIndex, BOOL isLastStep, BOOL *stop))handler;
@@ -77,5 +77,4 @@
/// Returns the value of the specified step in the sequence.
- (NSInteger)tileIndexForStep:(NSInteger)step;
@end
+3 -5
View File
@@ -28,10 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKSpatialSpanGame.h"
@implementation ORKSpatialSpanGame
{
@implementation ORKSpatialSpanGame {
NSInteger *_sequence;
}
@@ -81,13 +82,10 @@
if (_sequence == NULL) {
self = nil;
}
}
return self;
}
/// Step parameter is the step in the sequence; tileIndex is the value of that step of the sequence.
- (void)enumerateSequenceWithHandler:(void(^)(NSInteger step, NSInteger tileIndex, BOOL isLastStep, BOOL *stop))handler {
BOOL stop = NO;
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <Foundation/Foundation.h>
#import "ORKSpatialSpanTargetView.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKSpatialSpanGame;
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKSpatialSpanGameState.h"
#import "ORKSpatialSpanGame.h"
@@ -37,7 +38,6 @@
ORKSpatialSpanTargetState *_states;
}
- (instancetype)initWithGame:(ORKSpatialSpanGame *)game {
self = [super init];
if (self) {
@@ -59,7 +59,6 @@
}
}
- (void)reset {
const NSInteger gameSize = [_game gameSize];
for (NSInteger tileIndex = 0; tileIndex < gameSize; tileIndex++) {
@@ -98,7 +97,6 @@
return correct ? ORKSpatialSpanResultCorrect : ORKSpatialSpanResultIncorrect;
}
- (NSInteger)currentStepIndex {
return [_plays count];
}
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKCustomStepView_Internal.h"
#import "ORKSpatialSpanTargetView.h"
NS_ASSUME_NONNULL_BEGIN
typedef struct {
@@ -46,6 +48,7 @@ typedef struct {
@end
@interface ORKSpatialSpanMemoryGameView : UIView <ORKSpatialSpanTargetViewDelegate>
@property (nonatomic, weak, nullable) id<ORKSpatialSpanMemoryGameViewDelegate> delegate;
@@ -68,7 +71,7 @@ typedef struct {
@interface ORKSpatialSpanMemoryContentView : ORKActiveStepCustomView
@property (nonatomic, readonly, strong) ORKSpatialSpanMemoryGameView *gameView;
@property (nonatomic, strong, readonly) ORKSpatialSpanMemoryGameView *gameView;
@property (nonatomic, assign, getter=isFooterHidden) BOOL footerHidden;
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKSpatialSpanMemoryContentView.h"
#import "ORKSpatialSpanTargetView.h"
#import "ORKActiveStepQuantityView.h"
@@ -122,20 +123,20 @@
- (void)layoutSubviews {
[super layoutSubviews];
CGRect bds = [self bounds];
CGFloat gridItemEdgeLength = ORKFloorToViewScale(MIN(bds.size.width / _gridSize.width, bds.size.height / _gridSize.height), self);
CGRect bounds = [self bounds];
CGFloat gridItemEdgeLength = ORKFloorToViewScale(MIN(bounds.size.width / _gridSize.width, bounds.size.height / _gridSize.height), self);
gridItemEdgeLength = MIN(gridItemEdgeLength, 114);
CGSize gridItemSize = (CGSize){gridItemEdgeLength, gridItemEdgeLength};
CGPoint centeringOffset = CGPointZero;
centeringOffset.x = 0.5*(bds.size.width - (gridItemSize.width * _gridSize.width));
centeringOffset.y = 0.5*(bds.size.height - (gridItemSize.height * _gridSize.height));
centeringOffset.x = 0.5*(bounds.size.width - (gridItemSize.width * _gridSize.width));
centeringOffset.y = 0.5*(bounds.size.height - (gridItemSize.height * _gridSize.height));
NSInteger tileIndex = 0;
for (NSInteger x = 0; x < _gridSize.width; x++) {
for (NSInteger y = 0; y < _gridSize.height; y++) {
ORKSpatialSpanTargetView *targetView = [_tileViews objectAtIndex:tileIndex];
ORKSpatialSpanTargetView *targetView = _tileViews[tileIndex];
CGPoint origin = (CGPoint){.x = ORKFloorToViewScale(centeringOffset.x + x * gridItemSize.width, self),
.y = ORKFloorToViewScale(centeringOffset.y + y * gridItemSize.height, self)};
@@ -147,12 +148,12 @@
}
- (void)setState:(ORKSpatialSpanTargetState)state forTileIndex:(NSInteger)tileIndex animated:(BOOL)animated {
ORKSpatialSpanTargetView *view = [_tileViews objectAtIndex:tileIndex];
ORKSpatialSpanTargetView *view = _tileViews[tileIndex];
[view setState:state animated:animated];
}
- (ORKSpatialSpanTargetState)stateForTileIndex:(NSInteger)tileIndex {
return [(ORKSpatialSpanTargetView *)[_tileViews objectAtIndex:tileIndex] state];
return [(ORKSpatialSpanTargetView *)_tileViews[tileIndex] state];
}
#pragma mark Accessibility
@@ -163,6 +164,7 @@
@end
@implementation ORKSpatialSpanMemoryContentView {
ORKQuantityPairView *_quantityPairView;
ORKNavigationContainerView *_continueView;
@@ -219,7 +221,6 @@
[self countView].backgroundColor = [[UIColor purpleColor] colorWithAlphaComponent:0.2];
#endif
[self setNeedsUpdateConstraints];
}
return self;
@@ -259,7 +260,7 @@
- (void)updateMargins {
self.layoutMargins = (UIEdgeInsets){.left=ORKStandardMarginForView(self),.right=ORKStandardMarginForView(self)};
self.layoutMargins = (UIEdgeInsets){.left=ORKStandardHorizMarginForView(self), .right=ORKStandardHorizMarginForView(self)};
_quantityPairView.layoutMargins = self.layoutMargins;
}
@@ -277,22 +278,57 @@
NSDictionary *views = NSDictionaryOfVariableBindings(_gameView, _quantityPairView, _continueView);
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=0)-[_gameView][_quantityPairView]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
NSLayoutConstraint *c1 = [NSLayoutConstraint constraintWithItem:_gameView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:1000];
c1.priority = UILayoutPriorityDefaultLow-1;
[constraints addObject:c1];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=0)-[_gameView][_quantityPairView]|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_gameView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:1000.0];
constraint1.priority = UILayoutPriorityDefaultLow-1;
[constraints addObject:constraint1];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_gameView]-|" options:(NSLayoutFormatOptions)0 metrics:nil views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_gameView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_quantityPairView]|" options:(NSLayoutFormatOptions)0 metrics:nil views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_continueView]|" options:(NSLayoutFormatOptions)0 metrics:nil views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_continueView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_quantityPairView attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_continueView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:_quantityPairView attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_quantityPairView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_continueView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_continueView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_quantityPairView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_continueView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:_quantityPairView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:10000];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
maxWidthConstraint.priority = UILayoutPriorityRequired-1;
[constraints addObject:maxWidthConstraint];
[NSLayoutConstraint activateConstraints:constraints];
_constraints = constraints;
@@ -300,6 +336,4 @@
[super updateConstraints];
}
@end
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@@ -28,11 +28,13 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKSpatialSpanMemoryStep.h"
#import "ORKSpatialSpanMemoryStepViewController.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
@implementation ORKSpatialSpanMemoryStep
+ (Class)stepViewControllerClass {
@@ -41,13 +43,14 @@
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
self.shouldStartTimerAutomatically = YES;
self.shouldContinueOnFinish = YES;
if (self) {
self.shouldStartTimerAutomatically = YES;
self.shouldContinueOnFinish = YES;
}
return self;
}
- (instancetype)copyWithZone:(NSZone *)zone
{
- (instancetype)copyWithZone:(NSZone *)zone {
ORKSpatialSpanMemoryStep *step = [super copyWithZone:zone];
step.initialSpan = self.initialSpan;
step.minimumSpan = self.minimumSpan;
@@ -62,7 +65,6 @@
}
- (void)validateParameters {
[super validateParameters];
NSInteger const ORKSpatialSpanMemoryTaskMinimumInitialSpan = 2;
@@ -72,53 +74,45 @@
NSInteger const ORKSpatialSpanMemoryTaskMinimumMaxTests = 1;
NSInteger const ORKSpatialSpanMemoryTaskMinimumMaxConsecutiveFailures = 1;
if ( self.initialSpan < ORKSpatialSpanMemoryTaskMinimumInitialSpan)
{
if ( self.initialSpan < ORKSpatialSpanMemoryTaskMinimumInitialSpan) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"initialSpan can not be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumInitialSpan)]
userInfo:nil];
}
if ( self.minimumSpan > self.initialSpan)
{
if ( self.minimumSpan > self.initialSpan) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"initialSpan can not be less than minimumSpan." userInfo:nil];
}
if ( self.initialSpan > self.maximumSpan)
{
if ( self.initialSpan > self.maximumSpan) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"maximumSpan can not be less than initialSpan." userInfo:nil];
}
if ( self.maximumSpan > ORKSpatialSpanMemoryTaskMaximumSpan)
{
if ( self.maximumSpan > ORKSpatialSpanMemoryTaskMaximumSpan) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"maximumSpan can not be more than %@.", @(ORKSpatialSpanMemoryTaskMaximumSpan)]
userInfo:nil];
}
if (self.playSpeed < ORKSpatialSpanMemoryTaskMinimumPlaySpeed)
{
if (self.playSpeed < ORKSpatialSpanMemoryTaskMinimumPlaySpeed) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"playSpeed can not be shorter than %@ seconds.", @(ORKSpatialSpanMemoryTaskMinimumPlaySpeed)]
userInfo:nil];
}
if (self.playSpeed > ORKSpatialSpanMemoryTaskMaximumPlaySpeed)
{
if (self.playSpeed > ORKSpatialSpanMemoryTaskMaximumPlaySpeed) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"playSpeed can not be longer than %@ seconds.", @(ORKSpatialSpanMemoryTaskMaximumPlaySpeed)]
userInfo:nil];
}
if (self.maxTests < ORKSpatialSpanMemoryTaskMinimumMaxTests)
{
if (self.maxTests < ORKSpatialSpanMemoryTaskMinimumMaxTests) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"maxTests can not be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumMaxTests)]
userInfo:nil];
}
if (self.maxConsecutiveFailures < ORKSpatialSpanMemoryTaskMinimumMaxConsecutiveFailures)
{
if (self.maxConsecutiveFailures < ORKSpatialSpanMemoryTaskMinimumMaxConsecutiveFailures) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"maxConsecutiveFailures can not be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumMaxConsecutiveFailures)]
userInfo:nil];
@@ -129,11 +123,9 @@
return NO;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self)
{
if (self) {
ORK_DECODE_INTEGER(aDecoder, initialSpan);
ORK_DECODE_INTEGER(aDecoder, minimumSpan);
ORK_DECODE_INTEGER(aDecoder, maximumSpan);
@@ -147,8 +139,7 @@
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_INTEGER(aCoder, initialSpan);
ORK_ENCODE_INTEGER(aCoder, minimumSpan);
@@ -161,12 +152,10 @@
ORK_ENCODE_OBJ(aCoder, customTargetPluralName);
}
+ (BOOL)supportsSecureCoding
{
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
@@ -179,14 +168,11 @@
(self.maxTests == castObject.maxTests) &&
(self.maxConsecutiveFailures == castObject.maxConsecutiveFailures) &&
(ORKEqualObjects(self.customTargetPluralName, castObject.customTargetPluralName)) &&
(self.requireReversal == castObject.requireReversal)) ;
(self.requireReversal == castObject.requireReversal));
}
- (BOOL)allowsBackNavigation {
return NO;
}
@end
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit_Private.h>
/**
View controller corresponding to `ORKSpatialSpanMemoryStep`.
*/
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKSpatialSpanMemoryStepViewController.h"
#import "ORKHelpers.h"
#import "ORKActiveStep_Internal.h"
@@ -45,6 +46,7 @@
#import "ORKSpatialSpanMemoryStep.h"
#import "ORKActiveStepView.h"
static const NSTimeInterval kMemoryGameActivityTimeout = 20;
typedef NS_ENUM(NSInteger, ORKSpatialSpanStepState) {
@@ -83,6 +85,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
@end
@implementation ORKState;
+ (ORKState *)stateWithState:(NSInteger)state entryHandler:(_ORKStateHandler)entryHandler exitHandler:(_ORKStateHandler)exitHandler context:(id)context {
@@ -94,15 +97,15 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
return s;
}
@end
@interface ORKSpatialSpanMemoryStepViewController () <ORKSpatialSpanMemoryGameViewDelegate>
@end
@interface ORKSpatialSpanMemoryStepViewController() <ORKSpatialSpanMemoryGameViewDelegate>
@end
@implementation ORKSpatialSpanMemoryStepViewController
{
@implementation ORKSpatialSpanMemoryStepViewController {
ORKSpatialSpanMemoryContentView *_contentView;
ORKState *_state;
NSDictionary *_states;
@@ -126,7 +129,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
NSTimer *_playbackTimer;
NSTimer *_activityTimer;
}
- (ORKSpatialSpanMemoryStep *)spatialSpanStep {
@@ -134,7 +136,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
}
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = YES;
@@ -144,7 +145,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
#pragma mark Overrides
- (void)viewDidLoad {
[super viewDidLoad];
@@ -154,7 +154,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
_contentView.gameView.delegate = self;
self.activeStepView.activeCustomView = _contentView;
self.activeStepView.stepViewFillsAvailableSpace = NO;
self.activeStepView.minimumStepHeaderHeight = ORKGetMetricForScreenType(ORKScreenMetricMinimumStepHeaderHeightForMemoryGame, ORKGetScreenTypeForWindow(self.view.window));
self.activeStepView.minimumStepHeaderHeight = ORKGetMetricForWindow(ORKScreenMetricMinimumStepHeaderHeightForMemoryGame, self.view.window);
[self resetUI];
@@ -162,7 +162,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
[self.activeStepView addGestureRecognizer:tapGestureRecognizer];
}
- (void)stepDidChange {
[super stepDidChange];
@@ -179,6 +178,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
[self transitionToState:ORKSpatialSpanStepStatePlayback];
}
- (void)suspend {
[super suspend];
switch (_state.state) {
@@ -190,26 +190,27 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
break;
}
}
- (void)resume {
[super resume];
}
- (void)finish {
[super finish];
[self transitionToState:ORKSpatialSpanStepStateStopped];
}
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
ORKStepResult *stepResult = [super result];
// "Now" is the end time of the result, which is either actually now,
// or the last time we were in the responder chain.
NSDate *now = sResult.endDate;
NSDate *now = stepResult.endDate;
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
NSMutableArray *results = [NSMutableArray arrayWithArray:stepResult.results];
ORKSpatialSpanMemoryResult *memoryResult = [[ORKSpatialSpanMemoryResult alloc] initWithIdentifier:(NSString *__nonnull)self.step.identifier];
memoryResult.startDate = sResult.startDate;
ORKSpatialSpanMemoryResult *memoryResult = [[ORKSpatialSpanMemoryResult alloc] initWithIdentifier:self.step.identifier];
memoryResult.startDate = stepResult.startDate;
memoryResult.endDate = now;
NSMutableArray *records = [NSMutableArray new];
@@ -224,8 +225,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
score += record.score;
if (record.gameStatus != ORKSpatialSpanMemoryGameStatusSuccess)
{
if (record.gameStatus != ORKSpatialSpanMemoryGameStatusSuccess) {
numberOfFailures++;
}
}
@@ -237,9 +237,9 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
memoryResult.gameRecords = [records copy];
[results addObject:memoryResult];
sResult.results = [results copy];
stepResult.results = [results copy];
return sResult;
return stepResult;
}
#pragma mark UpdateGameRecord
@@ -249,7 +249,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
}
- (void)createGameRecord {
if (_gameRecords == nil) {
_gameRecords = [NSMutableArray new];
}
@@ -268,8 +267,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
_lastRoundScore = _score;
}
- (void)updateGameRecordTargetRects
{
- (void)updateGameRecordTargetRects {
ORKSpatialSpanMemoryGameRecord *record = [self currentGameRecord];
NSArray *tileViews = _contentView.gameView.tileViews;
NSMutableArray *targetRects = [NSMutableArray new];
@@ -281,21 +279,18 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
NSAssert(tileViews.count == 0 || tileViews.count == record.gameSize, nil);
}
- (void)updateGameRecordOnStartingGamePlay
{
- (void)updateGameRecordOnStartingGamePlay {
_gameStartTime = CACurrentMediaTime();
}
- (void)handleUserTap:(UITapGestureRecognizer *)tapRecognizer
{
- (void)handleUserTap:(UITapGestureRecognizer *)tapRecognizer {
if (_state.state != ORKSpatialSpanStepStateGameplay) {
return;
}
[self updateGameRecordOnTouch:-1 location:[tapRecognizer locationInView: self.view]];
}
- (void)updateGameRecordOnTouch:(NSInteger)targetIndex location:(CGPoint)location
{
- (void)updateGameRecordOnTouch:(NSInteger)targetIndex location:(CGPoint)location {
ORKSpatialSpanMemoryGameTouchSample *sample = [ORKSpatialSpanMemoryGameTouchSample new];
sample.timestamp = CACurrentMediaTime() - _gameStartTime;
@@ -321,35 +316,28 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
[sampleArray addObject:sample];
record.touchSamples = [sampleArray copy];
}
- (void)updateGameRecordOnSuccess
{
- (void)updateGameRecordOnSuccess {
[self currentGameRecord].gameStatus = ORKSpatialSpanMemoryGameStatusSuccess;
}
- (void)updateGameRecordOnFailure
{
- (void)updateGameRecordOnFailure {
[self currentGameRecord].gameStatus = ORKSpatialSpanMemoryGameStatusFailure;
}
- (void)updateGameRecordOnTimeout
{
- (void)updateGameRecordOnTimeout {
[self currentGameRecord].gameStatus = ORKSpatialSpanMemoryGameStatusTimeout;
}
- (void)updateGameRecordScore
{
- (void)updateGameRecordScore {
[self currentGameRecord].score = _score - _lastRoundScore;
}
- (void)updateGameRecordOnPause
{
- (void)updateGameRecordOnPause {
[self currentGameRecord].gameStatus = ORKSpatialSpanMemoryGameStatusUnknown;
}
#pragma mark ORKSpatialSpanStepStateInitial
- (ORKGridSize)gridSizeForSpan:(NSInteger)span {
@@ -397,10 +385,8 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
[self createGameRecord];
[self resetUI];
}
#pragma mark ORKSpatialSpanStepStatePlayback
- (void)applyTargetState:(ORKSpatialSpanTargetState)targetState toSequenceIndex:(NSInteger)index duration:(NSTimeInterval)duration {
@@ -454,7 +440,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
[self.activeStepView updateTitle:title text:nil];
[_contentView.gameView resetTilesAnimated:NO];
_playbackTimer = [NSTimer scheduledTimerWithTimeInterval:step.playSpeed target:self selector:@selector(playbackNextItem) userInfo:nil repeats:YES];
@@ -521,7 +506,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
_activityTimer = nil;
}
- (void)gameView:(ORKSpatialSpanMemoryGameView *)gameView didTapTileWithIndex:(NSInteger)tileIndex recognizer:(UITapGestureRecognizer *)recognizer {
if (_state.state != ORKSpatialSpanStepStateGameplay) {
return;
@@ -533,6 +517,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
switch (result) {
case ORKSpatialSpanResultIgnore:
break;
case ORKSpatialSpanResultCorrect:
[gameView setState:ORKSpatialSpanTargetStateCorrect forTileIndex:tileIndex animated:YES];
NSInteger stepIndex = [_currentGameState currentStepIndex];
@@ -544,9 +529,8 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
if ([_currentGameState isComplete]) {
[self transitionToState:ORKSpatialSpanStepStateSuccess];
}
break;
case ORKSpatialSpanResultIncorrect:
[gameView setState:ORKSpatialSpanTargetStateIncorrect forTileIndex:tileIndex animated:YES];
[self transitionToState:ORKSpatialSpanStepStateFailed];
@@ -557,7 +541,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
#pragma mark ORKSpatialSpanStepStateSuccess
- (void)updateGameCountersForSuccess:(BOOL)success {
ORKSpatialSpanMemoryStep *step = [self spatialSpanStep];
if (success) {
NSInteger sequenceLength = [_currentGameState.game sequenceLength];
@@ -573,7 +556,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
}
- (void)continueAction {
ORKSpatialSpanMemoryStep *step = [self spatialSpanStep];
if (_gamesCounter < step.maxTests && _consecutiveGamesFailed < step.maxConsecutiveFailures) {
// Generate a new game
@@ -585,7 +567,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
}
- (void)showSuccess {
[self updateGameRecordOnSuccess];
[self updateGameCountersForSuccess:YES];
@@ -593,7 +574,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
return;
}
[self.activeStepView updateTitle:ORKLocalizedString(@"MEMORY_GAME_COMPLETE_TITLE", nil) text:ORKLocalizedString(@"MEMORY_GAME_COMPLETE_MESSAGE", nil)];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.75 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@@ -603,16 +583,13 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
#pragma mark ORKSpatialSpanStepStateFailed
- (void)tryAgainAction {
// Restart with a new, shorter game
[self transitionToState:ORKSpatialSpanStepStateRestart];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
}
- (BOOL)finishIfCompletedGames {
ORKSpatialSpanMemoryStep *step = [self spatialSpanStep];
if (_consecutiveGamesFailed >= step.maxConsecutiveFailures || _gamesCounter >= step.maxTests) {
[self transitionToState:ORKSpatialSpanStepStateComplete];
@@ -622,7 +599,6 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
}
- (void)showFailed {
[self updateGameRecordOnFailure];
[self updateGameCountersForSuccess:NO];
@@ -631,14 +607,12 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
}
[self.activeStepView updateTitle:ORKLocalizedString(@"MEMORY_GAME_FAILED_TITLE", nil) text:ORKLocalizedString(@"MEMORY_GAME_FAILED_MESSAGE", nil)];
_contentView.buttonItem = [[UIBarButtonItem alloc] initWithTitle:ORKLocalizedString(@"BUTTON_NEXT", nil) style:UIBarButtonItemStylePlain target:self action:@selector(tryAgainAction)];
}
#pragma mark ORKSpatialSpanStepStateTimeout
- (void)showTimeout {
[self updateGameRecordOnTimeout];
[self updateGameCountersForSuccess:NO];
@@ -686,37 +660,36 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
_contentView.buttonItem = [[UIBarButtonItem alloc] initWithTitle:ORKLocalizedString(@"BUTTON_NEXT", nil) style:UIBarButtonItemStylePlain target:self action:@selector(continueAction)];
}
#pragma mark State machine
- (void)initializeStates {
NSMutableDictionary *states = [NSMutableDictionary dictionary];
states[@(ORKSpatialSpanStepStateInitial)] = [ORKState stateWithState:ORKSpatialSpanStepStateInitial
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this resetGameAndUI];
}
exitHandler:nil context:self];
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this resetGameAndUI];
}
exitHandler:nil context:self];
states[@(ORKSpatialSpanStepStatePlayback)] = [ORKState stateWithState:ORKSpatialSpanStepStatePlayback
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this startPlayback];
}
exitHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this finishPlayback];
} context:self];
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this startPlayback];
}
exitHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this finishPlayback];
} context:self];
states[@(ORKSpatialSpanStepStateGameplay)] = [ORKState stateWithState:ORKSpatialSpanStepStateGameplay
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this startGameplay];
}
exitHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this finishGameplay];
} context:self];
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this startGameplay];
}
exitHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this finishGameplay];
} context:self];
states[@(ORKSpatialSpanStepStateSuccess)] = [ORKState stateWithState:ORKSpatialSpanStepStateSuccess
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this showSuccess];
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this showSuccess];
}
exitHandler:nil context:self];
@@ -727,31 +700,31 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
exitHandler:nil context:self];
states[@(ORKSpatialSpanStepStateTimeout)] = [ORKState stateWithState:ORKSpatialSpanStepStateTimeout
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this showTimeout];
}
exitHandler:nil context:self];
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this showTimeout];
}
exitHandler:nil context:self];
states[@(ORKSpatialSpanStepStateRestart)] = [ORKState stateWithState:ORKSpatialSpanStepStateRestart
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this doRestart];
}
exitHandler:nil context:self];
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this doRestart];
}
exitHandler:nil context:self];
states[@(ORKSpatialSpanStepStateComplete)] = [ORKState stateWithState:ORKSpatialSpanStepStateComplete
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this showComplete];
} exitHandler:nil context:self];
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this showComplete];
} exitHandler:nil context:self];
states[@(ORKSpatialSpanStepStateStopped)] = [ORKState stateWithState:ORKSpatialSpanStepStateStopped
entryHandler:nil
exitHandler:nil
context:self];
entryHandler:nil
exitHandler:nil
context:self];
states[@(ORKSpatialSpanStepStatePaused)] = [ORKState stateWithState:ORKSpatialSpanStepStatePaused
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this showPausedFromState:from];
} exitHandler:nil context:self];
entryHandler:^(ORKState *from, ORKState *to, ORKSpatialSpanMemoryStepViewController *this) {
[this showPausedFromState:from];
} exitHandler:nil context:self];
_states = states;
@@ -771,6 +744,4 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
}
}
@end
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, ORKSpatialSpanTargetState) {
@@ -48,6 +50,7 @@ typedef NS_ENUM(NSInteger, ORKSpatialSpanTargetState) {
@end
@interface ORKSpatialSpanTargetView : UIView
@property (nonatomic, weak, nullable) id<ORKSpatialSpanTargetViewDelegate> delegate;
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKSpatialSpanTargetView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
@@ -35,10 +36,10 @@
#import "ORKAccessibility.h"
#import "ORKDefines_Private.h"
static const UIEdgeInsets _ORKFlowerMargins = (UIEdgeInsets){12,12,12,12};
static const CGSize ORKFlowerBezierPathSize = (CGSize){90,90};
static UIBezierPath *ORKFlowerBezierPath() {
UIBezierPath *bezierPath = UIBezierPath.bezierPath;
[bezierPath moveToPoint: CGPointMake(58.8, 45)];
[bezierPath addCurveToPoint: CGPointMake(51.9, 33.2) controlPoint1: CGPointMake(107.8, 41.8) controlPoint2: CGPointMake(79.3, -7.2)];
@@ -61,7 +62,6 @@ static UIBezierPath *ORKFlowerBezierPath() {
static const CGSize ORKCheckBezierPathSize = (CGSize){28,28};
static UIBezierPath *ORKCheckBezierPath() {
UIBezierPath *bezierPath = UIBezierPath.bezierPath;
[bezierPath moveToPoint: CGPointMake(11.6, 19)];
[bezierPath addCurveToPoint: CGPointMake(11.1, 18.8) controlPoint1: CGPointMake(11.4, 19) controlPoint2: CGPointMake(11.2, 18.9)];
@@ -82,7 +82,6 @@ static UIBezierPath *ORKCheckBezierPath() {
static const CGSize ORKErrorBezierPathSize = (CGSize){28,28};
static UIBezierPath *ORKErrorBezierPath() {
UIBezierPath *bezier3Path = UIBezierPath.bezierPath;
[bezier3Path moveToPoint: CGPointMake(15.1, 14)];
[bezier3Path addLineToPoint: CGPointMake(18.8, 10.3)];
@@ -114,17 +113,17 @@ static UIBezierPath *ORKErrorBezierPath() {
@property (nonatomic, readonly) UIEdgeInsets canvasMargins;
@property (nonatomic, readonly) CGSize canvasSize;
@property (nonatomic, readonly, strong) UIBezierPath *path;
@property (nonatomic, readonly, strong) UIColor *color;
@property (nonatomic, strong, readonly) UIBezierPath *path;
@property (nonatomic, strong, readonly) UIColor *color;
@end
@implementation ORKPathView
- (instancetype)initWithBezierPath:(UIBezierPath *)path canvasSize:(CGSize)canvasSize canvasMargins:(UIEdgeInsets)margins color:(UIColor *)color
{
CGRect r = (CGRect){CGPointZero, canvasSize};
CGRect outsetRect = UIEdgeInsetsInsetRect(r, (UIEdgeInsets){.top=-margins.top,.left=-margins.left,.right=-margins.right,.bottom=-margins.bottom});
- (instancetype)initWithBezierPath:(UIBezierPath *)path canvasSize:(CGSize)canvasSize canvasMargins:(UIEdgeInsets)margins color:(UIColor *)color {
CGRect canvasRect = (CGRect){CGPointZero, canvasSize};
CGRect outsetRect = UIEdgeInsetsInsetRect(canvasRect, (UIEdgeInsets){.top=-margins.top, .left=-margins.left, .right=-margins.right, .bottom=-margins.bottom});
self = [super initWithFrame:outsetRect];
if (self) {
_canvasMargins = margins;
@@ -145,16 +144,16 @@ static UIBezierPath *ORKErrorBezierPath() {
}
- (void)drawRect:(CGRect)rect {
CGRect bds = [self bounds];
CGRect bounds = [self bounds];
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor clearColor] setFill];
CGContextFillRect(ctx, bds);
CGContextFillRect(ctx, bounds);
CGFloat baseWidth = _canvasSize.width + _canvasMargins.left + _canvasMargins.right;
CGFloat baseHeight = _canvasSize.height + _canvasMargins.top + _canvasMargins.bottom;
CGFloat aspectRatio = MIN( bds.size.width / baseWidth, bds.size.height / baseHeight);
CGFloat aspectRatio = MIN( bounds.size.width / baseWidth, bounds.size.height / baseHeight);
CGContextSaveGState(ctx);
@@ -165,14 +164,12 @@ static UIBezierPath *ORKErrorBezierPath() {
[_path fill];
CGContextRestoreGState(ctx);
}
- (void)tintColorDidChange {
[self setNeedsDisplay];
}
@end
@@ -245,7 +242,6 @@ static UIBezierPath *ORKErrorBezierPath() {
}
- (void)setState:(ORKSpatialSpanTargetState)state {
[self setState:state animated:NO];
}
@@ -278,12 +274,14 @@ static UIBezierPath *ORKErrorBezierPath() {
newCircleAlpha = 0.0;
newCircleTransform = CGAffineTransformMakeScale(0.2, 0.2);
break;
case ORKSpatialSpanTargetStateActive:
_flowerView.tintColor = [self tintColor];
newAlpha = 1.0;
newCircleTransform = CGAffineTransformMakeScale(0.2, 0.2);
newCircleAlpha = 0.0;
break;
case ORKSpatialSpanTargetStateIncorrect:
_flowerView.tintColor = [UIColor ork_redColor];
newTransform = CGAffineTransformMakeScale(0.9*_flowerScaleFactor, 0.9*_flowerScaleFactor);
@@ -295,6 +293,7 @@ static UIBezierPath *ORKErrorBezierPath() {
errorHidden = NO;
useSpring = NO;
break;
case ORKSpatialSpanTargetStateCorrect:
_flowerView.tintColor = [self tintColor];
newTransform = CGAffineTransformMakeScale(1.1*_flowerScaleFactor, 1.1*_flowerScaleFactor);
@@ -318,7 +317,6 @@ static UIBezierPath *ORKErrorBezierPath() {
_checkView.hidden = checkHidden;
_flowerView.transform = CGAffineTransformMakeScale(_flowerScaleFactor, _flowerScaleFactor);
[UIView animateWithDuration:(animated?duration:0) delay:0 usingSpringWithDamping:useSpring?0.5:1 initialSpringVelocity:0 options:(UIViewAnimationOptions)UIViewAnimationOptionBeginFromCurrentState animations:^{
_errorView.alpha = newCircleAlpha;
_checkView.alpha = newCircleAlpha;
@@ -326,19 +324,18 @@ static UIBezierPath *ORKErrorBezierPath() {
_checkView.transform = newCircleTransform;
self.alpha = newAlpha;
_flowerView.transform = newTransform;
} completion:NULL];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect bds = self.bounds;
_flowerView.center = (CGPoint){CGRectGetMidX(bds), CGRectGetMidY(bds)};
_flowerView.bounds = bds;
CGRect bounds = self.bounds;
_flowerView.center = (CGPoint){CGRectGetMidX(bounds), CGRectGetMidY(bounds)};
_flowerView.bounds = bounds;
_flowerView.transform = CGAffineTransformMakeScale(_flowerScaleFactor, _flowerScaleFactor);
CGFloat designWidth = ORKFlowerBezierPathSize.width + _ORKFlowerMargins.left + _ORKFlowerMargins.right;
CGFloat scaleFactor = bds.size.width / designWidth;
CGFloat scaleFactor = bounds.size.width / designWidth;
CGAffineTransform tfm = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
CGRect checkRect = CGRectApplyAffineTransform((CGRect){CGPointZero,ORKCheckBezierPathSize}, tfm);
@@ -28,9 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKCustomStepView_Internal.h"
#import "ORKRoundTappingButton.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKTappingContentView : ORKActiveStepCustomView
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKTappingContentView.h"
#import "ORKActiveStepTimer.h"
#import "ORKResult.h"
@@ -36,6 +37,10 @@
#import "ORKTapCountLabel.h"
#import "ORKHelpers.h"
// #define LAYOUT_DEBUG 1
@interface ORKTappingContentView ()
@property (nonatomic, strong) ORKSubheadlineLabel *tapCaptionLabel;
@@ -44,6 +49,7 @@
@end
@implementation ORKTappingContentView {
NSArray *_constraints;
@@ -54,7 +60,6 @@
- (instancetype)init {
self = [super init];
if (self) {
_screenType = ORKScreenTypeiPhone4;
_tapCaptionLabel = [ORKSubheadlineLabel new];
_tapCaptionLabel.textAlignment = NSTextAlignmentCenter;
@@ -94,6 +99,13 @@
[self setNeedsUpdateConstraints];
_tapCountLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
#if LAYOUT_DEBUG
self.backgroundColor = [[UIColor yellowColor] colorWithAlphaComponent:0.5];
self.tapCaptionLabel.backgroundColor = [UIColor orangeColor];
self.tapCountLabel.backgroundColor = [UIColor greenColor];
_buttonContainer.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:0.25];
#endif
}
return self;
}
@@ -142,12 +154,23 @@
ORKScreenType screenType = _screenType;
const CGFloat HeaderBaselineToCaptionTop = ORKGetMetricForScreenType(ORKScreenMetricCaptionBaselineToTappingLabelTop, screenType);
const CGFloat AssumedHeaderBaselineToStepViewTop = ORKGetMetricForScreenType(ORKScreenMetricLearnMoreBaselineToStepViewTop, screenType);
CGFloat margin = ORKStandardMarginForView(self);
CGFloat margin = ORKStandardHorizMarginForView(self);
self.layoutMargins = (UIEdgeInsets) { .left=margin*2, .right=margin*2 };
static const CGFloat CaptionBaselineToTapCountBaseline = 56;
static const CGFloat TapButtonBottomToBottom = 36;
// On the iPhone, _progressView is positioned outside the bounds of this view, to be in-between the header and this view.
// On the iPad, we want to stretch this out a bit so it feels less compressed.
CGFloat progressViewOffset, topCaptionLabelOffset;
if (screenType == ORKScreenTypeiPad) {
progressViewOffset = 0;
topCaptionLabelOffset = AssumedHeaderBaselineToStepViewTop;
} else {
progressViewOffset = (HeaderBaselineToCaptionTop/3) - AssumedHeaderBaselineToStepViewTop;
topCaptionLabelOffset = HeaderBaselineToCaptionTop - AssumedHeaderBaselineToStepViewTop;
}
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_buttonContainer, _tapCaptionLabel, _tapCountLabel, _progressView, _tapButton1, _tapButton2);
@@ -156,14 +179,14 @@
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1 constant:(HeaderBaselineToCaptionTop/3) - AssumedHeaderBaselineToStepViewTop]];
multiplier:1 constant:progressViewOffset]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_tapCaptionLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1 constant:(HeaderBaselineToCaptionTop - AssumedHeaderBaselineToStepViewTop)]];
multiplier:1 constant:topCaptionLabelOffset]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_tapCountLabel
attribute:NSLayoutAttributeFirstBaseline
@@ -232,7 +255,6 @@
multiplier:1 constant:0]];
_constraints = constraints;
[self addConstraints:_constraints];
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@@ -37,4 +39,4 @@ ORK_CLASS_AVAILABLE
@end
NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_END
@@ -28,17 +28,26 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKTappingIntervalStep.h"
#import "ORKTappingIntervalStepViewController.h"
@implementation ORKTappingIntervalStep
+ (Class)stepViewControllerClass {
return [ORKTappingIntervalStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
NSTimeInterval const ORKTwoFingerTappingMinimumDuration = 5.0;
@@ -46,9 +55,6 @@
if ( self.stepDuration < ORKTwoFingerTappingMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKTwoFingerTappingMinimumDuration)] userInfo:nil];
}
}
@end
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@@ -37,4 +39,4 @@ ORK_CLASS_AVAILABLE
@end
NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_END
@@ -28,6 +28,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKTappingIntervalStepViewController.h"
#import "ORKTappingContentView.h"
#import "ORKActiveStepViewController_internal.h"
@@ -38,14 +39,15 @@
#import "ORKHelpers.h"
#import "ORKActiveStepView.h"
@interface ORKTappingIntervalStepViewController () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) NSMutableArray *samples;
@end
@implementation ORKTappingIntervalStepViewController {
ORKTappingContentView *_tappingContentView;
NSTimeInterval _tappingStart;
BOOL _expired;
@@ -59,9 +61,7 @@
UIGestureRecognizer *_touchDownRecognizer;
}
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = YES;
@@ -69,8 +69,7 @@
return self;
}
- (void)initializeInternalButtonItems
{
- (void)initializeInternalButtonItems {
[super initializeInternalButtonItems];
// Don't show next button
@@ -98,10 +97,8 @@
[_tappingContentView.tapButton1 addTarget:self action:@selector(buttonPressed:forEvent:) forControlEvents:UIControlEventTouchDown];
[_tappingContentView.tapButton2 addTarget:self action:@selector(buttonPressed:forEvent:) forControlEvents:UIControlEventTouchDown];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
@@ -111,7 +108,6 @@
}
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
// "Now" is the end time of the result, which is either actually now,
@@ -120,7 +116,7 @@
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKTappingIntervalResult *tappingResult = [[ORKTappingIntervalResult alloc] initWithIdentifier:(NSString *__nonnull)self.step.identifier];
ORKTappingIntervalResult *tappingResult = [[ORKTappingIntervalResult alloc] initWithIdentifier:self.step.identifier];
tappingResult.startDate = sResult.startDate;
tappingResult.endDate = now;
tappingResult.buttonRect1 = _buttonRect1;
@@ -136,28 +132,26 @@
}
- (void)receiveTouch:(UITouch *)touch onButton:(ORKTappingButtonIdentifier)buttonIdentifier {
if (_expired || self.samples == nil) {
return;
}
NSTimeInterval ti = CACurrentMediaTime();
NSTimeInterval mediaTime = CACurrentMediaTime();
if (_tappingStart == 0) {
_tappingStart = ti;
_tappingStart = mediaTime;
}
CGPoint location = [touch locationInView:self.view];
// Add new sample
ti = ti-_tappingStart;
mediaTime = mediaTime-_tappingStart;
ORKTappingSample *sample = [[ORKTappingSample alloc] init];
sample.buttonIdentifier = buttonIdentifier;
sample.location = location;
sample.timestamp = ti;
sample.timestamp = mediaTime;
[self.samples addObject:sample];
@@ -176,7 +170,6 @@
[self goForward];
}
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished {
CGFloat progress = finished ? 1 : (timer.runtime / timer.duration);
[_tappingContentView setProgress:progress animated:YES];
@@ -201,7 +194,7 @@
NSInteger index = (button == _tappingContentView.tapButton1) ? ORKTappingButtonIdentifierLeft : ORKTappingButtonIdentifierRight;
[self receiveTouch:[[event touchesForView:button] anyObject] onButton:index] ;
[self receiveTouch:[[event touchesForView:button] anyObject] onButton:index];
}
#pragma mark UIGestureRecognizerDelegate
@@ -219,4 +212,3 @@
}
@end
@@ -0,0 +1,46 @@
/*
Copyright (c) 2015, Shazino SAS. 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 "ORKCustomStepView_Internal.h"
#import "ORKRoundTappingButton.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKToneAudiometryContentView : ORKActiveStepCustomView
- (void)setProgress:(CGFloat)progress
caption:(NSString *)caption
animated:(BOOL)animated;
@property (nonatomic, strong, readonly) ORKRoundTappingButton *tapButton;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,173 @@
/*
Copyright (c) 2015, Shazino SAS. 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 "ORKToneAudiometryContentView.h"
#import "ORKSkin.h"
#import "ORKUnitLabel.h"
#import "ORKHelpers.h"
@interface ORKToneAudiometryContentView ()
@property (nonatomic, strong) ORKUnitLabel *captionLabel;
@property (nonatomic, strong) UIProgressView *progressView;
- (void)setupConstraints;
@end
@implementation ORKToneAudiometryContentView {
ORKScreenType _screenType;
}
- (instancetype)init {
self = [super init];
if (self) {
_screenType = ORKGetScreenTypeForWindow(self.window);
_captionLabel = [ORKUnitLabel new];
_captionLabel.textAlignment = NSTextAlignmentCenter;
_captionLabel.translatesAutoresizingMaskIntoConstraints = NO;
_progressView = [UIProgressView new];
_progressView.translatesAutoresizingMaskIntoConstraints = NO;
_progressView.progressTintColor = [self tintColor];
[_progressView setAlpha:0];
_tapButton = [[ORKRoundTappingButton alloc] init];
_tapButton.translatesAutoresizingMaskIntoConstraints = NO;
[_tapButton setTitle:ORKLocalizedString(@"TAP_BUTTON_TITLE", nil) forState:UIControlStateNormal];
[self addSubview:_captionLabel];
[self addSubview:_progressView];
[self addSubview:_tapButton];
self.translatesAutoresizingMaskIntoConstraints = NO;
_captionLabel.text = nil;
[self setupConstraints];
[self setNeedsUpdateConstraints];
}
return self;
}
- (void)tintColorDidChange {
[super tintColorDidChange];
self.progressView.progressTintColor = [self tintColor];
}
- (void)setProgress:(CGFloat)progress
caption:(NSString *)caption
animated:(BOOL)animated {
self.captionLabel.text = caption;
[self.progressView setProgress:progress animated:animated];
[UIView animateWithDuration:animated ? 0.2 : 0 animations:^{
[self.progressView setAlpha:(progress == 0) ? 0 : 1];
}];
}
- (void)finishStep:(ORKActiveStepViewController *)viewController {
[super finishStep:viewController];
self.tapButton.enabled = NO;
}
- (void)setupConstraints {
ORKScreenType screenType = _screenType;
const CGFloat HeaderBaselineToCaptionTop = ORKGetMetricForScreenType(ORKScreenMetricCaptionBaselineToTappingLabelTop, screenType);
const CGFloat AssumedHeaderBaselineToStepViewTop = ORKGetMetricForScreenType(ORKScreenMetricLearnMoreBaselineToStepViewTop, screenType);
CGFloat margin = ORKStandardHorizMarginForView(self);
self.layoutMargins = (UIEdgeInsets) { .left=margin*2, .right=margin*2 };
static const CGFloat TapButtonBottomToBottom = 36;
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _captionLabel, _tapButton);
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1 constant:(HeaderBaselineToCaptionTop/3) - AssumedHeaderBaselineToStepViewTop]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_captionLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1 constant:(HeaderBaselineToCaptionTop - AssumedHeaderBaselineToStepViewTop)]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_tapButton
attribute:NSLayoutAttributeBottom
multiplier:1 constant:TapButtonBottomToBottom]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_captionLabel]-(>=10)-[_tapButton]"
options:NSLayoutFormatAlignAllCenterX
metrics:nil views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
NSLayoutConstraint *wideProgress = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:2000];
wideProgress.priority = UILayoutPriorityRequired-1;
[constraints addObject:wideProgress];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_captionLabel]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_tapButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1 constant:0]];
[self addConstraints:constraints];
[NSLayoutConstraint activateConstraints:constraints];
}
@end
@@ -28,15 +28,12 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIApplication (ORKFirstResponderAdditions)
- (nullable UIResponder *)ork_currentFirstResponder;
ORK_CLASS_AVAILABLE
@interface ORKToneAudiometryPracticeStep : ORKActiveStep
@end

Some files were not shown because too many files have changed in this diff Show More