Compare commits

...

511 Commits

Author SHA1 Message Date
Akshay 44c88877c5 Fix for CocoaPods 2017-07-13 11:42:25 -07:00
Akshay 6f2ac3f671 Fixes 2017-07-13 11:19:33 -07:00
Akshay 007583929c Convergence 2017-07-06 18:08:13 -07:00
Akshay c97d6bd78c Convergence 2017-07-06 15:33:24 -07:00
Umer Khan 6089b09963 Merge pull request #853 from ryanschneider/podspec-fix
Fix typo in podspec version quoting characters.
2016-10-27 14:42:33 -07:00
Ryan Schneider 87a7a6a718 Fix typo in podspec version quoting characters. 2016-10-27 11:26:15 -07:00
Umer Khan c1493b9c5c Merge pull request #851 from ResearchKit/podspec
Podspec
2016-10-26 13:09:39 -07:00
Umer Khan d47e835e8e Merge branch 'master' into podspec
* master:
  convergence
  Update pod spec version number.
  Declare ORKScrollToTopAnimationDuration and ORKCGFloatInvalidValue as extern in ORKHelpers.h; fixes #679
2016-10-26 13:08:56 -07:00
Umer Khan 4b456ad2bb Merge pull request #850 from ResearchKit/stable
Stable
2016-10-26 12:48:49 -07:00
Umer Khan 125ff93795 Updating podspec 2016-10-26 12:40:56 -07:00
Umer Khan 2a1bbeefe8 Merge branch 'master' into stable
* master: (346 commits)
  Updating podspec.
  Convergence
  Fixed width constraint priority
  Make ORKInstructionStepViewController and ORKCompletionStepViewController public
  Add comment to the aux image.
  Add example use of the auxillary image.
  created the touchIdEnabled serializable encoding, confirm all tests pass
  Typo in function name
  Add ORKTappingButtonIdentifier rather than NSInteger
  added taskViewController didChangeResult implementation example to show how to get the ORKPasscodeResult information in the delegate
  Fix merge errors
  as per PR comment edited the ORKPasscodeResult to handle a new boolean property touchIdEnabled, in encoding/decoding, copying, and description
  removed the forced taskViewController delegate call from the ORKPasscodeStepViewCOntroller as its already calling it on its own, so no need for double
  added the delegate call when the prompt for touchID call is complete
  Erased asterisk/pointer from my last pull request
  Fixing bug where timer label did not display
  invalid pointer updates (warning fixes)
  Fix documentation typo
  Update ORKPicker.m
  Documented the ORKPicker functions.
  ...

# Conflicts:
#	ResearchKit.podspec
#	ResearchKit/ResearchKit.h
#	ResearchKit/ResearchKit_Private.h
2016-10-26 12:36:20 -07:00
Umer Khan ddc023fd4c Merge pull request #849 from ResearchKit/podspec
Updating podspec.
2016-10-26 11:31:58 -07:00
Umer Khan 160bb111f0 Updating podspec. 2016-10-26 11:31:36 -07:00
Yuan Zhu 30742a5043 convergence 2016-09-27 13:42:56 -07:00
Yuan Zhu ead0650dfb Convergence 2016-09-26 22:23:17 -07:00
Yuan Zhu 4f3d0f33df Merge pull request #803 from Sage-Bionetworks/pr/public-ORKCompletionStepViewController
Make ORKInstructionStepViewController and ORKCompletionStepViewController public
2016-08-30 13:14:46 -07:00
Yuan Zhu 608d954197 Merge pull request #806 from asynchrony/fixed_width_constraint
Fixed width constraint priority
2016-08-30 10:25:18 -07:00
Joe Carroll 74326baef4 Fixed width constraint priority 2016-08-30 12:16:19 -05:00
Shannon Young 5b1abe95c5 Make ORKInstructionStepViewController and ORKCompletionStepViewController public
We use a custom subclass of ORKInstructionStep which uses a custom implementation for learn more actions. By publicly exposing these view controllers, we can return the appropriate view controller (or subclass).
2016-08-25 15:37:48 -07:00
Yuan Zhu fe9c9e1fc5 Merge pull request #752 from Sage-Bionetworks/pr/add-module-hand-tremor
Add Hand Tremor Module
2016-08-24 11:06:16 -07:00
Shannon Young b8b7b80f09 Add comment to the aux image. 2016-08-26 10:46:57 -07:00
Umer Khan 1bcc12bd80 Merge pull request #792 from boland25/feature/touchIDReportResults
Feature/touch ID report results of if touchID was chosen in Passcode Setup
2016-08-22 14:21:40 -07:00
Shannon Young eb9464b6ce Add example use of the auxillary image. 2016-08-22 11:09:42 -07:00
Yuan Zhu c476ad838e Merge pull request #798 from gmw/master
Typo in function name
2016-08-22 10:06:28 -07:00
Gregory Boland c167e4d84c created the touchIdEnabled serializable encoding, confirm all tests pass 2016-08-22 11:01:15 -04:00
Magnus Wissler 77eb12636a Typo in function name 2016-08-21 12:02:11 +02:00
Umer Khan 27f4197374 Merge pull request #654 from m1entus/master
Adding tap duration to Tapping Task Issue #561
2016-08-19 12:47:11 -07:00
Michal Zaborowski 34f473d8e5 Add ORKTappingButtonIdentifier rather than NSInteger 2016-08-19 20:47:01 +02:00
Gregory Boland 42b9907579 added taskViewController didChangeResult implementation example to show how to get the ORKPasscodeResult information in the delegate 2016-08-17 10:08:15 -04:00
Shannon Young 67a04562d6 Fix merge errors 2016-08-16 13:15:51 -07:00
Shannon Young f86668e8cb Merge branch 'master' into pr/add-module-hand-tremor 2016-08-16 12:46:10 -07:00
Yuan Zhu 33ca348856 Merge pull request #770 from rsanchezsaez/rsanchezsaez-charts
[Charts] Fix crashes
2016-08-16 12:22:22 -07:00
Gregory Boland bccef20ce5 as per PR comment edited the ORKPasscodeResult to handle a new boolean property touchIdEnabled, in encoding/decoding, copying, and description 2016-08-16 15:00:53 -04:00
Yuan Zhu 0f92862e52 Merge pull request #772 from md0u80c9/funcComments
Documented the ORKPicker functions.
2016-08-16 11:24:34 -07:00
Yuan Zhu c7a8cdd2c0 Merge pull request #764 from dephillipsmichael/bad_access_fix
bad_access_fix
2016-08-16 11:22:19 -07:00
Yuan Zhu 75142028b0 Merge pull request #648 from rsanchezsaez/rsanchezsaez-CodeHomogenization2
[Misc] #import section refactor to reduce header interdependency
2016-08-16 11:20:48 -07:00
Yuan Zhu d618d45635 Merge pull request #647 from weijentu/master
ORKQuestionResult could get truncated Chinese texts
2016-08-16 11:04:20 -07:00
Yuan Zhu 7a33c6b4a7 Merge pull request #789 from phantomkirby/patch-2
Erased asterisk/pointer from my last pull request
2016-08-16 10:46:50 -07:00
Gregory Boland add20301a1 removed the forced taskViewController delegate call from the ORKPasscodeStepViewCOntroller as its already calling it on its own, so no need for double 2016-08-16 11:48:22 -04:00
Gregory Boland fbc4dde858 added the delegate call when the prompt for touchID call is complete 2016-08-16 11:38:44 -04:00
Ricardo Sánchez-Sáez 18b6557cf3 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-CodeHomogenization2
# Conflicts:
#	ResearchKit/Charts/ORKGraphChartView.m
2016-08-13 10:56:09 -07:00
Cherry c195cf1a16 Erased asterisk/pointer from my last pull request
In my last pull request (#788) that was merged, I forgot to delete the "*" symbol. This actually caused the build to fail. The build should work now. Sorry about this!
2016-08-12 21:10:56 -04:00
Yuan Zhu 6679fb0922 Merge pull request #787 from 2020Deception/master
invalid pointer updates (warning fixes)
2016-08-12 15:23:46 -07:00
Yuan Zhu 740051812a Merge pull request #788 from phantomkirby/patch-1
Fixing bug where timerLabel did not display in ORKFitnessStep
2016-08-12 14:34:45 -07:00
Cherry 5c602d7850 Fixing bug where timer label did not display
in the updateTimerLabel function, the timer would be hidden if the labelString was null. The labelString was null everytime because the "formatter" object (an NSDateComponentsFormatter object) was null the whole time. This object was null because inside the "dispatch_once", we did not reference/edit the existing static formatter object outside of the dispatch_once, but rather, we instantiated a new formatter object.
2016-08-12 14:27:42 -04:00
Brian Bowman 0b4b2ae6e5 invalid pointer updates (warning fixes) 2016-08-12 11:41:02 -04:00
Yuan Zhu 0efee740e4 Merge pull request #778 from YuanZhu-apple/master_sliderGradient
Displaying a color gradient above the scale slider
2016-08-04 14:09:38 -07:00
Yuan Zhu 856d544fad Merge pull request #777 from YuanZhu-apple/master_lineGraphHideDots
Line graph hide dots
2016-08-04 14:09:03 -07:00
Yuan Zhu c257751d1d Merge pull request #776 from YuanZhu-apple/master_result_predicate_for_consentReviewStep
Result predicate for consent review step
2016-08-04 14:08:32 -07:00
Yuan Zhu 81e879e8f6 Merge pull request #775 from YuanZhu-apple/master_piechart_scale_factor
Piechart add scale factor support
2016-08-04 14:08:12 -07:00
Yuan Zhu ddeed599df Merge pull request #773 from ThreadResearch/master
Fix documentation typo
2016-08-01 13:44:03 -07:00
Jake Krog 65f525ff38 Fix documentation typo 2016-08-01 11:32:10 -07:00
Andrew Hill 60bfacf507 Merge remote-tracking branch 'origin/funcComments' into funcComments 2016-08-01 18:35:13 +01:00
Andrew Hill 0eae7e87f7 Update ORKPicker.m
Fixed a conflict.
2016-08-01 18:23:58 +01:00
Andrew Hill 26597eb334 Merge branch 'master' into funcComments 2016-08-01 18:21:32 +01:00
Andrew Hill 44c5535a8d Merge remote-tracking branch 'ResearchKit/master' into funcComments
# Conflicts:
#	ResearchKit/Common/ORKPicker.m
2016-08-01 18:14:35 +01:00
Andrew Hill d06f070e83 Documented the ORKPicker functions. 2016-07-31 23:48:27 +01:00
Andrew Hill 633d31be97 Merge branch 'ResearchKit/master' 2016-07-30 00:23:15 +01:00
Ricardo Sánchez-Sáez 6936eb34ac [ORKPieChartPieView] Add support for segments of 0 value
Avoids crash if the dataSource returns 0 for any segment value.
2016-07-29 23:40:40 +01:00
Ricardo Sánchez-Sáez 40891abb63 [ORKGraphChartView] Make '-numberOfPlotsInGraphChartView' non-optional and make it default to 0 plots.
Avoids crash if the graph chart view is laid out before the dataSource is set.
2016-07-29 23:26:23 +01:00
Yuan Zhu f9b8e39876 Adds support for displaying a color gradient above the slider for scale answer formats.
In the simple case this can be used to show a scale from bad to good by setting.
2016-07-25 17:05:17 -07:00
Yuan Zhu e14d327e3b Adds support for drawing plots within a chart without individual data point indicators. 2016-07-25 13:58:48 -07:00
Ricardo Sánchez-Sáez b9bcd6713c Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-CodeHomogenization2
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	ResearchKit/ActiveTasks/ORKCountdownStep.h
#	ResearchKit/Charts/ORKDiscreteGraphChartView.m
#	ResearchKit/Charts/ORKGraphChartView.m
#	ResearchKit/Charts/ORKGraphChartView_Internal.h
#	ResearchKit/Charts/ORKLineGraphChartView.m
#	ResearchKit/Charts/ORKPieChartLegendView.m
#	ResearchKit/Charts/ORKPieChartView.m
#	ResearchKit/Charts/ORKRangedPoint.h
#	ResearchKit/Charts/ORKRangedPoint.m
#	ResearchKit/Common/ORKAnswerFormat.h
#	ResearchKit/Common/ORKAnswerFormat_Internal.h
#	ResearchKit/Common/ORKAnswerTextView.m
#	ResearchKit/Common/ORKCompletionStep.h
#	ResearchKit/Common/ORKFormStep.m
#	ResearchKit/Common/ORKHeightPicker.h
#	ResearchKit/Common/ORKInstructionStep.h
#	ResearchKit/Common/ORKNavigableOrderedTask.m
#	ResearchKit/Common/ORKOrderedTask.m
#	ResearchKit/Common/ORKPasscodeStepViewController.m
#	ResearchKit/Common/ORKSignatureStepViewController.h
#	ResearchKit/Common/ORKSignatureStepViewController.m
#	ResearchKit/Common/ORKStepViewController.h
#	ResearchKit/Common/ORKTextButton.h
#	ResearchKit/Common/ORKTextFieldView.m
#	ResearchKit/Common/ORKTypes.h
#	ResearchKit/Consent/ORKConsentReviewStepViewController.m
#	ResearchKit/ResearchKit.h
#	ResearchKit/ResearchKit_Private.h
#	ResearchKitTests/ORKAnswerFormatTests.m
#	Testing/ORKTest/ORKTest/Charts/Charts.storyboard
#	Testing/ORKTest/ORKTest/DragonPokerStep.m
2016-07-25 21:52:13 +01:00
Yuan Zhu bc2801bb9e Result predicate for ORKConsentReviewStep
Add a result predicate for determining if the user selected accept or decline in a consent signature step, allowing for custom navigation rules, such as skipping to the end of a survey if the user does not consent.
2016-07-25 12:47:14 -07:00
Yuan Zhu ba78feb4dd Providing a scale factor property in ORKPieChartView. 2016-07-25 12:36:56 -07:00
MDP 56a8bc1db3 added check if weak self vc has been dismissed 2016-07-18 14:28:02 -04:00
Ricardo Sánchez-Sáez e86ef34a75 Merge branch 'master' of github.com:rsanchezsaez/ResearchKit into rsanchezsaez-CodeHomogenization2
# Conflicts:
#	ResearchKit/Common/ORKSurveyAnswerCellForText.m
#	ResearchKit/Common/ORKTextFieldView.m
2016-07-14 23:58:01 +01:00
Shannon Young 912a8112fb Fix warning in ORKHeightAnswerFormat due to failure to properly cast 2016-07-11 15:04:58 -07:00
Shannon Young 27644a292c Fix merge conflicts 2016-07-11 15:04:19 -07:00
Shannon Young 3f2cb32b23 Merge branch 'master' into pr/add-module-hand-tremor
# Conflicts:
#	ResearchKit/Common/ORKOrderedTask.m
#	ResearchKit/Common/ORKSkin.m
2016-07-11 14:56:27 -07:00
Yuan Zhu d84944ac6a Merge pull request #702 from stevemoser/ipad-pro-12-9-support
Support for 12.9 inch iPad Pro
2016-07-11 12:54:15 -07:00
Yuan Zhu ebfbfcb900 Merge pull request #637 from rsanchezsaez/rsanchezsaez-CodeHomogenization
[Misc] Code homogenization
2016-07-11 12:49:30 -07:00
Ricardo Sánchez-Sáez 3bd27d6ebe Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-CodeHomogenization
# Conflicts:
#	ResearchKit/Common/ORKAnswerFormat.m
#	ResearchKit/Common/ORKAnswerFormat_Internal.h
#	ResearchKit/Common/ORKDefines.h
#	ResearchKit/Common/ORKHealthAnswerFormat.m
#	ResearchKit/Common/ORKHelpers.h
#	ResearchKit/Common/ORKQuestionStepViewController.m
2016-07-09 19:42:16 +02:00
Yuan Zhu e11440b036 Merge pull request #643 from rsanchezsaez/rsanchezsaez-ORKHeightAnswerFormat
[ORKAnswerFormat] Implement picker-based 'ORKHeightAnswerFormat'
2016-07-08 10:41:15 -07:00
Andrew Hill fdedb11fea Merge branch 'ResearchKit/master' 2016-07-08 17:09:29 +01:00
Ricardo Sánchez-Sáez 72a665b961 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-CodeHomogenization
# Conflicts:
#	ResearchKit/Consent/ORKConsentReviewStepViewController.m
2016-07-08 15:07:21 +02:00
Ricardo Sánchez-Sáez cfe04441ad Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-CodeHomogenization
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	ResearchKit/ActiveTasks/ORKHealthQuantityTypeRecorder.m
#	ResearchKit/Charts/ORKGraphChartView.m
#	ResearchKit/Charts/ORKRangedPoint.m
#	ResearchKit/Common/ORKHealthAnswerFormat.m
#	ResearchKit/Common/ORKNavigableOrderedTask.m
#	ResearchKit/Common/ORKOrderedTask.m
#	ResearchKit/Common/ORKPasscodeStepViewController.m
#	ResearchKit/Common/ORKSurveyAnswerCellForText.m
#	ResearchKit/Common/ORKTextButton.h
#	ResearchKit/Common/ORKTextFieldView.m
#	Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m
2016-07-08 15:05:24 +02:00
Ricardo Sánchez-Sáez 7fe3e227ad [ORKHeightPicker] Fix issue returning empty 'selectedLabelText' 2016-07-08 13:34:17 +02:00
Yuan Zhu 4d8f4f3bb1 Merge pull request #753 from Sage-Bionetworks/pr/fix-signature-warning
Fix cast warning introduced with ORKSignatureResult
2016-07-07 15:39:47 -07:00
Shannon Young e29e7f2b73 Fix cast warning introduced with ORKSignatureResult 2016-07-07 13:24:25 -07:00
Allen Tu f2e133676b Merge remote-tracking branch 'ResearchKit/master' 2016-07-07 11:09:11 -07:00
Shannon Young 0c898b4abb Language updates to more closely match the wording approved by our IRB. 2016-07-07 10:26:22 -07:00
Ricardo Sánchez-Sáez c1fa1ea154 [ORKHeightPicker] Use cm as the internal answer unit regardless of chosen locale 2016-07-07 18:08:38 +02:00
Ricardo Sánchez-Sáez f659531d77 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-ORKHeightAnswerFormat
# Conflicts:
#	ResearchKit/Common/ORKHealthAnswerFormat.m
#	ResearchKit/Localized/en.lproj/ResearchKit.strings
2016-07-07 17:50:54 +02:00
Ricardo Sánchez-Sáez 6e22f94cf5 [ORKHeightPicker] Fix previous answer not being remembered
The _answerFormat ivar needs to be properly set before for the self.answer setter to work correctly.
2016-07-07 17:30:42 +02:00
Ricardo Sánchez-Sáez 88c7c87f28 [ORKHeightAnswerFormat] Fix documentation 2016-07-07 17:29:38 +02:00
Ricardo Sánchez-Sáez 6a9da73a8a [ORKCatalog] Add metric and USC height question step samples 2016-07-07 17:29:24 +02:00
Shannon Young 0f0448bff7 Fix ORKCatalog for updated tremor module 2016-07-07 00:28:21 -07:00
Shannon Young fd2c914b68 Add navigation rules to allow user to skip the steps for one hand. 2016-07-07 00:06:05 -07:00
Shannon Young 5122948de0 Add Tremot task to ORKTest 2016-07-06 16:51:25 -07:00
Erin-Mounts 19d3624658 Two-handed tremor task 2016-07-06 16:46:03 -07:00
Erin Mounts 4f68c2bf4e Allow excluding some active tasks from tremor test 2016-07-06 16:46:02 -07:00
Shannon Young 9e1ed9e070 Add initial tremor module 2016-07-06 16:46:01 -07:00
Shannon Young 9fb7562ce5 Add an auxillary image to the instruction view.
This is used in the tremor module to show a second image.
2016-07-06 16:46:01 -07:00
Yuan Zhu b1b25f9ac4 Merge pull request #751 from Sage-Bionetworks/pr/ui-public-signature-step
Add public ORKSignatureStep
2016-07-06 16:27:46 -07:00
Shannon Young a5b58c4c8e Add signaturePath to list of knownNotSerializedProperties 2016-07-06 16:23:31 -07:00
Yuan Zhu 66c7b86484 Merge pull request #743 from Sage-Bionetworks/pr/add-module-bilateral-tapping
Add task module for measuring bilateral tapping speed
2016-07-06 16:01:12 -07:00
Shannon Young 7b850951ef More syntax changes 2016-07-06 15:45:48 -07:00
Shannon Young bd5f5bb231 Retain signature state on back navigation 2016-07-06 15:44:16 -07:00
Shannon Young 2526450391 More syntax cleanup. 2016-07-06 15:11:06 -07:00
Shannon Young 289a45c3dd Change undefined hand to unspecified. 2016-07-06 14:38:35 -07:00
Shannon Young 931c7d7728 More curly brace changes. 2016-07-06 12:06:15 -07:00
Shannon Young 6d52269995 Fixed syntax, updated copyright and fixed localized formatting. 2016-07-06 11:49:25 -07:00
Shannon Young f69401cae9 Added task for showing just the signature step to ORKTest
Note: ORKCatalog uses this step in the consent flow example and displays the result.
2016-07-06 11:42:41 -07:00
Shannon Young 3d57bf65b8 Moved ORKSignatureStep into Common 2016-07-06 11:21:25 -07:00
Shannon Young e7b75b5f88 Move default title/text for signature to ORKSignatureStep 2016-07-06 09:29:55 -07:00
Shannon Young 590bb25559 Update text for tapping skip button and hide once tapping started. 2016-07-05 21:59:11 -07:00
Shannon Young f7345070a9 Add public ORKSignatureStep
Change the consent signature view controller to a step view controller that is instantiated using an ORKSignatureStep and outputs an ORKSignatureResult. This will allow for customization of the consent process and use of the signature gathering step in other task work flows.
2016-07-05 17:36:42 -07:00
Yuan Zhu 558b5391a3 Merge pull request #732 from Sage-Bionetworks/pr/ui-add-ORKStepTableViewController
Added a general purpose step table view controller
2016-07-05 15:10:28 -07:00
Shannon Young 4ea6fc7d46 Updated comment in ORKTableStep 2016-07-05 14:51:05 -07:00
Shannon Young 2289b01f7c Modified method signature for bilateral tapping task and updated ORKTest and ORKCatalog 2016-07-05 14:35:02 -07:00
Shannon Young 4899548438 Deprecated two-finger tapping test without hand specified 2016-07-05 14:25:37 -07:00
Shannon Young bcc85b9a2c Updated tapping unit test to explicitly check for reverse-compatibility 2016-07-05 14:23:54 -07:00
Shannon Young 613d3a676c Move the two-handed tapping test into ResearchKit
# Conflicts:
#	ResearchKitTests/ORKTaskTests.m
2016-07-05 14:23:54 -07:00
Shannon Young e5fa2374ab Add UIImage method for mirroring a collection of images
This is a utility method for flipping an image so that the same image can be used in both left-hand and right-hand orientations.
2016-07-05 14:21:01 -07:00
Erin Mounts 859bbb4e17 Modifications to ORKTappingContentView to support resizing the view if skippable.
cherry-pick d5011e37606365f794c377dad45e73a721d6db00 (with some manual intervention because of massive changes to ORKTappingContentView in RK 1.3)
2016-07-05 14:21:01 -07:00
Shannon Young 9fe59ca7a8 Default ORKTableStepViewController to allowsSelection=NO and simplify cell registration. 2016-07-05 14:19:50 -07:00
Shannon Young b3d72ce28a Add ORKTableStep with a default implementation for supporting a basic data source 2016-07-05 14:19:50 -07:00
Shannon Young e421214098 Add to the comments describing intended usage of this class. 2016-07-05 14:18:57 -07:00
Shannon Young 53e19548c4 Edited comments 2016-07-05 14:18:57 -07:00
Shannon Young f3fdb66cf8 Added comments and updated copyright. 2016-07-05 14:18:57 -07:00
Shannon Young ead682b402 Add files to project and update copyright date 2016-07-05 14:18:57 -07:00
Erin Mounts aeb3849fd7 Make ORKTableStepViewController visible...
...in release builds (RK sets symbols to hidden by default in release builds)
2016-07-05 14:18:57 -07:00
Shannon Young b9af6508ac Added a general purpose step table view controller 2016-07-05 14:18:57 -07:00
Yuan Zhu 2ff97e4558 Merge pull request #747 from Sage-Bionetworks/pr/add-module-walk-back-and-forth
Add module for walking back and forth
2016-07-05 14:17:05 -07:00
Shannon Young 26da4d8e34 Added serialized properties on ORKActiveStep to ORKTest 2016-07-05 13:53:15 -07:00
Shannon Young 6ee2b47dc1 Updated copyright and halfway count property name 2016-07-05 13:37:29 -07:00
Shannon Young 84f806ee11 Add walk back and forth task to ORKTest 2016-07-05 12:58:26 -07:00
Shannon Young a24dc1ac56 Added unit tests to check the identifiers and half-way spoken count. 2016-07-05 12:57:29 -07:00
Erin Mounts c3618bb104 update pocket image. phone should be inserted speaker-side-out 2016-07-05 12:56:37 -07:00
Shannon Young 119b5f19d2 Add halfway spoken instruction to countdown for walking back and forth 2016-07-05 12:56:37 -07:00
Shannon Young 5195ed44f1 Add back-and-forth walking task 2016-07-05 12:56:37 -07:00
Shannon Young 755db8b700 Add finishedSpokenInstruction to active step
The finished spoken instruction property allows a step to announce that it is completed. This is useful in the case where the phone screen is not visible such as a walking activity (where the phone is in the participant's phone) or a hand tremor measurement (where the screen is not facing the participant).
2016-07-05 12:56:37 -07:00
Yuan Zhu 3d95111ace Merge pull request #735 from Sage-Bionetworks/pr/method-add-stepvc-init
Allow steps to instantiate the view controller
2016-07-05 12:26:55 -07:00
Shannon Young 859fc28d8a Fix deprecation warning 2016-07-01 16:39:33 -07:00
Shannon Young ebc4ccacc0 Move example for initializing a custom step view controller into ORKTest 2016-07-01 16:31:53 -07:00
Shannon Young 1c3aab92c1 Update the unit test to make it a little more interesting. 2016-07-01 16:28:12 -07:00
Shannon Young 70093149b5 Updated comment to add additional description. 2016-07-01 16:28:12 -07:00
Shannon Young d595a0b199 Add unit test for instantiating a view controller and expose stepViewControllerClass method 2016-07-01 16:28:12 -07:00
Shannon Young 764b5f8691 Allow steps to instantiate the view controller 2016-07-01 16:28:12 -07:00
Yuan Zhu 395eb936d5 Merge pull request #721 from Sage-Bionetworks/pr/public-continue-button
Make the continue button public for UI consistency
2016-07-01 16:14:15 -07:00
Yuan Zhu dcab7194c1 Merge pull request #727 from Sage-Bionetworks/pr/ui-should-confirm-cancel
Added delegate method for discarding results without confirming cancel.
2016-07-01 15:39:48 -07:00
Yuan Zhu 9c271d87f6 Merge pull request #726 from Sage-Bionetworks/pr/fix-audio-prompts
Fix audio-prompts-coming-from-earpiece bug
2016-07-01 15:32:37 -07:00
Shannon Young d9ebc6d253 Fixed copyrights and removed commented out code 2016-07-01 15:26:20 -07:00
Yuan Zhu 2e555356a6 Merge pull request #722 from Sage-Bionetworks/pr/ui-forgot-passcode
Forgot passcode with delegate methods matching existing pattern
2016-07-01 14:53:49 -07:00
Shannon Young 69c830b8cd Code cleanup and fix alert in ORKTest 2016-07-01 14:24:12 -07:00
Shannon Young a5aa647ed0 Remove delegate method for setting the tintColor 2016-07-01 13:40:32 -07:00
Shannon Young d7d923e609 Forgot passcode with delegate methods matching existing pattern 2016-07-01 13:40:32 -07:00
Shannon Young 0cbb21d71d Add missing comma 2016-07-01 13:06:48 -07:00
Shannon Young f5fe7a47f3 Added files to ORKTest for creating example continue button 2016-07-01 13:02:13 -07:00
Shannon Young cbea809430 Add Continue Button to ORKTest project 2016-07-01 13:02:13 -07:00
Shannon Young a65d5da62f Add test for example usage of continue button. 2016-07-01 13:02:13 -07:00
Shannon Young 49f2914063 Mark ORKTextButton_Internal with project 2016-07-01 13:02:13 -07:00
Shannon Young f50340c7e1 Make the continue button public for UI consistency 2016-07-01 13:02:13 -07:00
Yuan Zhu dfcc02d75f Merge pull request #639 from rsanchezsaez/rsanchezsaez-ORKHealthKitCharacteristicTypeAnswerFormat
[ORKHealthKitCharacteristicTypeAnswerFormat] Expose date picker attributes
2016-06-29 12:36:18 -07:00
Ricardo Sánchez-Sáez 6ad71820d8 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-ORKHealthKitCharacteristicTypeAnswerFormat
# Conflicts:
#	Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m
2016-06-29 20:22:23 +01:00
Ricardo Sánchez-Sáez 275cc3ae17 [ORKJSONSerializationTests] Remove unneeded whitespace 2016-06-29 20:18:57 +01:00
Yuan Zhu 5f643fdcde Merge pull request #731 from Sage-Bionetworks/pr/audio-level-check
Added a optional ambient noise check to the voice task.
2016-06-29 10:57:14 -07:00
Shannon Young e444c32eb5 Add missing ORK_CLASS_AVAILABLE to ORKPredicateSkipStepNavigationRule 2016-06-29 10:55:54 -07:00
Shannon Young 7c7dfc4861 Added missing ORK_CLASS_AVAILABLE to headers 2016-06-29 10:44:59 -07:00
Shannon Young 9b9e941299 Add ORKAudioLevelNavigationRule to the tests for ORKSerialization 2016-06-28 17:58:44 -07:00
Shannon Young 27a0755414 Fix typo in documentation for audioTask with sound check 2016-06-28 16:31:48 -07:00
Shannon Young 0dfb3455f7 Update documentation and added unit test 2016-06-28 15:04:41 -07:00
Shannon Young 47d6b5e0f9 Change method signature and deprecate the old audioTask constructor 2016-06-28 14:45:41 -07:00
Shannon Young dbb0fcf2b7 Change name of step identifier property to destinationStepIdentifier 2016-06-28 14:45:41 -07:00
Shannon Young 170ca3e0b6 Added audio wiith sound check to ORKCatalog 2016-06-28 14:45:41 -07:00
Shannon Young 2c868e3bb4 Update copyrights and method signature 2016-06-28 14:45:41 -07:00
Shannon Young 1abd8bf548 Throw exception if recordingSettings dictionary is nil 2016-06-28 14:45:41 -07:00
Shannon Young 5db0f6422e Update copyright dates 2016-06-28 14:45:41 -07:00
Shannon Young 47f1a3bfd1 Added a optional ambient noise check to the voice task. 2016-06-28 14:45:41 -07:00
Yuan Zhu 231ed3f90c Merge pull request #738 from Sage-Bionetworks/pr/ui-confirm-answer-format
Expose method for instantiating an answer format for confirmation of another field.
2016-06-28 13:33:08 -07:00
Yuan Zhu dd465a00e7 Merge pull request #728 from Sage-Bionetworks/pr/public-ordered-task-step-index
Expose method for getting the index of a step from ORKOrderedTask
2016-06-28 13:24:14 -07:00
Yuan Zhu 05325d6070 Merge pull request #644 from rsanchezsaez/rsanchezsaez-Cocoapods
[Cocoapods] Fix podspec to include swift files
2016-06-28 10:22:41 -07:00
Shannon Young ee446da653 Added test for indexOfStep == NSNotFound 2016-06-27 16:38:38 -07:00
Shannon Young b39c2ea10d Add unit test for indexOfStep 2016-06-27 16:38:38 -07:00
Shannon Young 106b2d969f Remove ORKOrderedTask_Internal 2016-06-27 16:37:47 -07:00
Shannon Young cd02eefff7 Expose method for getting the index of a step. 2016-06-27 16:37:47 -07:00
Yuan Zhu 55b97af36a Merge pull request #633 from rsanchezsaez/rsanchezsaez-ORKBarGraphChart
[Charts] Implement ORKBarGraphChart
2016-06-27 16:22:34 -07:00
Shannon Young fa50f74e9c Throw assert on multiple lines - not currently supported. 2016-06-27 16:20:16 -07:00
Shannon Young 903e1cbffe Added example usage of confirmation form item to ORKTest 2016-06-27 16:20:16 -07:00
Shannon Young 4cda98e896 Clean up tab spacing for readability. 2016-06-27 16:18:19 -07:00
Shannon Young 525d5b2350 Added additional comment and tests for the confirmation answer form item. 2016-06-27 16:18:19 -07:00
Shannon Young 191c17930d Move confirm answer to ORKFormItem 2016-06-27 16:18:19 -07:00
Shannon Young cfe39f8201 Fix issue with autocapitolization 2016-06-27 16:18:19 -07:00
Shannon Young 4b35370e80 Expose method for instantiating an answer format for confirmation of another field.
This answer format is intended to be used with an `ORKFormStep` in order to confirm a previous formItem input. Example usage includes a password or participant identifier that is used to anonymously identify a study participant.
2016-06-27 16:18:19 -07:00
Yuan Zhu 2404b20433 Merge pull request #739 from Sage-Bionetworks/pr/ui-task-delegate-vc-will-disappear
Add delegate method to task view controller for step will disappear
2016-06-27 14:59:45 -07:00
Shannon Young a20f953467 Add example that uses the step will disappear method. 2016-06-27 14:36:45 -07:00
Shannon Young f41480f5bb Add unit test of the delgate callback 2016-06-24 12:18:45 -07:00
Shannon Young ddef74e9cc Updated comment and added direction to the method signature. 2016-06-23 17:31:48 -07:00
Yuan Zhu a50f7cbc2f Merge pull request #736 from Sage-Bionetworks/pr/fix-HKQuantityTypeRecorder
Fix ORKHealthQuantityTypeRecorder to allow for iOS 10 and iOS 8 support
2016-06-23 16:47:52 -07:00
Shannon Young 5715ea13c5 Update comment to match method signature. 2016-06-23 16:33:04 -07:00
Shannon Young 41575b830c Add delegate method to task view controller for step will disappear 2016-06-23 16:27:47 -07:00
Shannon Young c6907b1e9e Add comment explaining why tracking both object and uint 2016-06-23 14:46:41 -07:00
Yuan Zhu 286f49bb5d Merge pull request #737 from Sage-Bionetworks/pr/task-copy-with-steps
Copy the properties of an ORKOrderedTask (or subclass) and mutate the steps.
2016-06-23 14:00:35 -07:00
Yuan Zhu 59ac9c3213 Merge pull request #729 from Sage-Bionetworks/pr/fix-result-nullable-date
ORKResult start/end dates should not be nullable
2016-06-23 13:29:31 -07:00
Shannon Young 0cfce94dd6 Copy the properties of an ORKOrderedTask (or subclass) and mutate the steps. 2016-06-22 22:56:00 -07:00
Ricardo Sánchez-Sáez cb4ff44859 [Charts] Rename 'pointForPlotIndex:' (and related methods) to 'dataPointForPlotIndex:'
Also rename 'ORKGraphChartType' to 'ORKValueCollectionType'.
2016-06-23 02:51:02 +01:00
Shannon Young 0375b70146 Wrap the interface for iOS 8 HKAnchoredObjectQuery init
Use a #ifdef __IPHONE_10_0 to only expose the interface if it would not otherwise be available.
2016-06-22 13:29:19 -07:00
Shannon Young e9e2434d5f Add deprecation warning into protocol work-around for HK iOS 10 support 2016-06-22 11:45:13 -07:00
Shannon Young 72fb6d5138 Updated implementation for iOS 8 compatibility to HealthKit for iOS 10 2016-06-22 11:45:05 -07:00
Shannon Young 60aa464b02 Add work-around for missing method for HKAnchoredObjectQuery 2016-06-22 11:44:57 -07:00
Ricardo Sánchez-Sáez 8474d39cdf Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-ORKBarGraphChart
# Conflicts:
#	ResearchKit/Charts/ORKGraphChartView.m
#	ResearchKit/Charts/ORKGraphChartView_Internal.h
#	ResearchKit/Charts/ORKLineGraphChartView.m
#	ResearchKit/Common/ORKHelpers.h
2016-06-22 03:09:42 +01:00
Erin Mounts 3f258d2c6c ORKResult start/end dates should not be nullable 2016-06-21 16:37:48 -07:00
Shannon Young aad49eac86 Added delegate method for discarding results without confirming cancel. 2016-06-21 16:12:25 -07:00
Shannon Young 4b610ee085 Log an error with restoring audio session but do not forward.
If an error occurs with restoring the saved audio session category, then log the error but otherwise ignore. Do not want to fail the task.
2016-06-21 15:49:05 -07:00
Yuan Zhu 78d59f7ed8 Merge pull request #636 from rsanchezsaez/rsanchezsaez-ORKNavigableOrderedTask
[ORKNavigableOrderedTask] Implement skip navigation rules
2016-06-21 15:12:32 -07:00
Shannon Young a147b2e6e3 Report error (if any) for restoring the saved audio session category 2016-06-21 14:54:46 -07:00
Yuan Zhu 78bc96956c Merge pull request #724 from Sage-Bionetworks/pr/update-module-voice-threshold
Audio ActiveTask View - add ability to define threshold value
2016-06-21 14:30:23 -07:00
Shannon Young 0e9ce26b82 Mark audio prompt property as copy rather than strong 2016-06-21 14:28:56 -07:00
Shannon Young e2f284a4cb Only update the view threshold if the view is loaded 2016-06-21 14:26:52 -07:00
Shannon Young 90af9211eb Only set the threshold if greater than 0 2016-06-21 14:25:15 -07:00
Shannon Young 1107bd9dba Do not set the initial threshold. Zero by default is ignored. 2016-06-21 14:22:04 -07:00
Yuan Zhu 4bcc83ecd3 Merge pull request #716 from king7532/swift3
Update `ORKPredicateStepNavigationRule` Swift 2.x formatting to match…
2016-06-21 14:19:27 -07:00
Ricardo Sánchez-Sáez aa86bf3bed [ORKNavigableOrderedTask] Return empty dictionaries instead of empty arrays 2016-06-21 21:51:00 +01:00
Erin Mounts 5de1888375 Fix audio-prompts-coming-from-earpiece bug
save the current AVAudioSession category before starting voice recording and then restore afterward
2016-06-21 13:20:51 -07:00
Everest Liu 01eab7bd0c PAN-98 - Audio ActiveTask View - add ability to define threshold value 2016-06-21 13:10:17 -07:00
Yuan Zhu 1da1d632b6 Merge pull request #718 from Sage-Bionetworks/pr/fix-defaultResultStore
Fix bug where the defaultResultSource is using ivar rather than public property accessor
2016-06-21 11:11:52 -07:00
Shannon Young 072d19c84b Fix bug where the defaultResultSource is using ivar rather than public property accessor 2016-06-21 11:06:27 -07:00
Yuan Zhu 11effe846e Merge pull request #625 from shazino/ib-graph-chart
Make chart and graph IBInspectable/IBDesignable
2016-06-21 10:18:53 -07:00
Umer Khan c185fce465 Merge pull request #583 from chb/feature/passcode-override
Improve Passcode View
2016-06-20 14:47:53 -05:00
Benjamin King 4863368e23 Update ORKPredicateStepNavigationRule Swift 2.x formatting to match the style guide 2016-06-20 15:07:39 -04:00
Yuan Zhu 1ce947395d Merge pull request #715 from king7532/swift3
Update extension to `ORKPredicateStepNavigationRule` to support Swift 3 and 2.x
2016-06-20 11:10:18 -07:00
Benjamin King c15b98e41a Update extension to ORKPredicateStepNavigationRule to support Swift 3 and 2.x 2016-06-18 21:32:37 -04:00
Andrew Hill 9341e85030 Merge branch 'ResearchKit/master' 2016-06-14 20:14:53 +01:00
Steve Moser 1934f143a5 Add suggested fixes for 12 iPad Pro metrics 2016-06-13 12:54:29 -04:00
Yuan Zhu 9b1efb8641 Merge pull request #707 from malhal/master
Fix for blank white screen when app activates back from viewing the N…
2016-06-10 14:30:59 -07:00
Malcolm Hall c1f30947be Fix for blank white screen when app activates back from viewing the NC or a privacy prompt 2016-06-08 20:09:11 +01:00
Steve Moser dc22fe8191 Add initial support for 12.9 inch iPad Pro
Needs feedback on naming and metrics
2016-06-03 15:11:43 -04:00
Yuan Zhu 4259a1cc92 Update pod spec version number. 2016-05-24 10:54:15 -07:00
Ben DiFrancesco 70d4532d0e Declare ORKScrollToTopAnimationDuration and ORKCGFloatInvalidValue as extern in ORKHelpers.h; fixes #679 2016-05-24 10:53:53 -07:00
Yuan Zhu 8e2313118f Merge pull request #680 from apbendi/header-fix
Fix declaration of constants in ORKHelpers
2016-05-17 11:12:34 -07:00
Ben DiFrancesco 354cee7e7a Declare ORKScrollToTopAnimationDuration and ORKCGFloatInvalidValue as extern in ORKHelpers.h; fixes #679 2016-05-12 16:18:20 -04:00
Ricardo Sánchez-Sáez 7cfb8960c9 [ORKHeightPicker] Rename variables in internal method 2016-05-05 01:36:04 +01:00
Ricardo Sánchez-Sáez cabaecb5d1 [ORKHeightAnswerFormat] Use ORK_DECODE_ENUM() and ORK_ENCODE_ENUM() 2016-05-05 01:08:37 +01:00
Ricardo Sánchez-Sáez 99bd214f23 [Misc] Rename 'ORKNumberFormatter' to 'ORKDecimalNumberFormatter' 2016-05-05 01:04:07 +01:00
Umer Khan ea7c941424 Merge pull request #662 from dukemike/issues/658
allow plot fill color of ORKLineGraphChartView to be set by the delegate
2016-05-04 13:17:02 -07:00
Umer Khan 75e880e1d9 Merge pull request #653 from samfalconer/master
Update ORKSignatureView to support pressure sensitive stroke widths.
2016-05-03 11:07:35 -07:00
Andrew Hill a788e35d25 Merge branch 'ResearchKit/master' 2016-05-02 10:50:32 +01:00
Yuan Zhu e9d7b847da Merge pull request #638 from evands/improve-vertical-slider-layout
Improved flexibility for laying out a vertical ORKScaleSliderView.
2016-04-29 13:47:56 -07:00
Yuan Zhu b0f5e2cbb7 Merge pull request #650 from dwarfland/master
Typo/case fix in #include
2016-04-28 16:38:31 -07:00
Yuan Zhu 2c4ef0f73e Merge pull request #664 from ResearchKit/stable
Merge class visibility fix from Stable to Master
2016-04-19 17:12:02 -07:00
Yuan Zhu 23900bed0e Merge pull request #663 from YuanZhu-apple/stable_class_visibility
Fix class visibility
2016-04-19 17:10:44 -07:00
Yuan Zhu 8c8a1adc47 Fix class visibility 2016-04-19 17:05:49 -07:00
Mike Revoir 4ada9cf5ff Merge pull request #1 from rsanchezsaez/dukemike-issue-658
[ORKLineGraphChartView] Improvements to new fill color method
2016-04-14 10:56:03 -04:00
Ricardo Sánchez-Sáez 7b23d8b21e [ORKLineGraphChartView] Fix issue where fill color wasn't correctly obtained on updatePlotColors method
Also:
- Have points and lines to be drawn above their corresponding fill
- Move fillColorForPlotIndex: to ORKLineGraphChartView.m
- Minor headerdoc improvement
2016-04-13 20:01:57 +01:00
Ricardo Sánchez-Sáez d2f26a5ab9 [ORKTest] Add ORKLineGraphChartView's graphChartView:fillColorForPlotIndex: method test 2016-04-13 19:58:58 +01:00
Mike Revoir c170a8c38a reformat whitespace. refs #658 2016-04-13 10:56:54 -04:00
Mike Revoir 934aa3283b allow plot fill color to be set. refs #658 2016-04-13 10:56:47 -04:00
Sam Falconer 639f75eaa6 Merge if statements.
In addition to checking for 3D touch, check for Apple Pencil
to see if we can get force from that.
2016-04-06 18:11:01 -04:00
Michal Zaborowski 5f969da0d7 Adding tap duration to Tapping Task Issue #561 2016-04-06 19:49:58 +02:00
Sam Falconer 080c69bd8b Update ORKSignatureView to support pressure sensitive stroke widths.
Add property for setting the stroke width variation (default to 3pts).

If the device supports 3D touch, use the true pressure to determine
how thick the line should be at a given point.

If the device does not support 3D touch, use the speed of the stroke
to determine how thick the line should be at a given point.
2016-04-05 14:36:53 -04:00
Ricardo Sánchez-Sáez 42c12ca73f [ORKHeightAnswerFormat] Replace 'BOOL useMetricSystem' by 'ORKMeasurementSystem measurementSystem'
Valid values are:
- ORKMeasurementSystemLocal
- ORKMeasurementSystemMetric
- ORKMeasurementSystemUSC
2016-03-30 00:56:12 +01:00
Ricardo Sánchez-Sáez 025581ad55 [ORKHealthKitQuantityTypeAnswerFormat] Use 'ORKHeightAnswerFormat' as the impliedAnswerFormat when the quantity type is 'HKQuantityTypeIdentifierHeight 2016-03-29 21:53:30 +01:00
Ricardo Sánchez-Sáez 65aee797ce [ORKHealthKitCharacteristicTypeAnswerFormat] Move 'defaultDate', 'minimumDate', 'maximumDate' and 'calendar' default value calculation to impliedAnswerFormat's initialization
This prevents archiving of stale date and calendar values.
2016-03-29 20:47:46 +01:00
Yuan Zhu f7ea0167b1 Merge pull request #641 from rsanchezsaez/rsanchezsaez-ORKStepResult.enabledAssistiveTechnology
[ORKStepResult] Add 'enabledAssistiveTechnology' property
2016-03-29 12:39:21 -07:00
Ricardo Sánchez-Sáez a5a8531fdf [ORKStepResult] Rename 'checkEnabledAssistiveTechnology' to 'updateEnabledAssistiveTechnology' 2016-03-29 20:23:58 +01:00
Yuan Zhu e60db320ed Merge pull request #645 from rsanchezsaez/rsanchezsaez-ORKCountdownStep
[Framework] Expose ORKCountdownStep and ORKCompletionStep publicly
2016-03-29 11:08:23 -07:00
marc hoffman 8a6895d762 ORKWaitStepViewController.h was marked as private and thus missing (but needed) from compiled .framework 2016-03-29 11:26:53 -04:00
marc hoffman 2ac579a610 Type/case fix in #include 2016-03-29 11:20:57 -04:00
Ricardo Sánchez-Sáez 4b9ae8e404 [ORKTest] Fix small indentation misalign 2016-03-29 14:12:14 +01:00
Ricardo Sánchez-Sáez f7d1591c19 [Misc] Change all framework #imports to @import
Also:
- Change some #imports to directly refer headers instead of going though the framework header because it enables it be included as a module through Cocoapods.
- Improve unit test encapsulation by making some classes (recorders) and methods available in the private header
2016-03-28 20:06:58 +01:00
Ricardo Sánchez-Sáez 9b539d7faf [Misc] Remove needless #imports from ORKVerticalContainerView 2016-03-28 16:05:34 +01:00
Ricardo Sánchez-Sáez e515278b4c [Misc] Perform #import section refactor to reduce header interdependency
Compilation time after you modify a header file has been greatly improved by avoiding including the umbrella headers (ResearchKit.h and ResearchKit_Private.h) in any of the framework files.

Also:
- Restructure .m files #import section into a hierarchy of alphabetically sorted subsections separated by one newline (1. local views and controls; 2. view controllers and recorders; 3. model files; 4. general files and helpers, 5. iOS frameworks). The #import order follows advice found here: http://qualitycoding.org/import-order/
- Remove needless and duplicate imports from .m files
- Make sure all headers include at least Foundation or UIKit; except Private or Internal headers which only include their own class header at the next public level
- Rename ORKHelpers.h to ORKHelpers_Internal.h (it is not public, and its name was misleading given that we also have ORKHelpers_Private.h).
- Add a few missing NS_ASSUME_NONNULL_BEGIN/NS_ASSUME_NONNULL_END annotation in headers
- Add a few missing double newline before and after import section
2016-03-28 15:34:27 +01:00
WEI-JEN TU e3b2d91a8b ORKQuestionResult could get truncated Chinese texts before textFieldDidEndEditing is called
ORKQuestionResult could get truncated Chinese texts before
textFieldDidEndEditing is called in UITextFieldDelegate

The repository “truncated-branch” is revised to be able to demonstrate
the scenario right away. Also uncomment line 202 in
ORKSurveyAnswerCellForText addresses the issue.

There are two videos as well to elaborate truncated Chinese texts and
difference between before and after.
Before: (Notice that the last character is always truncated before
textFieldDidEndEditing is called in UITextFieldDelegate)
https://db.tt/jHlCyr62

After:
https://db.tt/jeh1O20k
2016-03-26 12:07:17 -07:00
WEI-JEN TU da41b8a43b Merge remote-tracking branch 'ResearchKit/master' 2016-03-26 10:41:03 -07:00
Ricardo Sánchez-Sáez 86273181ac [Framework] Expose ORKCountdownStep and ORKCompletionStep publicly 2016-03-24 17:29:05 +00:00
Ricardo Sánchez-Sáez 930d94f804 [ORKSpatialSpanMemoryTask] Rename methods to avoid abbreviations and add step documentation
(Missing step documentation was causing broken links in the documentation.)
2016-03-24 17:08:56 +00:00
Ricardo Sánchez-Sáez d783c0b2b6 [Cocoapods] Fix podspec to include swift files 2016-03-24 15:23:50 +00:00
Ricardo Sánchez-Sáez 92cc2c0ef9 [ORKTest] Add 'ORKHeightAnswerFormat' step to review example
Fix review step text output which was showing total inches instead of decomposed feet and inches.
2016-03-24 15:20:57 +00:00
Ricardo Sánchez-Sáez 275b7b5ff9 [ORKAnswerFormat] Implement picker-based 'ORKHeightAnswerFormat'
Details:
- Metric and imperial measuring systems support
- Standalone question steps and on form steps support
- Serialization unit tests implemented

Notes:
- For input it uses the newly added 'ORKHeighPicker' class
- Height limits and default value are hardcoded into the picker, taking the same values as the Health App: [0 ft, 0 in - 9 ft, 11 in] range, default: 5 ft, 4 in; [0 cm - 299 cm] range, default: 162 cm
- Results are output as an 'ORKNumericResult' object, with the unit canonically set to 'in' or 'cm' depending on the chosen measuring system (on the imperial system, feet and inches always get converted to total inches when stored in the outputted result)
- Visually, the picker and the chosen answer in form steps display the 'cm' and decomposed 'ft in' values, with their units localized if applicable (unlike the canonical result units which are never localized)
2016-03-24 14:51:36 +00:00
Ricardo Sánchez-Sáez 642f87576a [Misc] Avoid some abbreviations and needless intermediate variables 2016-03-23 17:43:44 +00:00
Ricardo Sánchez-Sáez 4735bc5d47 [Misc] Add missing whitespace around '!=' operator 2016-03-22 18:43:59 +00:00
Ricardo Sánchez-Sáez 0e29f50f77 [ORKStepResult] Add 'enabledAssistiveTechnology' property
The property can have the following values:
 - `UIAccessibilityNotificationVoiceOverIdentifier` if Voice Over was active
 - `UIAccessibilityNotificationSwitchControlIdentifier` if Switch Control was active
2016-03-22 18:34:09 +00:00
Ricardo Sánchez-Sáez daac3505b4 [ORKSample] Small improvement to 40x40 app icon 2016-03-22 12:45:09 +00:00
Ricardo Sánchez-Sáez 89838d63bd [Misc] Update to Swift 2.2 code (Xcode 7.3 only)
(Avoid using newly deprecated methods)
2016-03-22 12:22:33 +00:00
Ricardo Sánchez-Sáez 1337dbf851 [ORKDirectionView] Avoid CGMutablePath leak 2016-03-22 12:15:24 +00:00
Ricardo Sánchez-Sáez 0c60532068 [ORKTextScaleAnswerFormat] Fix issue potentially causing 'nil' to try to be added to an array 2016-03-22 12:12:07 +00:00
Ricardo Sánchez-Sáez ea0fb64319 [ORKHealthKitCharacteristicTypeAnswerFormat] Expose 'defaultDate', 'minimumDate', 'maximumDate' and 'calendar'
Used to customize the presented date picker, only applicable to the 'HKCharacteristicTypeIdentifierDateOfBirth' characteristic type.
2016-03-21 18:50:27 +00:00
Ricardo Sánchez-Sáez 14bb563d26 [ORKPieChartView] Implement new ORKPieChartLegendCollectionViewLayout
It evenly distributes the cells between all the rows, and lays them out as compactly possible along the center by increasing leading and trailing padding.
2016-03-18 18:04:02 +00:00
Ricardo Sánchez-Sáez 09b7adc981 [Charts] Make scrubber to be shown on a static long press
Adds public UILongPressGestureRecognizer property.
2016-03-18 11:57:03 +00:00
Ricardo Sánchez-Sáez 412f30652f [Charts] Adjust reference line boundaries so they rest on full pixels on iPhone 6 and 6 Plus 2016-03-17 16:46:56 +00:00
Ricardo Sánchez-Sáez 9ef8b4a980 [Charts] Make sure ORKBarGraphChartView bars and ORKLineGraphChartView fill start at whole pixel coordinates 2016-03-17 15:47:20 +00:00
Ricardo Sánchez-Sáez ce365bbe10 [Charts] Make auto-calculated reduced-alpha colors opaque, so reference lines don't show below bar graphs 2016-03-16 21:15:15 +00:00
Ricardo Sánchez-Sáez 778bcf71e0 [ORKValueStack] Rename '-initWithStackedValueArray:' to '-initWithStackedValues:' and fix documentation 2016-03-16 18:05:15 +00:00
Ricardo Sánchez-Sáez bf94333d32 [ORKChartTypes] Make 'stackedValues' property to have copy semantics 2016-03-16 17:45:56 +00:00
Yuan Zhu 9f5caad71d Merge pull request #445 from rsanchezsaez/rsanchezsaez-HomogenousORKTextFieldView
[ORKTextField] Coherent placeholder handling
2016-03-16 10:07:20 -07:00
Ricardo Sánchez-Sáez 14fce4445f [Charts] Minor documentation improvements 2016-03-16 16:48:30 +00:00
Ricardo Sánchez-Sáez 1984b46efb [ORKNavigableOrderedTask] Add nullability annotations when returning individual rules; make sure the rule dictionary property always returns a proper non-mutable dictionary 2016-03-16 16:20:40 +00:00
Ricardo Sánchez-Sáez 02a822baef [Misc] Make sure -isEqual: method always uses the property format when accessing the variables to compare 2016-03-16 16:02:01 +00:00
Ricardo Sánchez-Sáez cdaa4d4c91 [Misc] Make sure +(instancetype)new is NS_UNAVAILABLE when init is so.
Also, throw exception on unavailable methods where appropriate. Make sure ORKTest unit tests continue to pass.
2016-03-16 15:55:09 +00:00
Ricardo Sánchez-Sáez 6e4a4560d8 [Misc] Use property syntax for accessing 'hash' 2016-03-16 14:04:46 +00:00
Ricardo Sánchez-Sáez 657bcab2f7 [Misc] Use 'error' instead of the non-standard 'err' abbreviation
(https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html#//apple_ref/doc/uid/20001285-BCIHCGAE)
2016-03-16 13:34:41 +00:00
Ricardo Sánchez-Sáez b8a999995f [Misc] Remove explicit __autoreleasing annotation in indirect parameters to avoid noisy code
Indirect parameters are __autoreleasing implicitly: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#indirect-parameters
Also, add _Nullable annotation to indirect parameters in headers, and homogenize whitespace surrounding it.
2016-03-16 13:31:50 +00:00
Ricardo Sánchez-Sáez 28ee60beb7 [Coding Style Guide] Add some whitespace notes, and favor '_Nullable' over '__nullable. 2016-03-16 13:21:02 +00:00
Ricardo Sánchez-Sáez e305e3c4b2 [ORKNavigationContainerView] Use explicit struct initialization 2016-03-16 13:17:03 +00:00
Ricardo Sánchez-Sáez 90f5a2cc62 [Misc] Avoid needless returns from void functions 2016-03-16 13:16:58 +00:00
Ricardo Sánchez-Sáez 75c75901a3 [Misc] Use __typeof instead of typeof
(Avoids pedantic warning)
2016-03-16 13:16:53 +00:00
Ricardo Sánchez-Sáez c5396e8ae6 [ORKHelpers] Remove needless struct casts 2016-03-16 13:16:46 +00:00
Ricardo Sánchez-Sáez 942a092bd1 [Misc] Remove extraneous ; symbols 2016-03-16 13:16:41 +00:00
Ricardo Sánchez-Sáez 1cb09d68d3 [Charts] Draw reference lines for Bar Graph Chart View on ORKCatalog example 2016-03-15 18:32:25 +00:00
Evan D. Schoenberg, M.D fd11ee1e89 Improved flexibility for laying out vertical ORKScaleSliderView. This allows longer text labels by setting constraints to allow the slider to move as far left as 25% the width of the view, and allows the text labels to expand to the edge of the view (less a SideLabelMargin margin width). 2016-03-15 13:32:19 -04:00
Ricardo Sánchez-Sáez 878acecad6 [ORKSpatialSpanTargetView] Remove needsless '_' prefix from static variable name 2016-03-15 17:07:20 +00:00
Ricardo Sánchez-Sáez 5d1fe51b42 [Coding Style Guide] Add 'Spaces in array and dictionary literals' subsection 2016-03-15 16:31:34 +00:00
Ricardo Sánchez-Sáez 077dfcc4ab [Misc] Additional whitespace homogenization regarding space before dictionary keys and around the tertiary operator (?:) 2016-03-15 16:09:19 +00:00
Ricardo Sánchez-Sáez f24c371541 [Misc] Rename STRONGTYPE() to ORKStrongTypeOf() and introduce ORKWeakTypeOf() for homogeneity 2016-03-15 15:31:26 +00:00
Ricardo Sánchez-Sáez 7a0101c12b [Project] Rename ORKDefines_Private.h to ORKHelpers_Private.h
(Since it has fuctions, not macros.)

Also, move localization functions from ORKHelpers_Private.h to ORKHelpers.h (the latter is an internal file, so encapsulation is better).
2016-03-15 14:54:55 +00:00
Ricardo Sánchez-Sáez 887f8dd6bd [Project] Extract type definitions from 'ORKDefines.h' into the new 'ORKTypes.h' file 2016-03-15 12:42:16 +00:00
Ricardo Sánchez-Sáez f6c8bc939b [ORKHelpers] Use ORK_INLINE macro 2016-03-15 12:14:44 +00:00
Ricardo Sánchez-Sáez b6cc2f3add [ORKGraphChartView] Use ORK_INLINE macro 2016-03-15 11:47:36 +00:00
Ricardo Sánchez-Sáez 24929ca8b1 [ORKHelpers] Rename STRINGIFY to ORK_STRINGIFY 2016-03-14 15:35:15 +00:00
Ricardo Sánchez-Sáez 8c270dca89 [ORKHelpers] Avoid using the reserved '__' prefix 2016-03-14 15:31:56 +00:00
Ricardo Sánchez-Sáez 129ee6baef [ORKKeychainWrapper]: Use '_Nullable' instead of '__nullable' (Xcode 7 style) 2016-03-14 15:23:26 +00:00
Ricardo Sánchez-Sáez a2e4b5aa1c [Misc] Always add space before '__autoreleasing' 2016-03-14 15:22:15 +00:00
Ricardo Sánchez-Sáez 75047cabb2 [ORKHolePegTest] Replace 'can not' by 'cannot' in exception messages 2016-03-14 15:09:58 +00:00
Ricardo Sánchez-Sáez 8a3fea6488 [Misc] Make some code to conform to code homogenization
- Remove space after unary '!' operator
- Remove space after pointer '*' start
2016-03-14 15:08:45 +00:00
Ricardo Sánchez-Sáez 57cbebae64 [ORKNavigableOrderedTask] Implement skip navigation rules
Introduce the ORKSkipStepNavigationRule and ORKPredicateSkipStepNavigationRule classes, and the appropriate 'ORKNavigableOrderedTask' methods to insert, view and remove them.
Implement ORKTest example code within the Navigable Loop Task Items.
Implement unit tests for the new functionality, and makes sure all serialization tests continue to pass.
2016-03-11 18:41:32 +00:00
Andrew Hill b13a470348 Merge branch 'ResearchKit/master' 2016-03-11 12:45:54 +00:00
Ricardo Sánchez-Sáez 2ea828e29e [ORKBarGraphChartView] Made BarWidth constant static 2016-03-11 11:56:08 +00:00
Ricardo Sánchez-Sáez 7efb9ecb36 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-ORKBarGraphChart 2016-03-10 18:10:44 +00:00
Ricardo Sánchez-Sáez ea777873af [Charts] Make 'ORKValueRange' and 'ORKValueStack' to use 'double' instead of 'CGFloat' 2016-03-10 17:58:46 +00:00
Ricardo Sánchez-Sáez fc7c55c3ab [ORKValueRange] Raname 'isEmpty' property to 'isEmptyRange' 2016-03-10 17:24:13 +00:00
Ricardo Sánchez-Sáez df05877256 [Charts] Rename 'ORKFloatRange' and 'ORKFloatStack' to 'ORKValueRange' and 'ORKValueStack' 2016-03-10 17:20:13 +00:00
vtourraine 9025045a4c [Charts] Add sample graph chart data source for Interface Builder 2016-03-10 15:47:14 +01:00
vtourraine 0571b6e960 [Charts] Add sample pie chart data source for Interface Builder 2016-03-10 15:01:09 +01:00
Yuan Zhu d1fbc178a1 Merge pull request #591 from rsanchezsaez/rsanchezsaez-master-ORKSampleIcon
[ORKSample] Add app icon
2016-03-09 16:12:08 -08:00
Yuan Zhu 6a2f18af4d Merge pull request #629 from evands/vertical-slider-multiline
Allow 2 lines of text on vertical scale sliders
2016-03-09 16:10:45 -08:00
Yuan Zhu cc352493f9 Merge pull request #626 from weijentu/master
About ORKQuestionType for ORKTextAnswerFormat?
2016-03-09 11:00:42 -08:00
Yuan Zhu 43a4379c8e Merge pull request #621 from pra85/patch-1
[RELEASE-NOTES.md] Fix a typo
2016-03-09 10:30:43 -08:00
Evan D. Schoenberg, M.D 5c3db570f7 Allow unlimited lines for vertical scale slider views rather than 2 as per discussion in #629 2016-03-08 21:15:00 -05:00
Ricardo Sánchez-Sáez 0980410b95 [ORKFloatRange] Throw exception if 'maximumValue' is lower than 'minimumValue 2016-03-08 18:05:42 +00:00
Ricardo Sánchez-Sáez 2e5d784608 [ORKFloatStack] Add comma before the 'and' separator 2016-03-08 17:56:15 +00:00
Ricardo Sánchez-Sáez 288d710e51 [ORKGraphChartView] Fix issue with wrong UIAccessibilityIsVoiceOverRunning() check
The issue prevented accessibility elements to be properly set.
2016-03-08 17:49:21 +00:00
Ricardo Sánchez-Sáez cc46125c69 [ORKFloatStack] Implement accessibilityLabel method
(Used by Voice Over)
2016-03-08 17:48:37 +00:00
Ricardo Sánchez-Sáez ca94aa7468 [ORKChartTypes] Conform ORKFloatRange and ORKFloatStack descriptions to ObjC conventions 2016-03-08 17:46:09 +00:00
Ricardo Sánchez-Sáez d0293a0ee7 [ORKBarGraphChartView] Fix display animation implementation
Also, add ORKTest appearance tests, and make other graph tests more comprehensive by adding empty points at the middle.
2016-03-08 17:45:47 +00:00
Ricardo Sánchez-Sáez b8c80c70c7 [ORKBarGraphChartView] Implement most of bar graph chart functionality
Some details:
- Added ORKCatalog example and ORKTest test
- Conform ORKFloatRange and ORKFloatStack to the new ORKGraphChartType protocol. Move them to the ORKChartTypes.h/m files.
- ORKLineGraphChartView and ORKDiscreteGraphChartView now inherit from the abstract ORKFloatRangeGraphChartViewClass.
- There are now two concrete protocolsL ORKFloatRangeGraphChartViewDataSource (used by ORKLineGraphChartView and ORKDiscreteGraphChartView) and ORKFloatStackGraphChartViewDataSource (used by ORKBarGraphChartView). Both inherit from the abstract ORKGraphChartViewDataSource protocol.

Things yet to do:
- Implement appearing animations
- Implement ORKTest appearance-properties testing
- Implement and test bar chart view accessibility
2016-03-08 17:45:04 +00:00
Evan D. Schoenberg, M.D 40e328e29e Allow 2 lines of text on vertical scale sliders, as there is plenty of space for this to fit comfortably. 2016-03-05 09:51:20 -08:00
Ricardo Sánchez-Sáez 3f89fba2cf [Charts] Implement first steps for ORKBarGraphChartView
Also, makes ORKTest's 'ORKDiscreteGraphChartView' tests more comprehensive.
2016-03-01 17:14:55 +00:00
Ricardo Sánchez-Sáez bece29b351 [ORKGraphChartView] Fix global appearance proxy tintColor taking over custom local tintColor 2016-03-01 16:02:43 +00:00
Allen Tu 4d1601a787 Set questionType for ORKEmailAnswerFormat with ORKQuestionTypeText
Discussion: An ORKEmailAnswerFormat object is implied with
ORKTextAnswerFormat and produces an ORKTextQuestionResult object, too.
Could it be better to set its questionType to ORKQuestionTypeText?
2016-02-26 21:59:13 +08:00
Allen Tu 80d7685ab3 Merge remote-tracking branch 'ResearchKit/master' 2016-02-26 21:43:36 +08:00
vtourraine 6e1334a2fc Make chart and graph IBDesignable 2016-02-26 14:39:16 +01:00
vtourraine 3c550b54b4 Fix IBInspectable for readonly properties 2016-02-26 14:13:38 +01:00
vtourraine 7ca7079522 Make chart and graph properties IBInspectable 2016-02-26 10:49:19 +01:00
Prayag Verma e4af7fe7fe [RELEASE-NOTES.md] Fix a typo
Remove extra `the`
2016-02-18 13:07:24 +05:30
Jared Crawford 8c3b5ce81f Update delegate method documentation 2016-02-17 17:27:34 -08:00
Jared Crawford 783ad4c6b4 Adds support for drawing plots within a chart without individual data point indicators 2016-02-17 17:17:40 -08:00
Jared Crawford b85182b372 Fix typos 2016-02-12 12:27:58 -08:00
Jared Crawford 6e075cbfe3 Add a result predicate for determining if the user selected accept or decline in a consent signature step, allowing for custom navigation rules, such as skipping to the end of a survey if the user does not consent. 2016-02-11 18:07:08 -08:00
Yuan Zhu 410affbf5d Merge pull request #619 from rsanchezsaez/rsanchezsaez-UnitTests
[ORKNavigableOrderedTask] Fix 'shouldReportProgress' being ignored by NSSecureCoding and NSCopying
2016-02-08 15:34:57 -08:00
Ricardo Sánchez-Sáez 182960a263 [ORKGraphChartView] Fix small documentation issues 2016-02-08 18:24:51 +00:00
Ricardo Sánchez-Sáez 0971ef71f4 [ORKSample] Fix typos in variable names 2016-02-08 17:52:46 +00:00
Ricardo Sánchez-Sáez 92ca8f86a5 [ORKGraphChartView] Fix error in accessibility string key 2016-02-08 17:50:45 +00:00
Ricardo Sánchez-Sáez 24c46898e8 [ORKLineGraphChartView] Go back to consistently using minimumValue as main plotted data 2016-02-08 16:40:34 +00:00
Ricardo Sánchez-Sáez 065a02eff1 [ORKNavigableOrderedTask] Fix 'shouldReportProgress' being ignored by NSSecureCoding and NSCopying
Also, fix ORKTest's unit tests.
2016-02-08 16:33:22 +00:00
Ricardo Sánchez-Sáez 2db99d6152 [Charts] Rename ORKRangedPoint to ORKFloatRange
Also:
- Improve documentation.
- Fix ORKFloatRange's 'hasEmptyRange' property being always 'NO'.
- Fix typo in ORKGraphChartView's 'colorForPlotIndex:' method.
2016-02-08 16:24:33 +00:00
Ricardo Sánchez-Sáez f6cb8b09f0 [ORKGraphChartView] Make the discrete graph to snap on the actual chosen plot index when scrubbing 2016-02-07 18:51:06 +00:00
Ricardo Sánchez-Sáez f9d49594fe [ORKGraphVhartView] Fix scrubber not being correctly positioned for last data point in discrete graphs 2016-02-07 15:41:07 +00:00
Yuan Zhu 62a31b087a Merge pull request #618 from rsanchezsaez/rsanchezsaez-ReleaseNotes
[RELEASE-NOTES.md] Improvements
2016-02-05 12:27:31 -08:00
Ricardo Sánchez-Sáez 70fd57488d [RELEASE-NOTES.md] Fix some typos, rewrite some sentences and improve formatting 2016-02-05 18:29:06 +00:00
Yuan Zhu 1f457e1d54 Merge pull request #615 from apbendi/nav-ordered-progress
Allow user to opt-in to linear progress reporting on ORKNavigableOrderedTask
2016-02-03 10:21:30 -08:00
Ben DiFrancesco 729247cfcd Allow user to opt-in to linear progress reporting on ORKNavigableOrderedTask 2016-01-29 10:50:25 -05:00
Yuan Zhu 218b8af66a Merge pull request #604 from rsanchezsaez/rsanchezsaez-ORKTestTests
[ORKTestTests] Fix unit tests
2016-01-27 14:21:42 -08:00
Ricardo Sánchez-Sáez 069c388cb3 [ORKTest] Remove README.md from target 2016-01-27 19:34:13 +00:00
Ricardo Sánchez-Sáez e199db13b4 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-ORKTestTests 2016-01-27 19:30:50 +00:00
Ricardo Sánchez-Sáez a96c8b9540 [ResearchKit] Fix unit tests
- Fixes tests to reflect the new empty answer for a Choice Answer Format being ORKNullAnswerValue() instead of an empty array (introduced on the Review Step feature).
- Fixes test for task step identifier uniqueness validation (it now takes place on task init).
2016-01-27 13:21:05 +00:00
Ricardo Sánchez-Sáez 865275d3aa [Projects] Fix ResearchKit framework linkage for all 3 apps
This links and embeds the workspace instance of ResearchKit from the three subprojects.

Also:
- Remove ResearchKit subproject reference from ORKCatalog.
- Link HealthKit framework from ORKSample.
- Link HealthKit and MapKit in an optional way.
- Reorganise frameworks into Framework group for each subproject.
2016-01-27 12:39:55 +00:00
Yuan Zhu a1d29fe225 Merge pull request #612 from CareEvolution/ORKWaitStepView-header-fix
Revert ORKWaitStepView.h to Project visibility
2016-01-26 11:32:03 -08:00
Scott Guelich 67bcc93947 Remove Private attribute from internal headers 2016-01-26 11:29:18 -08:00
Yuan Zhu 8e8fabf79f Merge pull request #605 from rsanchezsaez/rsanchezsaez-ORKStepNavigationRule
[ORKStepNavigationRule] Improve documentation
2016-01-26 11:27:30 -08:00
Yuan Zhu 292727ad91 Merge pull request #611 from CareEvolution/remove-chart-no-data-label
ORKGraphChartView - Remove the "No Data" label when there is data
2016-01-26 10:46:57 -08:00
Scott Guelich 2f1e58e234 Revert ORKWaitStepView.h to Project visibility 2016-01-26 08:47:41 -08:00
Scott Guelich 86226e9ba8 Remove noDataLabel when no data
Fix simple logic error
2016-01-26 08:37:13 -08:00
Yuan Zhu d40e8193d5 Providing a scale factor property in ORKPieChartView.
One reasoning this might be needed is incase the labels in the pie chart don't fit.
2016-01-22 13:39:59 -08:00
Yuan Zhu 525f2c6efb Merge branch 'master' of https://github.com/ResearchKit/ResearchKit 2016-01-22 13:20:39 -08:00
Ricardo Sánchez-Sáez ad52da287c [ORKStepNavigationRule] Improve documentation
- Improve whitespace
- Specify that passing 'ORKNullStepIdentifier' (instead of 'nil') ends the task for direct and predicate step navigation rules.
2016-01-16 21:46:18 +00:00
Ricardo Sánchez-Sáez 8d0fd95ad0 [ORKTestTests] Fix failing tests (mainly due ORKReviewStep) 2016-01-16 21:36:55 +00:00
Ricardo Sánchez-Sáez 46c78c08a4 [Workspace] Remove duplicated ResearchKit subproject references from ORKSample and ORKTest
They're not needed since ResearchKit is already in the Workspace.
2016-01-16 21:35:53 +00:00
Yuan Zhu 54927408bf Merge pull request #601 from rsanchezsaez/rsanchezsaez-ORKSample
[ORKSample] Allow onboarding to proceed on the Simulator despite HealthKit not being present
2016-01-14 16:27:36 -08:00
Yuan Zhu f325310d77 Merge pull request #451 from rsanchezsaez/rsanchezsaez-documentationformatting
README.md formatting
2016-01-14 16:11:13 -08:00
Yuan Zhu dd4e4fdbce Merge pull request #596 from shazino/timed-walk-optional-form
Add includeAssistiveDeviceForm parameter to timed walk task
2016-01-14 16:00:33 -08:00
Yuan Zhu 063cde7656 Merge pull request #602 from rsanchezsaez/rsanchezsaez-ORKGraphChartView
[Charts] Fix crash when displaying graph chart with no data source
2016-01-14 15:53:48 -08:00
Ricardo Sánchez-Sáez fb1ef39165 [Charts] Add reloadData methods
The developer can call this method if the data provided by the dataSource changes.
2016-01-14 22:26:59 +00:00
Ricardo Sánchez-Sáez c570771b4d [ORKGraphChartView] Avoid crash when displaying a graph with no dataSource set 2016-01-14 21:55:50 +00:00
Ricardo Sánchez-Sáez 00ff2f3402 [ORKSample] Allow onboarding to proceed on the Simulator despite the lack of HealthKit 2016-01-14 21:15:59 +00:00
Ricardo Sánchez-Sáez 407de8ed11 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-HomogeneousORKTextFieldView 2016-01-14 20:59:10 +00:00
Ricardo Sánchez-Sáez 6474ebfff7 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-documentationformatting
# Conflicts:
#	ResearchKit/ActiveTasks/ORKTowerOfHanoiStep.h
#	ResearchKit/Common/ORKAnswerFormat_Private.h
2016-01-14 20:57:48 +00:00
Yuan Zhu 340ba7210d Merge branch 'master' of gitlab.sd.apple.com:y_zhu/GitHub-ResearchKit-Fork into convergence_regex_api_change 2016-01-14 10:29:03 -08:00
Yuan Zhu 8c86b8d80d Merge pull request #463 from oliverschaefer/master
Review Step: API Design v1.2
2016-01-13 17:14:58 -08:00
Oliver Schäfer 21c89256fa Merge remote-tracking branch 'apple/master' 2016-01-12 17:19:49 +01:00
Pascal Pfiffner 62ae57bb11 Merge branch 'master' into feature/passcode-override 2016-01-12 14:20:38 +01:00
Yuan Zhu fbc4191081 Merge pull request #599 from ResearchKit/stable
Merge `Stable` into `Master`
2016-01-11 15:50:58 -08:00
Yuan Zhu 674e06cebc Merge pull request #597 from evliu/master
Samples - ORKCatalog/Charts/ChartListViewController - set prop on dis…
2016-01-08 13:17:32 -08:00
Everest Liu ade7f99010 Samples - ORKCatalog/Charts/ChartListViewController - set prop on discreteGraphChartView instead of lineGraphChartView 2016-01-07 13:29:27 -08:00
vtourraine 94fbd3a6d1 Add includeAssistiveDeviceForm parameter to timed walk task
Make timed walk assistive device form items non-optional
2016-01-06 16:47:31 +01:00
Oliver Schäfer f24a74006a PR updates 2016-01-06 13:27:38 +01:00
Oliver Schäfer 040b9d2220 Merge remote-tracking branch 'apple/master' 2016-01-06 13:18:34 +01:00
Oliver Schäfer 2e1749a14d alert controller bugfixes 2016-01-06 13:09:30 +01:00
Yuan Zhu 204d5dbf40 Merge pull request #595 from rsanchezsaez/rsanchezsaez-ORKOrderedTask
[ORKOrderedTask] Validate step identifier uniqueness on init
2016-01-05 16:17:59 -08:00
Yuan Zhu 908b9cb713 Merge pull request #593 from rsanchezsaez/rsanchezsaez-ORKGraphChartView
[ORKGraphChartView] Fix wrong selector check on accessibility
2016-01-05 16:14:23 -08:00
Yuan Zhu ff2c5ad055 Merge pull request #592 from rsanchezsaez/rsanchezsaez-ORKChoiceAnswerFormatHelper
[ORKChoiceAnswerFormatHelper] Relax class checking so choice answer formats can be subclassed
2016-01-05 15:47:05 -08:00
Oliver Schäfer 66fa232ca7 PR updates 2016-01-05 17:09:44 +01:00
Pascal Pfiffner 75ad7512b8 Merge branch 'master' of github.com:ResearchKit/ResearchKit 2016-01-05 10:46:51 +01:00
Ricardo Sánchez-Sáez 8b521477dd [docs] Fix some headerdoc warnings 2016-01-05 03:05:42 +00:00
Ricardo Sánchez-Sáez d60c81b004 [docs] Remove extraneous line from the Programming Guide 2016-01-05 02:52:22 +00:00
Ricardo Sánchez-Sáez a44f2db8fd [ORKOrderedTask] Validate step identifier uniqueness on init 2016-01-05 02:32:56 +00:00
Ricardo Sánchez-Sáez 58d377d9ab [ORKGraphChartView] Fix wrong selector check on accessibility 2016-01-05 02:24:52 +00:00
Ricardo Sánchez-Sáez e56bf7d217 [ORKChoiceAnswerFormatHelper] Relax class checking so choice answer formats can be subclassed 2016-01-05 01:49:17 +00:00
Ricardo Sánchez-Sáez 28ff1415dd Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-documentationformatting
# Conflicts:
#	README.md
2016-01-05 00:19:28 +00:00
Ricardo Sánchez-Sáez 8cbe836bb2 ORKTextFieldView: proper fix for animation glitch
The text frame sometimes animated from left to right (e.g., in ORKTest's MiniForm, tap 4th text field, type any number and tap any other text field).
Also remove needless period on latest placeholder text.
2016-01-05 00:14:49 +00:00
Ricardo Sánchez-Sáez 2289abf03a ORKFormItemTextFieldBasedCell: Allow temporarily leaving the text field empty without triggering answer validity checking
This fixes a regression. It restores the behavior in which you are allowed to edit a different text field in a form if you leave the current text field blank. E.g., on ORKTest's 'Mini Form', tapping on the first cell text field and then tapping on second cell text field without having written anything should not trigger the alert.
2016-01-04 23:09:35 +00:00
Ricardo Sánchez-Sáez 44ee48fa54 ORKTextField: Hide placeholder when editing a field which has a suffix 2016-01-04 23:00:18 +00:00
Ricardo Sánchez-Sáez b704be75b5 ORKAnswerTextView: fix comment typo 2016-01-04 22:30:54 +00:00
Ricardo Sánchez-Sáez 4048e34530 ORKAnswerTextFieldView: fix whitespace 2016-01-04 22:30:13 +00:00
Ricardo Sánchez-Sáez b34fb01350 ORKAnswerTextView: use the same placeholder approach as in ORKTextFieldView
This creates a non-interactive 'UITextView' for displaying the placeholder at the exact same position as the 'ORKAnswerTextView' text.

It improves encapsulation, the 'ORKAnswerTextView' class handles the placeholder internally.

Also: some minor naming convention improvenets in 'ORKTextFieldView'.
2016-01-04 22:30:09 +00:00
Ricardo Sánchez-Sáez 1b266c3652 ORKTextFieldView: conform to naming and whitespacing conventions 2016-01-04 22:23:58 +00:00
Ricardo Sánchez-Sáez 8ab052577d ORKTextFieldView: fix active unit color being off when there's no placeholder 2016-01-04 21:58:51 +00:00
Ricardo Sánchez-Sáez 1e34cf6d35 ORKTextFieldView: fix unit frame animation glitch
To reproduce, tap on an empty field with unit label and no placeholder (first form item of first step in ORKTest's Miniform).
2016-01-04 21:58:35 +00:00
Ricardo Sánchez-Sáez d39a72e535 ORKTextField: reduce left paddingGuess 2016-01-04 21:58:13 +00:00
Ricardo Sánchez-Sáez 135e2209c8 ORKTextFieldView: whitespace 2016-01-04 21:58:07 +00:00
Ricardo Sánchez-Sáez b865da3a75 ORKTextFieldView: make placeholder behave like 'UITextFieldView' placeholder
# Conflicts:
#	ResearchKit/Common/ORKTextFieldView.m
2016-01-04 21:57:53 +00:00
Ricardo SaÃÅnchez-SaÃÅez 40111a1431 ORKTextFieldView: remove '_unitWithPlaceholder' ivar which was producing extra unneeded padding between the placeholder and the unit 2016-01-04 21:55:34 +00:00
Ricardo Sánchez-Sáez cc45d92266 [ORKSample] Add app icon 2016-01-04 20:00:33 +00:00
Oliver Schäfer 1619428bb0 Accessibility updates 2015-12-29 22:07:22 +01:00
Oliver Schäfer 3ae773049a PR updates 2015-12-29 12:20:54 +01:00
Oliver Schäfer 76eb4f97d9 Merge remote-tracking branch 'apple/master' 2015-12-28 17:45:52 +01:00
Pascal Pfiffner 12326634db Spaces instead of tabs 2015-12-23 17:30:06 +01:00
Pascal Pfiffner 36b90b813c Merge branch 'master' of https://github.com/ResearchKit/ResearchKit into feature/passcode-override 2015-12-23 17:28:41 +01:00
Yuan Zhu 22b769b786 Merge pull request #588 from YuanZhu-apple/convergence_merge_master
Merge convergence code into master
2015-12-22 14:21:49 -08:00
Yuan Zhu 0afc2027d7 Merge branch 'master' of https://github.com/ResearchKit/ResearchKit into convergence
Conflicts:
	samples/ORKCatalog/ORKCatalog/Results/ResultTableViewProviders.swift
2015-12-22 14:09:54 -08:00
Pascal Pfiffner a78878c712 Allow to enforce a certain passcode
Comes in handy when moving to ResearchKit's passcode entry from a custom implementation or AppCore.
2015-12-18 11:21:04 +01:00
Pascal Pfiffner f6fd29087b Use instancetype instead of id 2015-12-18 10:48:32 +01:00
Pascal Pfiffner 4517cd445e Merge branch 'master' of github.com:ResearchKit/ResearchKit 2015-12-18 09:38:50 +01:00
Andrew Hill d151e11004 Merge branch 'ResearchKit/master' 2015-12-17 23:23:09 +00:00
Yuan Zhu ec9b1c9108 Change regex api to accept NSRegularExpression. 2015-12-16 15:56:28 -08:00
Yuan Zhu d7bf7a6ec3 Merge pull request #581 from Sage-Bionetworks/master-sage
Added method to create a copy of a step with a new identifier
2015-12-16 10:03:20 -08:00
Shannon Young 4342caae71 Updated in response to code review. 2015-12-15 18:10:26 -08:00
Shannon Young f7d7355c49 Added method to create a copy of a step with a new identifier 2015-12-15 14:48:38 -08:00
Oliver Schäfer 610ce5aefd Merge remote-tracking branch 'apple/master' 2015-12-08 22:01:56 +01:00
Oliver Schäfer bd52a14196 Minor PR updates 2015-12-08 22:01:44 +01:00
Pascal Pfiffner 423a89c879 Merge branch 'master' of github.com:ResearchKit/ResearchKit 2015-12-07 16:51:07 -05:00
Oliver Schäfer e444086399 PR updates 2015-12-06 13:13:33 +01:00
Oliver Schäfer 0ed1df3945 PR changes 2015-12-04 13:36:38 +01:00
Oliver Schäfer d71ab9538c PR updates 2015-12-03 22:08:37 +01:00
Oliver Schäfer 7caaf525e3 PR updates 2015-12-03 13:05:22 +01:00
Yuan Zhu c3102d6183 Merge branch 'convergence' 2015-12-01 15:31:04 -08:00
Oliver Schäfer 73495244be PR change 2015-11-30 21:31:52 +01:00
Yuan Zhu 85dd559217 Merge pull request #575 from UberJason/master
Fixed build error in ResultTableViewProviders.swift caused by an outdated property.
2015-11-30 10:44:03 -08:00
Jason Ji 81c8c10ebc Fixed build error in ResultTableViewProviders.swift caused by an outdated property. 2015-11-24 20:12:48 -05:00
Yuan Zhu 63a7e30049 Merge pull request #573 from tomihisaw/master
Allow ORKLoginStepViewController to be subclassed by making the class…
2015-11-23 14:23:47 -08:00
Tom Welsh 8fa839a66b Allow ORKLoginStepViewController to be subclassed by making the class symbol visible 2015-11-23 14:02:47 -05:00
Oliver Schäfer f8a77a1b1e Read only message 2015-11-19 20:24:11 +01:00
Oliver Schäfer ddc0016bd1 Disable skip button 2015-11-19 20:00:57 +01:00
Oliver Schäfer 8b81a8c5f1 Merge remote-tracking branch 'apple/master' 2015-11-18 22:55:22 +01:00
Oliver Schäfer ff673f0ad4 Fixed header comment typos 2015-11-18 22:50:03 +01:00
Oliver Schäfer 116a8e08ad Changed animation direction 2015-11-18 22:40:24 +01:00
Yuan Zhu 09e717c69f Merge pull request #564 from md0u80c9/CorrectDestionation
CorrectDestionation
2015-11-18 10:34:49 -08:00
Oliver Schäfer 9b1bdd390c PR changes, added documentation 2015-11-18 15:28:23 +01:00
Oliver Schäfer b113ef0ee3 PR updates 2015-11-17 21:52:23 +01:00
Andrew Hill 8e49cbc733 Correct Destionation
Changed all instances of Destionation to Destination
2015-11-17 13:47:25 +00:00
Andrew Hill 37cfadf81a Merge branch 'ResearchKit/master' 2015-11-16 22:29:18 +00:00
Oliver Schäfer fb778eefcf Bug fix 2015-11-13 09:41:25 +01:00
Oliver Schäfer f384f9137d Bug fixes 2015-11-12 22:24:12 +01:00
Oliver Schäfer 2f19a3e089 PR updates, bug fix 2015-11-12 21:44:04 +01:00
Oliver Schäfer b112945365 PR update 2015-11-11 21:13:38 +01:00
Oliver Schäfer 58c12a025b Changed review step ui for better navigation 2015-11-11 18:56:31 +01:00
Oliver Schäfer 2aa09084c8 PR updates 2015-11-06 22:16:43 +01:00
Oliver Schäfer 4d16e39f73 Merge remote-tracking branch 'apple/master' 2015-11-06 21:21:13 +01:00
Oliver Schäfer 59d2ed7a39 PR updates 2015-11-04 21:54:53 +01:00
Oliver Schäfer e5a4d01039 Merge remote-tracking branch 'apple/master' 2015-11-04 05:45:38 +01:00
Oliver Schäfer e7aac14571 PR update to fix ORKTextScaleAnswerFormat crash and re-connect embedded and standalone review step in ORKTest 2015-11-04 05:41:11 +01:00
Oliver Schäfer 746b0866b0 PR changes related to displaying results 2015-11-03 22:23:27 +01:00
Andrew Hill 11a29435cd Merge branch 'ResearchKit/master' 2015-11-01 09:01:21 +00:00
Oliver Sch√§fer 00886afe69 Displaying results for ORKLocationAnswerFormat 2015-10-26 17:53:24 +01:00
Oliver Schäfer fdd608fee4 Merge remote-tracking branch 'apple/master' 2015-10-26 17:30:54 +01:00
Andrew Hill b630dff27e Merge branch 'ResearchKit/master' 2015-10-25 20:28:57 +00:00
Oliver Sch√§fer c41fac8023 Displaying results 2015-10-25 18:27:34 +01:00
Andrew Hill 2819b7714d Merge branch 'ResearchKit/master' 2015-10-22 07:55:27 +01:00
Oliver Schäfer 81ec1f0056 Merge remote-tracking branch 'apple/master' 2015-10-22 00:10:02 +02:00
Oliver Sch√§fer 36f710739d PR updates 2015-10-22 00:05:11 +02:00
Oliver Sch√§fer 04f5a9e9f6 PR changes 2015-10-21 20:14:18 +02:00
Andrew Hill aa2e83e2b5 Merge branch 'ResearchKit/master' 2015-10-20 19:09:40 +01:00
Andrew Hill 79deaaa4b2 Merge branch 'ResearchKit/master' 2015-10-19 19:11:34 +01:00
Oliver Sch√§fer a581d58243 Bug fixes 2015-10-17 16:44:59 +02:00
Oliver Sch√§fer 718a4d3ed7 PR changes 2015-10-17 12:49:24 +02:00
Oliver Sch√§fer 9241848bc3 PR changes 2015-10-17 11:09:35 +02:00
Oliver Sch√§fer 913be47d6d Fixed corruption of project.pbxproj 2015-10-17 11:00:46 +02:00
Oliver Sch√§fer 88a94e106b PR Changes 2015-10-17 10:47:17 +02:00
Oliver Schäfer 2469bfe5a3 Merge remote-tracking branch 'apple/master' 2015-10-17 10:45:19 +02:00
Oliver Sch√§fer 6ec5df751d PR changes 2015-10-17 10:40:14 +02:00
Oliver Sch√§fer 7ef55e55e7 Bug fux 2015-10-16 21:51:00 +02:00
Oliver Sch√§fer 41d6a415ad Bug fixes 2015-10-12 11:59:10 +02:00
Oliver Sch√§fer a3b2d68b7a State restoration bugfix #2 2015-10-11 12:43:52 +02:00
Oliver Sch√§fer 87560025c8 State restoration bugfix 2015-10-11 12:34:08 +02:00
Oliver Sch√§fer dc3c6e011c PR changes 2015-10-08 20:47:55 +02:00
Oliver Schäfer 0180500607 Merge remote-tracking branch 'apple/master' 2015-10-03 12:02:33 +02:00
Oliver Sch√§fer 42e6c97ee2 API changes 2015-10-03 12:02:18 +02:00
Oliver Sch√§fer ce6c79a60f Minor changes 2015-10-01 23:01:54 +02:00
Oliver Sch√§fer 86bcdaa3ee Minor changes 2015-10-01 22:57:32 +02:00
Oliver Schäfer 6d2c1400b1 Merge remote-tracking branch 'apple/master' 2015-10-01 17:02:45 +02:00
Oliver Sch√§fer 8fa8dbae9e Changed progress label appearance when reviewing a step 2015-10-01 16:50:10 +02:00
Ricardo Sánchez-Sáez d26712e5a1 README.md: add 'Charts' section
Also add information about the chart examples in ORKCatalog.
2015-09-30 01:23:22 +01:00
Ricardo Sánchez-Sáez 0eba3970b5 README.md and Programming Guide: fix minor formatting issues 2015-09-30 01:20:42 +01:00
Ricardo Sánchez-Sáez 20e9cb24d4 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-documentationformatting
# Conflicts:
#	docs/Overview/GuideOverview-template.markdown
2015-09-29 22:37:51 +01:00
Oliver Sch√§fer 29f883b04b Refactored for ResearchKit 1.2 Compatibility 2015-09-20 09:12:01 +02:00
Pascal Pfiffner 870a9f6ac5 Merge branch 'master' of https://github.com/ResearchKit/ResearchKit 2015-09-17 13:10:03 +02:00
Ricardo Sánchez-Sáez 30a346e94d Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-documentationformatting 2015-09-17 01:45:30 +01:00
Ricardo Sánchez-Sáez 7361442a04 Programming Guide: add formatting for keywords and hard-wrap at line 100 2015-09-11 00:03:54 +01:00
Ricardo Sánchez-Sáez 398ae8029f README.md: add formatting to keywords such 'ResearchKit framework', 'iOS', 'Xcode', etc.
Also: hard-wrap documentation at line 100.
2015-09-10 23:58:38 +01:00
Pascal Pfiffner 1c0ac116d1 Backport slider fixes for Xcode 6 2015-08-30 23:36:52 +01:00
Allen Tu 1ecf1d7027 Merge remote-tracking branch 'ResearchKit/master' 2015-07-08 13:20:44 -07:00
954 changed files with 43445 additions and 7179 deletions
+75 -67
View File
@@ -1,8 +1,8 @@
ResearchKit Framework
===========
The ResearchKit™ framework is an open source software framework that makes it easy to
create apps for medical research or for other research projects.
The *ResearchKit™ framework* is an open source software framework that makes it easy to create apps
for medical research or for other research projects.
* [Getting Started](#gettingstarted)
* Documentation:
@@ -16,36 +16,48 @@ create apps for medical research or for other research projects.
Getting More Information
========================
* Join the [ResearchKit Forum](https://forums.developer.apple.com/community/researchkit) for discussing uses of the ResearchKit framework and related projects.
* Join the [*ResearchKit* Forum](https://forums.developer.apple.com/community/researchkit) for discussing uses of the *ResearchKit framework and* related projects.
Use Cases
===========
A task in the ResearchKit framework contains a set of steps to present to a
user. Everything, whether its a survey, the consent process, or active tasks,
is represented as a task that can be presented with a task view controller.
A task in the *ResearchKit framework* contains a set of steps to present to a user. Everything,
whether its a *survey*, the *consent process*, or *active tasks*, is represented as a task that can
be presented with a task view controller.
Surveys
-------
The ResearchKit framework provides a pre-built user interface for surveys, which can be
presented modally on an iPhone, iPod Touch, or iPad. See *[Creating Surveys](http://researchkit.org/docs/docs/Survey/CreatingSurveys.html)* for more information.
The *ResearchKit framework* provides a pre-built user interface for surveys, which can be presented
modally on an *iPhone*, *iPod Touch*, or *iPad*. See
*[Creating Surveys](http://researchkit.org/docs/docs/Survey/CreatingSurveys.html)* for more
information.
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. See *[Obtaining Consent](http://researchkit.org/docs/docs/InformedConsent/InformedConsent.html)* for more information.
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.
See *[Obtaining Consent](http://researchkit.org/docs/docs/InformedConsent/InformedConsent.html)* for
more information.
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. See *[Active Tasks](http://researchkit.org/docs/docs/ActiveTasks/ActiveTasks.html)* for more information.
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. See
*[Active Tasks](http://researchkit.org/docs/docs/ActiveTasks/ActiveTasks.html)* for more
information.
Charts
------------
*ResearchKit* includes a *Charts module*. It features three chart types: a *pie chart* (`ORKPieChartView`), a *line graph chart* (`ORKLineGraphChartView`), and a *discrete graph chart* (`ORKDiscreteGraphChartView`).
The views in the *Charts module* can be used independently of the rest of *ResearchKit*. They don't automatically connect with any other part of *ResearchKit*: the developer has to supply the data to be displayed through the views' `dataSources`, which allows for maximum flexibility.
Getting Started<a name="gettingstarted"></a>
@@ -55,16 +67,15 @@ Getting Started<a name="gettingstarted"></a>
Requirements
------------
The primary ResearchKit framework codebase supports iOS and requires Xcode 7.0
or newer.
The ResearchKit framework has a Base SDK version of 8.0, meaning that apps
using the ResearchKit framework can run on devices with iOS 8.0 or newer.
The primary *ResearchKit framework* codebase supports *iOS* and requires *Xcode 8.0* or newer. The
*ResearchKit framework* has a *Base SDK* version of *8.0*, meaning that apps using the *ResearchKit
framework* can run on devices with *iOS 8.0* or newer.
Installation
------------
The latest 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
@@ -79,48 +90,49 @@ git clone https://github.com/ResearchKit/ResearchKit.git
Building
--------
Build the ResearchKit framework by opening `ResearchKit.xcodeproj` and running the
`ResearchKit` framework target. Optionally, run the unit tests too.
Build the *ResearchKit framework* by opening `ResearchKit.xcodeproj` and running the `ResearchKit`
framework target. Optionally, run the unit tests too.
Adding the ResearchKit framework to your App
------------------------------
This walk-through shows how to embed the ResearchKit framework in your app as a
dynamic framework, and present a simple task view controller.
This walk-through shows how to embed the *ResearchKit framework* in your app as a dynamic framework,
and present a simple task view controller.
###1. Add the ResearchKit framework to Your Project
### 1. Add the ResearchKit framework to Your Project
To get started, drag `ResearchKit.xcodeproj` from your checkout into
your iOS app project in Xcode:
To get started, drag `ResearchKit.xcodeproj` from your checkout into your *iOS* app project
in *Xcode*:
<center>
<figure>
<img src="../../wiki/AddingResearchKitXcode.png" alt="Adding the ResearchKit framework to your project" align="middle"/>
<img src="../../wiki/AddingResearchKitXcode.png" alt="Adding the ResearchKit framework to your
project" align="middle"/>
</figure>
</center>
Then, embed the ResearchKit framework as a dynamic framework in your app, by adding
it to the Embedded Binaries section of the General pane for your
target as shown in the figure below.
Then, embed the *ResearchKit framework* as a dynamic framework in your app, by adding it to the
*Embedded Binaries* section of the *General* pane for your target as shown in the figure below.
<center>
<figure>
<img src="../../wiki/AddedBinaries.png" width="100%" alt="Adding the ResearchKit framework to Embedded Binaries" align="middle"/>
<img src="../../wiki/AddedBinaries.png" width="100%" alt="Adding the ResearchKit framework to
Embedded Binaries" align="middle"/>
<figcaption><center>Adding the ResearchKit framework to Embedded Binaries</center></figcaption>
</figure>
</center>
Note: You can also import ResearchKit into your project using a [dependency manager](./docs-standalone/dependency-management.md) such as CocoaPods or Carthage.
Note: You can also import *ResearchKit* into your project using a
[dependency manager](./docs-standalone/dependency-management.md) such as *CocoaPods* or *Carthage*.
###2. Create a Step
### 2. Create a Step
In this walk-through, we will use the ResearchKit framework to modally present a
simple single-step task showing a single instruction.
In this walk-through, we will use the *ResearchKit framework* to modally present a simple
single-step task showing a single instruction.
Create a step for your task by adding some code, perhaps in
`viewDidAppear:` of an existing view controller. To keep things
simple, we'll use an instruction step (`ORKInstructionStep`) and name
Create a step for your task by adding some code, perhaps in `viewDidAppear:` of an existing view
controller. To keep things simple, we'll use an instruction step (`ORKInstructionStep`) and name
the step `myStep`.
*Objective-C*
@@ -138,12 +150,11 @@ let myStep = ORKInstructionStep(identifier: "intro")
myStep.title = "Welcome to ResearchKit"
```
###3. Create a Task
### 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
selection of later steps does not depend on the results of earlier
ones. Name your task `task` and initialize it with `myStep`.
Use the ordered task class (`ORKOrderedTask`) to create a task that 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*
@@ -158,11 +169,10 @@ ORKOrderedTask *task =
let task = ORKOrderedTask(identifier: "task", steps: [myStep])
```
###4. Present the Task
### 4. Present the Task
Create a task view controller (`ORKTaskViewController`) and initialize
it with your `task`. A task view controller manages a task and collects the
results of each step. In this case, your task view
Create a task view controller (`ORKTaskViewController`) and initialize 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*
@@ -182,9 +192,9 @@ 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:
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*
@@ -204,20 +214,19 @@ 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.
func taskViewController(_ taskViewController: ORKTaskViewController,
didFinishWith reason: ORKTaskViewControllerFinishReason,
error: Error?) {
let taskResult = taskViewController.result
// You could do something with the result here.
// Then, dismiss the task view controller.
dismissViewControllerAnimated(true, completion: nil)
// Then, dismiss the task view controller.
dismiss(true, completion: nil)
}
```
If you now run your app, you should see your first ResearchKit framework
instruction step:
If you now run your app, you should see your first *ResearchKit framework* instruction step:
<center>
<figure>
@@ -230,22 +239,21 @@ instruction step:
What else can the ResearchKit framework do?
-----------------------------
The ResearchKit [`ORKCatalog`](samples/ORKCatalog) sample app is a
good place to start. Find the project in ResearchKit's
[`samples`](samples) directory. This project includes a list of all
the types of steps supported by the ResearchKit framework in one tab, and displays a
browser for the results of the last completed task in the other tab.
The *ResearchKit* [`ORKCatalog`](samples/ORKCatalog) sample app is a good place to start. Find the
project in ResearchKit's [`samples`](samples) directory. This project includes a list of all the
types of steps supported by the *ResearchKit framework* in the first tab, and displays a browser for the
results of the last completed task in the second tab. The third tab shows some examples from the *Charts module*.
License<a name="license"></a>
=======
The source in the ResearchKit repository is made available under the
following license unless another license is explicitly identified:
The source in the *ResearchKit* repository is made available under the following license unless
another license is explicitly identified:
```
Copyright (c) 2015, Apple Inc. All rights reserved.
Copyright (c) 2015 - 2017, Apple Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
+174 -47
View File
@@ -1,5 +1,132 @@
# ResearchKit Release Notes
## ResearchKit 1.5 Release Notes
*ResearchKit 1.5* supports *iOS* and requires *Xcode 8.0* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stabiltiy and performance improvements, *ResearchKit 1.5* includes the following new features and enhancements.
- **New Active Tasks**
- **Stroop Test**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *Stroop Test* shows the participant different combinations of text and tint colors on the screen.
Users must ignore the text and instead select the button that reflects the first letter of the tint color.
- **Trail Making Test**
*Contributed by Faraz Hussain.*
The *Trail Making Test* instructs participants to connect a series of labelled circles and the time to complete the test is recorded.
- **Range of Motion Test**
*Contributed by Daren Levy, Dr. Raj Karia, John Guydo.*
Participants are instructed to follow a series of steps while accelerometer and gyroscope data is captured to measure flexed and extended positions for both the shoulder and knee.
- **Touch Anywhere Active Task**
*Contributed by Daren Levy, Dr. Raj Karia, John Guydo*
Allows the user to get their device in the proper position and then tap the screen to indicate they are ready to begin the next step.
- **New Steps**
- **Video Instruction Step**
*Contributed by [Oliver Schäfer](https://github.com/oliverschaefer).*
The *Video Instruction Step* provides a step to be used to display a video.
This step can be used to display videos to users from either a local or remote source.
- **Other Improvements**
- **Tone Audiometry Test**
*Contributed by [Apple Inc](https://github.com/researchkit).*
Updated to include both a left and right button.
- **Digital Object Identifier**
*Contributed by [Apple Inc](https://github.com/researchkit).*
Assigns a Digital Object Identifier to the ResearchKit repository on GitHub to use when referencing the framework.
## ResearchKit 1.4 Release Notes
*ResearchKit 1.4* supports *iOS* and requires *Xcode 8.0* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stabiltiy and performance improvements, *ResearchKit 1.4* includes the following new features and enhancements.
- **New Active Task**
- **Hand Tremor Task**
*Contributed by [Shannon Young](https://github.com/syoung-smallwisdom).*
The *Hand Tremor Task* asks the participant to hold the device with their most affected hand in various positions while accelerometer and motion data is captured.
- **Walk Back and Forth Task**
*Contributed by [Shannon Young](https://github.com/syoung-smallwisdom).*
The *Walk Back and Forth Task* addresses the concern of researchers/participants who have difficulty locating an unobstructed path for 20 steps.
Instructs users to walk and turn in a full circle, allowing the tests to be conducted in a smaller space.
- **New Steps**
- **Video Capture Step**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *Video Capture Step* provides a step to be used to record video.
The step can be used as part of a survey to capture video respones as well.
- **Review Step**
*Contributed by [Oliver Schäfer](https://github.com/oliverschaefer).*
The *Review Step* allows a participant to review and modify their answers to a survey.
The step can be used in the middle of a survey, at the end of a survey, or a standalone module.
- **Signature Step**
*Contributed by [Oliver Schäfer](https://github.com/oliverschaefer).*
The *Signature Step* provides an interface for a participant to sign their name.
The step can be used for handwriting detection or simply to sign a document.
- **Table Step**
*Contributed by [Shannon Young](https://github.com/syoung-smallwisdom).*
The *Table Step* provides a way to neatly display data in a table.
- **Other Improvements**
- **Data Collection Module**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *Data Collection Module* makes it even easier to aggregate data from HealthKit and device sensors.
- **Tapping Test**
*Contributed by [Michał Zaborowski](https://github.com/m1entus).*
The *Tapping Test* is updated to include tap duration as part of the result.
## ResearchKit 1.3 Release Notes
@@ -7,88 +134,88 @@
In addition to general stability and performance improvements, *ResearchKit 1.3* includes the following new features and enhancements.
- **New Active Tasks**
- **New Active Task**
- **9-Hole Peg Test**
*Contributed by [Julien Therier](https://github.com/julientherier).*
The *[9-Hole Peg Test] task* is used to test upper extremity functionality.
The test involves putting a variable variable number of pegs in a hole, and then removing them.
The *9-Hole Peg Test task* is used to test upper extremity functionality.
The test involves putting a variable number of pegs in a hole and subsequently removing them.
The test is documented in the scientific literature to measure the *[MSFC score in Multiple Sclerosis](http://www.nationalmssociety.org/For-Professionals/Researchers/Resources-for-Researchers/Clinical-Study-Measures/9-Hole-Peg-Test-(9-HPT))* or *[Parkinson's Disease](http://www.ncbi.nlm.nih.gov/pubmed/22020457)*.
- **Sample App**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *[Sample App]* serves as a template application that combines different modules from the ResearchKit framework.
The *Sample App* (`ORKSample` project on *ResearchKit*'s workspace) serves as a template application that combines different modules from the *ResearchKit framework*.
- **Account Module**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *[Account Module]* provides steps to facilitate account creation and login.
The *Account Module* provides steps to facilitate account creation and login.
The module includes the following steps:
1. Registration to create a new account.
2. Verification to verify email.
3. Login to allow registered users to login.
1. *Registration*, used to allow the participant to create a new account.
2. *Verification*, used to confirm if the participant has verified the provided email address.
3. *Login*, used to allow registered users to login.
- **Passcode with Touch ID**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *[Passcode with Touch ID] module* provides the ability to secure any ResearchKit application with a pin entry.
This module includes a *Keychain Wrapper* that stores the passcode on the device, as well as the option to use Touch ID on compatible devices. The passcode module supports 4-pin and 6-pin entries.
The passcode module can be used in the following scenarios:
1. Passcode creation step which can be used as part of onboarding to create a passcode and store it in the keychain.
2. Passcode authentication view controller which can be presented modally when appropriate.
3. Passcode modification view controller which allows the participant to change their passcode.
The *Passcode with Touch ID module* provides the ability to secure any *ResearchKit* application with a numeric passcode.
This module includes a *Keychain Wrapper* that stores the passcode on the device, as well as the option to use *Touch ID* on compatible devices. The passcode module supports 4-digit and 6-digit numeric codes.
The passcode module provides the following components:
1. *Passcode creation step*, which can be used as part of onboarding to create a passcode and store it in the keychain.
2. *Passcode authentication view controller*, which can be modally presented when appropriate.
3. *Passcode modification view controller*, which allows the participant to change their passcode.
- **Other Improvements**
- **Optional Form Items**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
Implements the `ORKFormItem` `optional` property.
The *Continue/Done* button of form steps enables only if:
- At least one form item has an answer.
- All answered form items are valid.
- All the non-optional form items have answers.
Adds the `optional` property to `ORKFormItem`.
The *Continue/Done* button of form steps is enabled when all of the following conditions are met:
- At least one form item has an answer.
- All the non-optional form items have answers.
- All answered form items have valid answers.
- **Location Question**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
A *Location Question* can be used to request details about the participant's current location or a specific address.
The question uses *MapKit* to provides a visual representation for the specified address.
A *Location Question* can be used to request details about the participant's current location or about a specific address.
The question uses *MapKit* to provide a visual representation for the specified address.
- **Wait Step**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
The *Wait Step* provides a step to be used in-between steps when additional data processing is required.
The step supports both indeterminate and determinate progress views, as well as the ability to show text status updates.
- **Validated Text Answer Format**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
The *Validated Text Answer Format* enhances the existing *Text Answer Format* by providing input validation using a regular expression.
A valid *NSRegularExpression* object and an *error message* string are required to properly use this answer format.
## ResearchKit 1.2 Release Notes
@@ -170,7 +297,7 @@ In addition to general stability and performance improvements, *ResearchKit 1.1*
A new type of *conditional ordered task* (`ORKNavigableOrderedTask`) has been implemented.
The developer can use the `ORKStepNavigationRule` subclasses to dynamically navigate between the task steps:
- `ORKPredicateStepNavigationRule` allows to make conditional jumps by matching previous results (either those of the the ongoing task, or those of any previously stored task result tree). You typically use the class methods in the `ORKResultPredicate` class to match answers in the most commonly used result types.
- `ORKPredicateStepNavigationRule` allows to make conditional jumps by matching previous results (either those of the ongoing task, or those of any previously stored task result tree). You typically use the class methods in the `ORKResultPredicate` class to match answers in the most commonly used result types.
- `ORKDirectStepNavigationRule` provides support for unconditional jumps.
- **New Active Tasks**
@@ -216,4 +343,4 @@ In addition to general stability and performance improvements, *ResearchKit 1.1*
*Contributed by [Apple Inc.](https://github.com/researchkit) and [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
*iPhone landscape orientation support* has been implemented.
*iPhone landscape orientation support* has been implemented.
+3 -3
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'ResearchKit'
s.version = '1.3.0'
s.version = '1.5.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/'
@@ -8,8 +8,8 @@ Pod::Spec.new do |s|
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.source_files = 'ResearchKit/**/*.{h,m,swift}'
s.resources = 'ResearchKit/**/*.{fsh,vsh}', 'ResearchKit/Animations/**/*.m4v', 'ResearchKit/Artwork.xcassets', 'ResearchKit/Localized/*.lproj'
s.platform = :ios, '8.0'
s.platform = :ios, '8.2'
s.requires_arc = true
end
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0900"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0900"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
+1 -1
View File
@@ -30,6 +30,6 @@
// Shared header for accessibility functionality.
#import "UIView+ORKAccessibility.h"
#import "ORKAccessibilityFunctions.h"
#import "ORKLineGraphAccessibilityElement.h"
#import "UIView+ORKAccessibility.h"
@@ -30,9 +30,11 @@
#import "ORKDefines.h"
#import "ORKHelpers.h"
#import "ORKHelpers_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKScaleSlider;
// Used to properly format values from the ORKScaleSlider.
@@ -43,7 +45,7 @@ ORK_EXTERN NSString *ORKAccessibilityFormatContinuousScaleSliderValue(CGFloat va
ORK_EXTERN void ORKAccessibilityPerformBlockAfterDelay(NSTimeInterval delay, void(^block)(void));
// Convenience for posting an accessibility notification after a delay.
ORK_INLINE void ORKAccessibilityPostNotificationAfterDelay(UIAccessibilityNotifications notification, id argument, NSTimeInterval delay) {
ORK_INLINE void ORKAccessibilityPostNotificationAfterDelay(UIAccessibilityNotifications notification, _Nullable id argument, NSTimeInterval delay) {
ORKAccessibilityPerformBlockAfterDelay(delay, ^{
UIAccessibilityPostNotification(notification, argument);
});
@@ -52,3 +54,5 @@ ORK_INLINE void ORKAccessibilityPostNotificationAfterDelay(UIAccessibilityNotifi
// Creates a string suitable for Voice Over by joining the variables with ", " and avoiding nil and empty strings.
#define ORKAccessibilityStringForVariables(...) _ORKAccessibilityStringForVariables(ORK_NARG(__VA_ARGS__), ##__VA_ARGS__)
ORK_EXTERN NSString *_ORKAccessibilityStringForVariables(NSInteger numParameters, NSString *baseString, ...);
NS_ASSUME_NONNULL_END
@@ -29,11 +29,14 @@
*/
#import <UIKit/UIKit.h>
#import "ORKAccessibilityFunctions.h"
#import "ORKAnswerFormat_Internal.h"
@import UIKit;
#import "ORKScaleSlider.h"
#import "ORKScaleSliderView.h"
#import "ORKAnswerFormat_Internal.h"
#import "ORKAccessibilityFunctions.h"
#import "UIView+ORKAccessibility.h"
@@ -28,10 +28,16 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
@import UIKit;
NS_ASSUME_NONNULL_BEGIN
@interface ORKLineGraphAccessibilityElement : UIAccessibilityElement
- (nonnull instancetype)initWithAccessibilityContainer:(nonnull UIView *)container index:(NSInteger)index maxIndex:(NSInteger)maxIndex;
@end
NS_ASSUME_NONNULL_END
@@ -30,11 +30,15 @@
#import "ORKLineGraphAccessibilityElement.h"
@interface ORKLineGraphAccessibilityElement()
@property (assign, nonatomic) NSInteger index;
@property (assign, nonatomic) NSInteger maxIndex;
@end
@implementation ORKLineGraphAccessibilityElement
- (nonnull instancetype)initWithAccessibilityContainer:(nonnull UIView *)container index:(NSInteger)index maxIndex:(NSInteger)maxIndex {
@@ -29,8 +29,7 @@
*/
#import <UIKit/UIKit.h>
#import <ResearchKit/ResearchKit.h>
@import UIKit;
NS_ASSUME_NONNULL_BEGIN
@@ -29,8 +29,7 @@
*/
#import <CoreLocation/CoreLocation.h>
#import <ResearchKit/ResearchKit.h>
@import CoreLocation;
NS_ASSUME_NONNULL_BEGIN
@@ -30,7 +30,8 @@
#import "CLLocation+ORKJSONDictionary.h"
#import "ORKHelpers.h"
#import "ORKHelpers_Internal.h"
@implementation CLLocation (ORKJSONDictionary)
@@ -45,10 +46,11 @@
NSDate *timestamp = self.timestamp;
CLFloor *floor = self.floor;
NSMutableDictionary *dictionary = [@{@"timestamp" : ORKStringFromDateISO8601(timestamp)} mutableCopy];
NSMutableDictionary *dictionary = [@{ @"timestamp": ORKStringFromDateISO8601(timestamp) } mutableCopy];
if (horizAccuracy >= 0) {
dictionary[@"coordinate"] = @{ @"latitude" : [NSDecimalNumber numberWithDouble:coord.latitude], @"longitude" : [NSDecimalNumber numberWithDouble:coord.longitude]};
dictionary[@"coordinate"] = @{ @"latitude": [NSDecimalNumber numberWithDouble:coord.latitude],
@"longitude": [NSDecimalNumber numberWithDouble:coord.longitude]};
dictionary[@"horizontalAccuracy"] = [NSDecimalNumber numberWithDouble:horizAccuracy];
}
if (vertAccuracy >= 0) {
@@ -29,8 +29,7 @@
*/
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
@import CoreMotion;
NS_ASSUME_NONNULL_BEGIN
@@ -35,10 +35,10 @@
@implementation CMAccelerometerData (ORKJSONDictionary)
- (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]
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;
}
@@ -29,8 +29,7 @@
*/
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
@import CoreMotion;
NS_ASSUME_NONNULL_BEGIN
@@ -42,34 +42,34 @@
CMCalibratedMagneticField field = self.magneticField;
NSDictionary *dictionary = @{@"timestamp": [NSDecimalNumber numberWithDouble:self.timestamp],
@"attitude" : @{
@"x" : [NSDecimalNumber numberWithDouble:attitude.x],
@"y" : [NSDecimalNumber numberWithDouble:attitude.y],
@"z" : [NSDecimalNumber numberWithDouble:attitude.z],
@"w" : [NSDecimalNumber numberWithDouble:attitude.w]
},
@"rotationRate" : @{
@"x" : [NSDecimalNumber numberWithDouble:rotationRate.x],
@"y" : [NSDecimalNumber numberWithDouble:rotationRate.y],
@"z" : [NSDecimalNumber numberWithDouble:rotationRate.z]
},
@"gravity" : @{
@"x" : [NSDecimalNumber numberWithDouble:gravity.x],
@"y" : [NSDecimalNumber numberWithDouble:gravity.y],
@"z" : [NSDecimalNumber numberWithDouble:gravity.z]
},
@"userAcceleration" : @{
@"x" : [NSDecimalNumber numberWithDouble:userAccel.x],
@"y" : [NSDecimalNumber numberWithDouble:userAccel.y],
@"z" : [NSDecimalNumber numberWithDouble:userAccel.z]
},
@"magneticField" : @{
@"x" : [NSDecimalNumber numberWithDouble:field.field.x],
@"y" : [NSDecimalNumber numberWithDouble:field.field.y],
@"z" : [NSDecimalNumber numberWithDouble:field.field.z],
@"accuracy" : [NSDecimalNumber numberWithDouble:field.accuracy]
}
};
@"attitude": @{
@"x": [NSDecimalNumber numberWithDouble:attitude.x],
@"y": [NSDecimalNumber numberWithDouble:attitude.y],
@"z": [NSDecimalNumber numberWithDouble:attitude.z],
@"w": [NSDecimalNumber numberWithDouble:attitude.w]
},
@"rotationRate": @{
@"x": [NSDecimalNumber numberWithDouble:rotationRate.x],
@"y": [NSDecimalNumber numberWithDouble:rotationRate.y],
@"z": [NSDecimalNumber numberWithDouble:rotationRate.z]
},
@"gravity": @{
@"x": [NSDecimalNumber numberWithDouble:gravity.x],
@"y": [NSDecimalNumber numberWithDouble:gravity.y],
@"z": [NSDecimalNumber numberWithDouble:gravity.z]
},
@"userAcceleration": @{
@"x": [NSDecimalNumber numberWithDouble:userAccel.x],
@"y": [NSDecimalNumber numberWithDouble:userAccel.y],
@"z": [NSDecimalNumber numberWithDouble:userAccel.z]
},
@"magneticField": @{
@"x": [NSDecimalNumber numberWithDouble:field.field.x],
@"y": [NSDecimalNumber numberWithDouble:field.field.y],
@"z": [NSDecimalNumber numberWithDouble:field.field.z],
@"accuracy": [NSDecimalNumber numberWithDouble:field.accuracy]
}
};
return dictionary;
}
@@ -29,8 +29,7 @@
*/
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
@import CoreMotion;
NS_ASSUME_NONNULL_BEGIN
@@ -30,7 +30,8 @@
#import "CMMotionActivity+ORKJSONDictionary.h"
#import "ORKHelpers.h"
#import "ORKHelpers_Internal.h"
static NSString *const ActivityUnknown = @"unknown";
@@ -42,9 +43,9 @@ static NSString *const StartDateKey = @"startDate";
static NSString *const EndDateKey = @"endDate";
static NSString *stringFromActivityConfidence(CMMotionActivityConfidence confidence) {
NSDictionary *confidences = @{@(CMMotionActivityConfidenceHigh) : @"high",
@(CMMotionActivityConfidenceMedium) : @"medium",
@(CMMotionActivityConfidenceLow) : @"low"};
NSDictionary *confidences = @{@(CMMotionActivityConfidenceHigh): @"high",
@(CMMotionActivityConfidenceMedium): @"medium",
@(CMMotionActivityConfidenceLow): @"low"};
return confidences[@(confidence)];
}
@@ -71,12 +72,13 @@ static NSArray *activityArray(CMMotionActivity *activity) {
static NSString *const ActivityKey = @"activity";
static NSString *const ConfidenceKey = @"confidence";
@implementation CMMotionActivity (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary {
return @{ConfidenceKey : stringFromActivityConfidence(self.confidence),
ActivityKey : activityArray(self),
StartDateKey : ORKStringFromDateISO8601(self.startDate)};
return @{ConfidenceKey: stringFromActivityConfidence(self.confidence),
ActivityKey: activityArray(self),
StartDateKey: ORKStringFromDateISO8601(self.startDate)};
}
@end
@@ -29,8 +29,7 @@
*/
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
@import CoreMotion;
NS_ASSUME_NONNULL_BEGIN
@@ -30,17 +30,17 @@
#import "CMPedometerData+ORKJSONDictionary.h"
#import "ORKHelpers.h"
#import <CoreMotion/CoreMotion.h>
#import "ORKHelpers_Internal.h"
@import CoreMotion;
@implementation CMPedometerData (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary {
NSMutableDictionary *dictionary = [@{@"startDate": ORKStringFromDateISO8601(self.startDate),
@"endDate": ORKStringFromDateISO8601(self.endDate)
} mutableCopy];
for (NSString *key in @[@"numberOfSteps", @"distance", @"floorsAscended", @"floorsDescended"]) {
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 dictionary;
@@ -29,8 +29,7 @@
*/
#import <HealthKit/HealthKit.h>
#import <ResearchKit/ResearchKit.h>
@import HealthKit;
NS_ASSUME_NONNULL_BEGIN
@@ -30,7 +30,8 @@
#import "HKSample+ORKJSONDictionary.h"
#import "ORKHelpers.h"
#import "ORKHelpers_Internal.h"
static NSString *const HKSampleIdentifierKey = @"type"; // For compatibility with Health XML export
@@ -89,7 +90,7 @@ static NSString *const HKCorrelatedObjectsKey = @"objects";
}
if (options & ORKSampleIncludeSource) {
HKSource *source = [self source];
HKSource *source = [[self sourceRevision] source];
if (source.name) {
mutableDictionary[HKSourceKey] = source.name;
}
@@ -29,6 +29,7 @@
*/
@import UIKit;
#import <ResearchKit/ORKRecorder.h>
@@ -58,7 +59,7 @@ ORK_CLASS_AVAILABLE
@return An initialized accelerometer recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifer
- (instancetype)initWithIdentifier:(NSString *)identifier
frequency:(double)frequency
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory;
@@ -30,12 +30,15 @@
#import "ORKAccelerometerRecorder.h"
#import "ORKDataLogger.h"
#import "CMAccelerometerData+ORKJSONDictionary.h"
#import <CoreMotion/CoreMotion.h>
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
#import "ORKHelpers.h"
#import "ORKHelpers_Internal.h"
#import "CMAccelerometerData+ORKJSONDictionary.h"
@import CoreMotion;
@interface ORKAccelerometerRecorder () {
@@ -70,7 +73,7 @@
}
- (void)setFrequency:(double)frequency {
if (frequency <=0) {
if (frequency <= 0) {
_frequency = 1;
} else {
_frequency = frequency;
@@ -87,10 +90,10 @@
self.motionManager = [self createMotionManager];
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
if (!_logger) {
[self finishRecordingWithError:err];
[self finishRecordingWithError:error];
return;
}
}
@@ -98,7 +101,7 @@
if (!self.motionManager || !self.motionManager.accelerometerAvailable) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}];
userInfo:@{@"recorder": self}];
[self finishRecordingWithError:error];
return;
}
@@ -124,7 +127,7 @@
}
- (NSDictionary *)userInfo {
return @{ @"frequency" : @(self.frequency) };
return @{ @"frequency": @(self.frequency) };
}
- (void)stop {
+22 -15
View File
@@ -29,10 +29,10 @@
*/
#import <ResearchKit/ORKDefines.h>
@import UIKit;
@import HealthKit;
#import <ResearchKit/ORKStep.h>
#import <UIKit/UIKit.h>
#import <HealthKit/HealthKit.h>
@class ORKRecorderConfiguration;
@@ -103,6 +103,17 @@ automatically navigates forward when the timer expires.
*/
@property (nonatomic) BOOL shouldSpeakCountDown;
/**
A Boolean value indicating whether to speak the halfway point in the count down of the
duration of a timed step.
When the value of this property is `YES`, `AVSpeechSynthesizer` is used to synthesize the countdown. Note that this property is ignored if VoiceOver is enabled.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldSpeakRemainingTimeAtHalfway;
/**
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.
@@ -171,6 +182,14 @@ The default value of this property is `NO`.
*/
@property (nonatomic, copy, nullable) NSString *spokenInstruction;
/**
Localized text that represents an instructional voice prompt for when the step finishes.
Instructional speech begins when the step finishes. If VoiceOver is active,
the instruction is spoken by VoiceOver.
*/
@property (nonatomic, copy, nullable) NSString *finishedSpokenInstruction;
/**
An image to be displayed below the instructions for the step.
@@ -195,18 +214,6 @@ The default value of this property is `NO`.
*/
@property (nonatomic, copy, nullable) NSArray<ORKRecorderConfiguration *> *recorderConfigurations;
/**
The set of HealthKit types the step requests for reading. (read-only)
The task view controller uses this set of types when constructing a list of
all the HealthKit types required by all the steps in a task, so that it can
present the HealthKit access dialog just once during that task.
By default, the property scans the recorders and collates the HealthKit
types the recorders require. Subclasses may override this implementation.
*/
@property (nonatomic, readonly, nullable) NSSet<HKObjectType *> *requestedHealthKitTypesForReading;
@end
NS_ASSUME_NONNULL_END
+16 -3
View File
@@ -30,12 +30,15 @@
#import "ORKActiveStep.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
#import "ORKActiveStep_Internal.h"
#import "ORKActiveStepViewController.h"
#import "ORKRecorder_Private.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@implementation ORKActiveStep
@@ -62,7 +65,9 @@
}
- (BOOL)hasVoice {
return (_spokenInstruction != nil && _spokenInstruction.length > 0);
BOOL hasSpokenInstruction = (_spokenInstruction != nil && _spokenInstruction.length > 0);
BOOL hasFinishedSpokenInstruction = (_finishedSpokenInstruction != nil && _finishedSpokenInstruction.length > 0);
return (hasSpokenInstruction || hasFinishedSpokenInstruction);
}
- (BOOL)isRestorable {
@@ -86,6 +91,7 @@
step.stepDuration = self.stepDuration;
step.shouldStartTimerAutomatically = self.shouldStartTimerAutomatically;
step.shouldSpeakCountDown = self.shouldSpeakCountDown;
step.shouldSpeakRemainingTimeAtHalfway = self.shouldSpeakRemainingTimeAtHalfway;
step.shouldShowDefaultTimer = self.shouldShowDefaultTimer;
step.shouldPlaySoundOnStart = self.shouldPlaySoundOnStart;
step.shouldPlaySoundOnFinish = self.shouldPlaySoundOnFinish;
@@ -94,6 +100,7 @@
step.shouldUseNextAsSkipButton = self.shouldUseNextAsSkipButton;
step.shouldContinueOnFinish = self.shouldContinueOnFinish;
step.spokenInstruction = self.spokenInstruction;
step.finishedSpokenInstruction = self.finishedSpokenInstruction;
step.recorderConfigurations = [self.recorderConfigurations copy];
step.image = self.image;
return step;
@@ -105,6 +112,7 @@
ORK_DECODE_DOUBLE(aDecoder, stepDuration);
ORK_DECODE_BOOL(aDecoder, shouldStartTimerAutomatically);
ORK_DECODE_BOOL(aDecoder, shouldSpeakCountDown);
ORK_DECODE_BOOL(aDecoder, shouldSpeakRemainingTimeAtHalfway);
ORK_DECODE_BOOL(aDecoder, shouldShowDefaultTimer);
ORK_DECODE_BOOL(aDecoder, shouldPlaySoundOnStart);
ORK_DECODE_BOOL(aDecoder, shouldPlaySoundOnFinish);
@@ -113,6 +121,7 @@
ORK_DECODE_BOOL(aDecoder, shouldUseNextAsSkipButton);
ORK_DECODE_BOOL(aDecoder, shouldContinueOnFinish);
ORK_DECODE_OBJ_CLASS(aDecoder, spokenInstruction, NSString);
ORK_DECODE_OBJ_CLASS(aDecoder, finishedSpokenInstruction, NSString);
ORK_DECODE_IMAGE(aDecoder, image);
ORK_DECODE_OBJ_ARRAY(aDecoder, recorderConfigurations, ORKRecorderConfiguration);
}
@@ -124,6 +133,7 @@
ORK_ENCODE_DOUBLE(aCoder, stepDuration);
ORK_ENCODE_BOOL(aCoder, shouldStartTimerAutomatically);
ORK_ENCODE_BOOL(aCoder, shouldSpeakCountDown);
ORK_ENCODE_BOOL(aCoder, shouldSpeakRemainingTimeAtHalfway);
ORK_ENCODE_BOOL(aCoder, shouldShowDefaultTimer);
ORK_ENCODE_BOOL(aCoder, shouldPlaySoundOnStart);
ORK_ENCODE_BOOL(aCoder, shouldPlaySoundOnFinish);
@@ -133,6 +143,7 @@
ORK_ENCODE_BOOL(aCoder, shouldContinueOnFinish);
ORK_ENCODE_IMAGE(aCoder, image);
ORK_ENCODE_OBJ(aCoder, spokenInstruction);
ORK_ENCODE_OBJ(aCoder, finishedSpokenInstruction);
ORK_ENCODE_OBJ(aCoder, recorderConfigurations);
}
@@ -142,12 +153,14 @@
__typeof(self) castObject = object;
return (isParentSame &&
ORKEqualObjects(self.spokenInstruction, castObject.spokenInstruction) &&
ORKEqualObjects(self.finishedSpokenInstruction, castObject.finishedSpokenInstruction) &&
ORKEqualObjects(self.recorderConfigurations, castObject.recorderConfigurations) &&
ORKEqualObjects(self.image, castObject.image) &&
(self.stepDuration == castObject.stepDuration) &&
(self.shouldShowDefaultTimer == castObject.shouldShowDefaultTimer) &&
(self.shouldStartTimerAutomatically == castObject.shouldStartTimerAutomatically) &&
(self.shouldSpeakCountDown == castObject.shouldSpeakCountDown) &&
(self.shouldSpeakRemainingTimeAtHalfway == castObject.shouldSpeakRemainingTimeAtHalfway) &&
(self.shouldPlaySoundOnStart == castObject.shouldPlaySoundOnStart) &&
(self.shouldPlaySoundOnFinish == castObject.shouldPlaySoundOnFinish) &&
(self.shouldVibrateOnStart == castObject.shouldVibrateOnStart) &&
@@ -29,7 +29,7 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import "ORKLabel.h"
@@ -30,10 +30,12 @@
#import "ORKActiveStepQuantityView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
#import "ORKTintedImageView.h"
#import "ORKSubheadlineLabel.h"
#import "ORKTintedImageView.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@implementation ORKQuantityLabel
+1 -2
View File
@@ -29,8 +29,7 @@
*/
#import <Foundation/Foundation.h>
#import <ResearchKit/ResearchKit.h>
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
+7 -3
View File
@@ -30,9 +30,12 @@
#import "ORKActiveStepTimer.h"
#import "ORKHelpers_Internal.h"
@import UIKit;
#include <mach/mach.h>
#include <mach/mach_time.h>
#import <UIKit/UIKit.h>
static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
@@ -44,6 +47,7 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
return elapsedNano * 1.0 / NSEC_PER_SEC;
}
@implementation ORKActiveStepTimer {
uint64_t _startTime;
NSTimeInterval _preExistingRuntime;
@@ -197,9 +201,9 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
assert(0);
return;
}
__weak typeof(self) weakSelf = self;
ORKWeakTypeOf(self) weakSelf = self;
dispatch_source_set_event_handler(_timer, ^{
typeof(self) strongSelf = weakSelf;
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf hiqueue_event];
});
@@ -29,18 +29,20 @@
*/
#import <UIKit/UIKit.h>
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import "ORKCountdownLabel.h"
#import "ORKTextButton.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKActiveStep;
@class ORKCountdownLabel;
@class ORKTextButton;
@interface ORKActiveStepTimerView : ORKActiveStepCustomView
@property (nonatomic, strong, nullable) ORKCountdownLabel *countDownLabel;
@property (nonatomic, strong, nullable) ORKTextButton *startTimerButton;
@property (nonatomic, strong, nullable) ORKActiveStep *step;
@@ -30,17 +30,22 @@
#import "ORKActiveStepTimerView.h"
#import "ORKActiveStepTimer.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKVoiceEngine.h"
#import "ORKCountdownLabel.h"
#import "ORKSurveyAnswerCellForText.h"
#import "ORKSurveyAnswerCellForNumber.h"
#import "ORKActiveStep_Internal.h"
#import "ORKTextButton.h"
#import "ORKVoiceEngine.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStep_Internal.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@implementation ORKActiveStepTimerView {
BOOL _started;
@@ -29,6 +29,7 @@
*/
@import UIKit;
#import <ResearchKit/ORKStepViewController.h>
#import <ResearchKit/ORKRecorder.h>
@@ -30,23 +30,27 @@
#import "ORKActiveStepViewController.h"
#import "ORKVoiceEngine.h"
#import "ORKSkin.h"
#import "ORKHelpers.h"
#import "ORKActiveStep.h"
#import "ORKTask.h"
#import "ORKTaskViewController.h"
#import "ORKVerticalContainerView.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKActiveStep_Internal.h"
#import "ORKRecorder_Internal.h"
#import "ORKTaskViewController_Internal.h"
#import "ORKActiveStepTimerView.h"
#import "ORKActiveStepTimer.h"
#import "ORKAccessibility.h"
#import "ORKStepHeaderView_Internal.h"
#import "ORKActiveStepTimerView.h"
#import "ORKActiveStepView.h"
#import "ORKNavigationContainerView.h"
#import "ORKStepHeaderView_Internal.h"
#import "ORKVerticalContainerView.h"
#import "ORKVoiceEngine.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKTaskViewController_Internal.h"
#import "ORKRecorder_Internal.h"
#import "ORKActiveStep_Internal.h"
#import "ORKResult.h"
#import "ORKTask.h"
#import "ORKAccessibility.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@interface ORKActiveStepViewController () {
@@ -57,6 +61,7 @@
SystemSoundID _alertSound;
NSURL *_alertSoundURL;
BOOL _hasSpokenHalfwayCountdown;
}
@property (nonatomic, strong) NSArray *recorders;
@@ -92,6 +97,7 @@
}
- (ORKActiveStep *)activeStep {
NSAssert(self.step == nil || [self.step isKindOfClass:[ORKActiveStep class]], @"Step should be a subclass of an ORKActiveStep");
return (ORKActiveStep *)self.step;
}
@@ -205,7 +211,9 @@
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
sResult.results = _recorderResults;
if (_recorderResults) {
sResult.results = [sResult.results arrayByAddingObjectsFromArray:_recorderResults] ? : _recorderResults;
}
return sResult;
}
@@ -362,6 +370,9 @@
if (self.activeStep.shouldVibrateOnFinish) {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
}
if (self.activeStep.hasVoice && self.activeStep.finishedSpokenInstruction) {
[[ORKVoiceEngine sharedVoiceEngine] speakText:self.activeStep.finishedSpokenInstruction];
}
if (!self.activeStep.startsFinished) {
if (self.activeStep.shouldContinueOnFinish) {
[self goForward];
@@ -390,12 +401,12 @@
NSTimeInterval stepDuration = self.activeStep.stepDuration;
if (stepDuration > 0) {
__weak typeof(self) weakSelf = self;
ORKWeakTypeOf(self) weakSelf = self;
_activeStepTimer = [[ORKActiveStepTimer alloc] initWithDuration:stepDuration
interval:_timerUpdateInterval
runtime:0
handler:^(ORKActiveStepTimer *timer, BOOL finished) {
typeof(self) strongSelf = weakSelf;
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf countDownTimerFired:timer finished:finished];
}];
[_activeStepTimer resume];
@@ -410,6 +421,7 @@
ORKActiveStepCustomView *customView = _activeStepView.activeCustomView;
[customView updateDisplay:self];
ORKVoiceEngine *voice = [ORKVoiceEngine sharedVoiceEngine];
if (!finished && self.activeStep.shouldSpeakCountDown) {
@@ -423,6 +435,13 @@
[voice speakInt:countDownValue];
}
}
BOOL isHalfway = !_hasSpokenHalfwayCountdown && timer.runtime > timer.duration / 2.0;
if (!finished && self.activeStep.shouldSpeakRemainingTimeAtHalfway && !UIAccessibilityIsVoiceOverRunning() && isHalfway) {
_hasSpokenHalfwayCountdown = YES;
NSString *text = [NSString localizedStringWithFormat:ORKLocalizedString(@"COUNTDOWN_SPOKEN_REMAINING_%@", nil), @(countDownValue)];
[voice speakText:text];
}
}
- (BOOL)timerActive {
@@ -450,7 +469,7 @@
- (void)recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error {
if (error) {
STRONGTYPE(self.delegate) strongDelegate = self.delegate;
ORKStrongTypeOf(self.delegate) strongDelegate = self.delegate;
if ([strongDelegate respondsToSelector:@selector(stepViewController:recorder:didFailWithError:)]) {
[strongDelegate stepViewController:self recorder:recorder didFailWithError:error];
}
@@ -30,11 +30,11 @@
#import "ORKActiveStepViewController.h"
#import "ORKActiveStepTimer.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKActiveStepTimer;
@class ORKActiveStepView;
@interface ORKActiveStepViewController ()
@@ -29,14 +29,14 @@
*/
#import <ResearchKit/ORKActiveStep.h>
#import "ORKActiveStep.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKActiveStep ()
/**
Convenience methods.
*/
// Convenience methods.
- (BOOL)startsFinished;
- (BOOL)hasCountDown;
- (BOOL)hasTitle;
@@ -44,3 +44,5 @@
- (BOOL)hasVoice;
@end
NS_ASSUME_NONNULL_END
@@ -29,7 +29,7 @@
*/
#import <UIKit/UIKit.h>
@import UIKit;
#import "ORKCustomStepView_Internal.h"
+16 -12
View File
@@ -30,11 +30,13 @@
#import "ORKAudioContentView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
#import "ORKLabel.h"
#import "ORKHeadlineLabel.h"
#import "ORKLabel.h"
#import "ORKAccessibility.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
// The central blue region.
@@ -59,6 +61,7 @@ static const CGFloat GraphViewRedZoneHeight = 25;
static const CGFloat ValueLineWidth = 4.5;
static const CGFloat ValueLineMargin = 1.5;
@implementation ORKAudioGraphView
- (instancetype)initWithFrame:(CGRect)frame {
@@ -67,7 +70,7 @@ static const CGFloat ValueLineMargin = 1.5;
[self setUpConstraints];
#if TARGET_IPHONE_SIMULATOR
_values = @[@(0.2),@(0.6),@(0.55), @(0.1), @(0.75), @(0.7)];
_values = @[ @(0.2), @(0.6), @(0.55), @(0.1), @(0.75), @(0.7) ];
#endif
}
return self;
@@ -328,17 +331,16 @@ static const CGFloat ValueLineMargin = 1.5;
}
- (void)updateTimerLabel {
static NSDateComponentsFormatter *_formatter = nil;
static NSDateComponentsFormatter *formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSDateComponentsFormatter *formatter = [NSDateComponentsFormatter new];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
_formatter = formatter;
});
NSString *string = [_formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
NSString *string = [formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = string;
_timerLabel.hidden = (string == nil);
}
@@ -351,6 +353,10 @@ static const CGFloat ValueLineMargin = 1.5;
- (void)updateAlertLabelHidden {
NSNumber *sample = _samples.lastObject;
BOOL show = (!_finished && (sample.doubleValue > _alertThreshold)) || _failed;
if (_alertLabel.hidden && show) {
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, _alertLabel.text);
}
_alertLabel.hidden = !show;
}
@@ -384,11 +390,9 @@ static const CGFloat ValueLineMargin = 1.5;
}
- (NSString *)accessibilityLabel {
if (_alertLabel.isHidden) {
return _timerLabel.accessibilityLabel;
}
return ORKAccessibilityStringForVariables(_timerLabel.accessibilityLabel, _alertLabel.accessibilityLabel);
NSString *timerAxString = _timerLabel.isHidden ? nil : _timerLabel.accessibilityLabel;
NSString *alertAxString = _alertLabel.isHidden ? nil : _alertLabel.accessibilityLabel;
return ORKAccessibilityStringForVariables(ORKLocalizedString(@"AX_AUDIO_BAR_GRAPH", nil), timerAxString, alertAxString);
}
- (UIAccessibilityTraits)accessibilityTraits {
+5 -2
View File
@@ -49,8 +49,11 @@
3. This notice may not be removed or altered from any source distribution.
*/
#import <ResearchKit/ORKRecorder.h>
#import <AVFoundation/AVFoundation.h>
@import UIKit;
@import AVFoundation;
#import "ORKTypes.h"
NS_ASSUME_NONNULL_BEGIN
+18 -18
View File
@@ -49,15 +49,15 @@
3. This notice may not be removed or altered from any source distribution.
*/
#import "ORKAudioGenerator.h"
@import AudioToolbox;
@interface ORKAudioGenerator () {
@public
AudioComponentInstance _toneUnit;
@public
@interface ORKAudioGenerator () {
@public
AudioComponentInstance _toneUnit;
double _frequency;
double _theta;
ORKAudioChannel _activeChannel;
@@ -148,15 +148,15 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
- (void)applicationDidBecomeActive:(NSNotification *)notification {
if (_toneUnit) {
__unused OSErr err = AudioOutputUnitStart(_toneUnit);
NSAssert1(err == noErr, @"Error starting unit: %hd", err);
__unused OSErr error = AudioOutputUnitStart(_toneUnit);
NSAssert1(error == noErr, @"Error starting unit: %hd", error);
}
}
- (void)applicationWillResignActive:(NSNotification *)notification {
if (_toneUnit) {
__unused OSErr err = AudioOutputUnitStop(_toneUnit);
NSAssert1(err == noErr, @"Error stopping unit: %hd", err);
__unused OSErr error = AudioOutputUnitStop(_toneUnit);
NSAssert1(error == noErr, @"Error stopping unit: %hd", error);
}
}
@@ -194,12 +194,12 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
[self createToneUnit];
// Stop changing parameters on the unit
OSErr err = AudioUnitInitialize(_toneUnit);
NSAssert1(err == noErr, @"Error initializing unit: %hd", err);
OSErr error = AudioUnitInitialize(_toneUnit);
NSAssert1(error == noErr, @"Error initializing unit: %hd", error);
// Start playback
err = AudioOutputUnitStart(_toneUnit);
NSAssert1(err == noErr, @"Error starting unit: %hd", err);
error = AudioOutputUnitStart(_toneUnit);
NSAssert1(error == noErr, @"Error starting unit: %hd", error);
}
}
@@ -240,20 +240,20 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
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);
OSErr error = AudioComponentInstanceNew(defaultOutput, &_toneUnit);
NSAssert1(_toneUnit, @"Error creating unit: %hd", error);
// Set our tone rendering function on the unit
AURenderCallbackStruct input;
input.inputProc = ORKAudioGeneratorRenderTone;
input.inputProcRefCon = (__bridge void *)(self);
err = AudioUnitSetProperty(_toneUnit,
error = AudioUnitSetProperty(_toneUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input));
NSAssert1(err == noErr, @"Error setting callback: %hd", err);
NSAssert1(error == noErr, @"Error setting callback: %hd", error);
// Set the format to 32 bit, single channel, floating point, linear PCM
const int four_bytes_per_float = 4;
@@ -267,13 +267,13 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
streamFormat.mBytesPerFrame = four_bytes_per_float;
streamFormat.mChannelsPerFrame = 2;
streamFormat.mBitsPerChannel = four_bytes_per_float * eight_bits_per_byte;
err = AudioUnitSetProperty (_toneUnit,
error = AudioUnitSetProperty (_toneUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&streamFormat,
sizeof(AudioStreamBasicDescription));
NSAssert1(err == noErr, @"Error setting stream format: %hd", err);
NSAssert1(error == noErr, @"Error setting stream format: %hd", error);
}
- (void)handleInterruption:(id)sender {
@@ -0,0 +1,77 @@
/*
Copyright (c) 2016, Sage Bionetworks
Copyright (c) 2016, Apple Inc.
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/ORKStepNavigationRule.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKAudioLevelNavigationRule : ORKStepNavigationRule
/*
The `init` and `new` methods are unavailable.
`ORKStepNavigationRule` classes should be initialized with custom designated initializers on each
subclass.
*/
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/**
Returns an initialized direct-step navigation rule using the specified destination step identifier.
@param audioLevelStepIdentifier The identifier of the step with the audio file to check.
@param destinationStepIdentifier The identifier of the destination step if audio test passes.
@param recordingSettings Use key AVNumberOfChannelsKey to sepcify the number of recording channels.
@return A audio level step navigation rule.
*/
- (instancetype)initWithAudioLevelStepIdentifier:(NSString *)audioLevelStepIdentifier
destinationStepIdentifier:(NSString *)destinationStepIdentifier
recordingSettings:(NSDictionary *)recordingSettings NS_DESIGNATED_INITIALIZER;
/**
Returns a new direct-step navigation rule initialized from data in a given unarchiver.
@param aDecoder The coder from which to initialize the step navigation rule.
@return A new direct-step navigation rule.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@property (nonatomic, copy, readonly) NSString *audioLevelStepIdentifier;
@property (nonatomic, copy, readonly) NSString *destinationStepIdentifier;
@property (nonatomic, copy, readonly) NSDictionary *recordingSettings;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,217 @@
/*
Copyright (c) 2016, Sage Bionetworks
Copyright (c) 2016, Apple Inc.
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 "ORKAudioLevelNavigationRule.h"
#import "ORKResult.h"
#import "ORKResultPredicate.h"
#import "ORKStepNavigationRule_Internal.h"
#import "ORKHelpers_Internal.h"
#import <AVFoundation/AVFoundation.h>
Float32 const VolumeThreshold = 0.45;
UInt16 const LinearPCMBitDepth = 16;
Float32 const MaxAmplitude = 32767.0;
Float32 const VolumeClamp = 60.0;
@interface ORKAudioLevelNavigationRule ()
@property (nonatomic, copy, readwrite) NSString *audioLevelStepIdentifier;
@property (nonatomic, copy, readwrite) NSString *destinationStepIdentifier;
@property (nonatomic, copy, readwrite) NSDictionary *recordingSettings;
@end
@implementation ORKAudioLevelNavigationRule
+ (instancetype)new {
ORKThrowMethodUnavailableException();
}
- (instancetype)init {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithAudioLevelStepIdentifier:(NSString *)audioLevelStepIdentifier
destinationStepIdentifier:(NSString *)destinationStepIdentifier
recordingSettings:(NSDictionary *)recordingSettings
{
ORKThrowInvalidArgumentExceptionIfNil(audioLevelStepIdentifier);
ORKThrowInvalidArgumentExceptionIfNil(destinationStepIdentifier);
ORKThrowInvalidArgumentExceptionIfNil(recordingSettings);
self = [super init];
if (self) {
_audioLevelStepIdentifier = [audioLevelStepIdentifier copy];
_destinationStepIdentifier = [destinationStepIdentifier copy];
_recordingSettings = [recordingSettings copy];
}
return self;
}
#pragma mark NSSecureCoding
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_OBJ_CLASS(aDecoder, audioLevelStepIdentifier, NSString);
ORK_DECODE_OBJ_CLASS(aDecoder, destinationStepIdentifier, NSString);
ORK_DECODE_OBJ_CLASS(aDecoder, recordingSettings, NSDictionary);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_OBJ(aCoder, audioLevelStepIdentifier);
ORK_ENCODE_OBJ(aCoder, destinationStepIdentifier);
ORK_ENCODE_OBJ(aCoder, recordingSettings);
}
#pragma mark NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
typeof(self) rule = [[[self class] allocWithZone:zone] initWithAudioLevelStepIdentifier:self.audioLevelStepIdentifier destinationStepIdentifier:self.destinationStepIdentifier recordingSettings:self.recordingSettings];
return rule;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame
&& ORKEqualObjects(self.audioLevelStepIdentifier, castObject.audioLevelStepIdentifier)
&& ORKEqualObjects(self.destinationStepIdentifier, castObject.destinationStepIdentifier)
&& ORKEqualObjects(self.recordingSettings, castObject.recordingSettings));
}
- (NSUInteger)hash {
return _audioLevelStepIdentifier.hash ^ _destinationStepIdentifier.hash ^ _recordingSettings.hash;
}
#pragma mark - Required overrides
- (NSString *)identifierForDestinationStepWithTaskResult:(ORKTaskResult *)taskResult {
// Get the result file
ORKStepResult *stepResult = (ORKStepResult *)[taskResult resultForIdentifier:self.audioLevelStepIdentifier];
ORKFileResult *audioLevelResult = (ORKFileResult *)[stepResult.results firstObject];
// Check the volume
if ((audioLevelResult.fileURL != nil) && [self checkAudioLevelFromSoundFile:audioLevelResult.fileURL]) {
// Returning nil will drop through to the next step (which should be the the step that has the instructions
// for moving to a quieter room).
return nil;
}
return self.destinationStepIdentifier;
}
- (BOOL)checkAudioLevelFromSoundFile:(NSURL *)fileURL {
// Setup reader
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
if (urlAsset.tracks.count == 0) {
NSLog(@"No tracks found for urlAsset: %@", fileURL);
return NO;
}
NSError *error = nil;
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:urlAsset error:&error];
AVAssetTrack *track = [urlAsset.tracks objectAtIndex:0];
NSDictionary *outputSettings = @{AVFormatIDKey: @(kAudioFormatLinearPCM),
AVLinearPCMBitDepthKey: @(LinearPCMBitDepth),
AVLinearPCMIsBigEndianKey: @(NO),
AVLinearPCMIsFloatKey: @(NO),
AVLinearPCMIsNonInterleaved: @(NO)};
AVAssetReaderTrackOutput *output = [[AVAssetReaderTrackOutput alloc] initWithTrack:track outputSettings:outputSettings];
[reader addOutput:output];
// Setup initial values - Assume 2 channels if not in recording settings
const UInt32 channelCount = (UInt32)[self.recordingSettings[AVNumberOfChannelsKey] unsignedIntegerValue] ? : 2;
const UInt32 bytesPerSample = 2 * channelCount;
// setup criteria block - Use a high-pass filter and a rolling average of the amplitude
// normalized to be < 1
__block Float32 rollingAvg = 0;
__block UInt64 totalCount = 0;
void (^processVolume)(Float32) = ^(Float32 amplitude) {
if (amplitude != 0) {
Float32 dB = 20 * log10(ABS(amplitude) / MaxAmplitude);
float clampedValue = MAX(dB / VolumeClamp, -1) + 1;
totalCount++;
rollingAvg = (rollingAvg * (totalCount - 1) + clampedValue) / totalCount;
}
};
// While there are samples to read and the number of samples above the decibel threshold
// is less than the total number of allowed samples over the limit, keep going
[reader startReading];
while (reader.status == AVAssetReaderStatusReading) {
AVAssetReaderTrackOutput *trackOutput = (AVAssetReaderTrackOutput *)[reader.outputs objectAtIndex:0];
CMSampleBufferRef sampleBufferRef = [trackOutput copyNextSampleBuffer];
if (sampleBufferRef) {
CMBlockBufferRef blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef);
size_t length = CMBlockBufferGetDataLength(blockBufferRef);
NSMutableData *data = [NSMutableData dataWithLength:length];
CMBlockBufferCopyDataBytes(blockBufferRef, 0, length, data.mutableBytes);
SInt16 *samples = (SInt16 *) data.mutableBytes;
UInt64 sampleCount = length / bytesPerSample;
for (UInt32 i = 0; i < sampleCount ; i++) {
Float32 left = (Float32) *samples++;
processVolume(left);
if (channelCount == 2) {
Float32 right = (Float32) *samples++;
processVolume(right);
}
}
CMSampleBufferInvalidate(sampleBufferRef);
CFRelease(sampleBufferRef);
}
}
return rollingAvg > VolumeThreshold;
}
@end
+2 -1
View File
@@ -29,8 +29,9 @@
*/
@import UIKit;
@import AVFoundation;
#import <ResearchKit/ORKRecorder.h>
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
+20 -6
View File
@@ -30,10 +30,10 @@
#import "ORKAudioRecorder.h"
#import "ORKHelpers.h"
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
#import "ORKDefines_Private.h"
#import "ORKHelpers_Internal.h"
@interface ORKAudioRecorder ()
@@ -42,6 +42,8 @@
@property (nonatomic, copy) NSDictionary *recorderSettings;
@property (nonatomic, copy) NSString *savedSessionCategory;
@end
@@ -79,6 +81,16 @@
return self;
}
- (void)restoreSavedAudioSessionCategory {
if (_savedSessionCategory) {
NSError *error;
if (![[AVAudioSession sharedInstance] setCategory:_savedSessionCategory error:&error]) {
ORK_Log_Error(@"Failed to restore the audio session category: %@", [error localizedDescription]);
}
_savedSessionCategory = nil;
}
}
- (void)start {
if (self.outputDirectory == nil) {
@throw [NSException exceptionWithName:NSDestinationInvalidException reason:@"audioRecorder requires an output directory" userInfo:nil];
@@ -95,6 +107,7 @@
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
_savedSessionCategory = audioSession.category;
if (![audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]) {
[self finishRecordingWithError:error];
return;
@@ -191,12 +204,13 @@
[self applyFileProtection:ORKFileProtectionComplete toFileAtURL:[self recordingFileURL]];
#endif
[self restoreSavedAudioSessionCategory];
}
}
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
@@ -231,7 +245,7 @@
return [[self recordingDirectoryURL] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", [self logName], [self extension]]];
}
- (BOOL)recreateFileWithError:(NSError * __autoreleasing *)error {
- (BOOL)recreateFileWithError:(NSError **)error {
NSURL *url = [self recordingFileURL];
if (!url) {
if (error) {
@@ -253,7 +267,7 @@
}
[fileManager createFileAtPath:[url path] contents:nil attributes:nil];
[fileManager setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(ORKFileProtectionCompleteUnlessOpen)} ofItemAtPath:[url path] error:error];
[fileManager setAttributes:@{NSFileProtectionKey: ORKFileProtectionFromMode(ORKFileProtectionCompleteUnlessOpen)} ofItemAtPath:[url path] error:error];
return YES;
}
+1
View File
@@ -29,6 +29,7 @@
*/
@import Foundation;
#import <ResearchKit/ORKActiveStep.h>
+5 -1
View File
@@ -30,10 +30,13 @@
#import "ORKAudioStep.h"
#import "ORKAudioStepViewController.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@implementation ORKAudioStep
@@ -45,6 +48,7 @@
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
self.shouldStartTimerAutomatically = YES;
}
return self;
}
@@ -29,7 +29,9 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
@@ -37,6 +39,8 @@ NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKAudioStepViewController : ORKActiveStepViewController
@property (nonatomic, assign) CGFloat alertThreshold;
@end
NS_ASSUME_NONNULL_END
@@ -30,17 +30,22 @@
#import "ORKAudioStepViewController.h"
#import "ORKAudioContentView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKVerticalContainerView.h"
#import <AVFoundation/AVFoundation.h>
#import "ORKActiveStepTimer.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
#import "ORKAudioStep.h"
#import "ORKAudioRecorder.h"
#import "ORKActiveStepView.h"
#import "ORKAudioContentView.h"
#import "ORKCustomStepView_Internal.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKAudioRecorder.h"
#import "ORKAudioStep.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@import AVFoundation;
@interface ORKAudioStepViewController ()
@@ -66,17 +71,24 @@
return self;
}
- (void)setAlertThreshold:(CGFloat)alertThreshold {
_alertThreshold = alertThreshold;
if (self.isViewLoaded && alertThreshold > 0) {
_audioContentView.alertThreshold = alertThreshold;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_audioContentView = [ORKAudioContentView new];
_audioContentView.timeLeft = self.audioStep.stepDuration;
self.activeStepView.activeCustomView = _audioContentView;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self start];
if (self.alertThreshold > 0) {
_audioContentView.alertThreshold = self.alertThreshold;
}
self.activeStepView.activeCustomView = _audioContentView;
}
- (void)audioRecorderDidChange {
@@ -115,9 +127,9 @@
- (void)startNewTimerIfNeeded {
if (!_timer) {
NSTimeInterval duration = self.audioStep.stepDuration;
__weak typeof(self) weakSelf = self;
ORKWeakTypeOf(self) weakSelf = self;
_timer = [[ORKActiveStepTimer alloc] initWithDuration:duration interval:duration / 100 runtime:0 handler:^(ORKActiveStepTimer *timer, BOOL finished) {
typeof(self) strongSelf = weakSelf;
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf doSample];
if (finished) {
[strongSelf finish];
@@ -170,7 +182,7 @@
_avAudioRecorder = recorder;
}
- (void) recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error {
- (void)recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error {
[super recorder:recorder didFailWithError:error];
_audioRecorderError = error;
_audioContentView.failed = YES;
+6 -1
View File
@@ -29,10 +29,13 @@
*/
#import <ResearchKit/ResearchKit.h>
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKCountdownStep` class represents a step that displays a label and a
countdown for a time equal to its duration.
@@ -46,3 +49,5 @@ ORK_CLASS_AVAILABLE
@interface ORKCountdownStep : ORKActiveStep
@end
NS_ASSUME_NONNULL_END
@@ -30,6 +30,7 @@
#import "ORKCountdownStep.h"
#import "ORKCountdownStepViewController.h"
@@ -29,9 +29,13 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKCountdownStepViewController` class represents the step view controller that corresponds to an `ORKCountdownStep`.
@@ -43,3 +47,5 @@ ORK_CLASS_AVAILABLE
@interface ORKCountdownStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -30,23 +30,29 @@
#import "ORKCountdownStepViewController.h"
#import "ORKCustomStepView_Internal.h"
#import "ORKActiveStepViewController_internal.h"
#import "ORKVerticalContainerView.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStepTimer.h"
#import "ORKResult.h"
#import "ORKActiveStepView.h"
#import "ORKCustomStepView_Internal.h"
#import "ORKLabel.h"
#import "ORKSubheadlineLabel.h"
#import "ORKHelpers.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStep.h"
#import "ORKResult.h"
#import "ORKAccessibility.h"
#import "ORKActiveStepView.h"
#import "ORKHelpers_Internal.h"
@interface ORKCountDownViewLabel : ORKLabel
@end
@implementation ORKCountDownViewLabel
+ (UIFont *)defaultFont {
return ORKThinFontWithSize(56);
@@ -173,8 +179,8 @@ static const CGFloat ProgressIndicatorOuterMargin = 1.0;
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = duration * 2;
animation.removedOnCompletion = YES;
animation.values = @[@(1.0), @(0.0), @(0.0)];
animation.keyTimes = @[@(0.0), @(0.5), @(1.0)];
animation.values = @[ @(1.0), @(0.0), @(0.0) ];
animation.keyTimes = @[ @(0.0), @(0.5), @(1.0) ];
animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[_circleLayer addAnimation:animation forKey:@"drawCircleAnimation"];
}
+51 -21
View File
@@ -29,8 +29,8 @@
*/
#import <Foundation/Foundation.h>
#import <ResearchKit/ORKDefines.h>
@import Foundation;
#import <ResearchKit/ORKTypes.h>
NS_ASSUME_NONNULL_BEGIN
@@ -65,6 +65,18 @@ NS_ASSUME_NONNULL_BEGIN
@end
@protocol ORKDataLoggerExtendedDelegate <ORKDataLoggerDelegate>
@optional
/**
Tells the delegate that the maximum current log file lifetime changed.
@param dataLogger Source of this event.
*/
- (void)dataLoggerThresholdsDidChange:(ORKDataLogger *)dataLogger;
@end
@class ORKLogFormatter;
/**
@@ -101,6 +113,7 @@ ORK_CLASS_AVAILABLE
*/
+ (ORKDataLogger *)JSONDataLoggerWithDirectory:(NSURL *)url logName:(NSString *)logName delegate:(nullable id<ORKDataLoggerDelegate>)delegate;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/**
@@ -166,7 +179,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
- (BOOL)enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
/**
Enumerates the URLs of completed log files not yet marked uploaded,
@@ -181,7 +194,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
/**
Enumerates the URLs of completed log files not already marked uploaded,
@@ -196,7 +209,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
/**
Appends an object to the log file, which is formatted with `logFormatter`.
@@ -207,12 +220,12 @@ ORK_CLASS_AVAILABLE
log data is made. If an attempt is made to log data and there is no access due
to file protection, the log is immediately rolled over and a new file created.
@param object Should be an object of a class that is accepted by the logFormatter.
@param error Error output, if the append fails.
@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;
- (BOOL)append:(id)object error:(NSError * _Nullable *)error;
/**
Appends multiple objects to the log file.
@@ -220,12 +233,12 @@ ORK_CLASS_AVAILABLE
This method formats and appends all the objects at once. Using this method may have efficiency
and atomicity gains for error handling, compared to making multiple calls to `append:error`.
@param objects An array of objects of a class that is accepted by the logFormatter.
@param error Error output, if the append fails.
@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;
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * _Nullable *)error;
/**
Checks whether a file has been marked as uploaded.
@@ -251,7 +264,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if adding or removing the attribute succeeded; otherwise, `NO`.
*/
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * _Nullable *)error;
/**
Removes files if they are marked uploaded.
@@ -265,7 +278,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if removing the files succeeded; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * _Nullable *)error;
/**
Removes all files managed by this logger (files that have the `logName` prefix).
@@ -274,7 +287,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if removing the files succeeded.; otherwise, `NO`.
*/
- (BOOL)removeAllFilesWithError:(NSError *_Nullable __autoreleasing *)error;
- (BOOL)removeAllFilesWithError:(NSError * _Nullable *)error;
@end
@@ -320,7 +333,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
/**
Appends the specified object to the log file.
@@ -331,7 +344,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
/**
Appends the specified objects to the log file.
@@ -342,7 +355,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
@end
@@ -425,6 +438,7 @@ ORK_CLASS_AVAILABLE
ORK_CLASS_AVAILABLE
@interface ORKDataLoggerManager : NSObject <ORKDataLoggerDelegate>
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/**
@@ -505,7 +519,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the enumeration succeeds; otherwise, `NO`.
*/
- (BOOL)enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
- (BOOL)enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
/**
Unmarks the set of uploaded files.
@@ -518,7 +532,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable *)error;
/**
Removes a set of uploaded files.
@@ -532,7 +546,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable *)error;
/**
Removes old and uploaded logs to bring total bytes down to a threshold.
@@ -545,7 +559,23 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError * _Nullable *)error;
@end
@interface ORKDataLogger (Tests)
/// The file handle to which to write
- (nullable NSFileHandle *)fileHandle;
@end
@interface NSURL (ORKDataLogger)
- (BOOL)ork_isUploaded;
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError * _Nullable *)error;
@end
+63 -56
View File
@@ -30,13 +30,12 @@
#import "ORKDataLogger.h"
#import <ResearchKit/ResearchKit.h>
#import "ORKHelpers.h"
#include <sys/xattr.h>
#import "ORKDataLogger_Private.h"
#import "HKSample+ORKJSONDictionary.h"
#import "ORKHelpers_Internal.h"
#import "CMMotionActivity+ORKJSONDictionary.h"
#import "ORKDefines_Private.h"
#import "HKSample+ORKJSONDictionary.h"
#include <sys/xattr.h>
static const char *ORKDataLoggerUploadedAttr = "com.apple.ResearchKit.uploaded";
@@ -109,7 +108,7 @@ static NSString *const ORKDataLoggerManagerConfigurationFilename = @".ORKDataLog
return (string.integerValue != 0);
}
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError * __autoreleasing *)error {
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError **)error {
NSString *value = (uploaded ? @"1" : @"0");
NSData *encodedString = [value dataUsingEncoding:NSUTF8StringEncoding];
return [self ork_setData:encodedString forAttr:ORKDataLoggerUploadedAttr error:error];
@@ -133,12 +132,12 @@ static NSString *const ORKDataLoggerManagerConfigurationFilename = @".ORKDataLog
return data;
}
- (BOOL)ork_setData:(NSData *)data forAttr:(const char *)attr error:(NSError * __autoreleasing *)error {
- (BOOL)ork_setData:(NSData *)data forAttr:(const char *)attr error:(NSError **)error {
const char *path = [self fileSystemRepresentation];
int rc = setxattr(path, attr, data.bytes, data.length, 0, 0);
if (rc != 0) {
if (error) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:rc userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_SET_ATTRIBUTE", nil)}];
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:rc userInfo:@{NSLocalizedDescriptionKey: ORKLocalizedString(@"ERROR_DATALOGGER_SET_ATTRIBUTE", nil)}];
}
}
return (rc == 0);
@@ -239,11 +238,11 @@ static void *ORKObjectObserverContext = &ORKObjectObserverContext;
return [object isKindOfClass:[NSData class]];
}
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
return YES;
}
- (BOOL)writeData:(NSData *)data fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
- (BOOL)writeData:(NSData *)data fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
BOOL result = YES;
@try {
[fileHandle writeData:data];
@@ -251,7 +250,7 @@ static void *ORKObjectObserverContext = &ORKObjectObserverContext;
@catch (NSException *exception) {
result = NO;
if (error) {
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorException userInfo:@{@"exception" : exception}];
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorException userInfo:@{@"exception": exception}];
}
}
return result;
@@ -266,14 +265,14 @@ static void *ORKObjectObserverContext = &ORKObjectObserverContext;
[fileHandle truncateFileAtOffset:offset];
}
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
if (![self canAcceptLogObject:object]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"ORKLogFormatter accepts NSData only" userInfo:nil];
}
return [self writeData:(NSData *)object fileHandle:fileHandle error:error];
}
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
unsigned long long checkpoint = [self checkpointWithFileHandle:fileHandle];
NSError *errorOut = nil;
@@ -327,7 +326,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return [object isKindOfClass:[NSDictionary class]] && [NSJSONSerialization isValidJSONObject:object];
}
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
// Write valid JSON containing no objects
NSData *data = [kJSONLogEmptyLogString dataUsingEncoding:NSUTF8StringEncoding];
return [self writeData:data fileHandle:fileHandle error:error];
@@ -348,7 +347,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
}
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
return [self appendObjects:@[object] fileHandle:fileHandle error:error];
}
@@ -446,10 +445,12 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return [[ORKDataLogger alloc] initWithDirectory:url logName:logName formatter:[ORKJSONLogFormatter new] delegate:delegate];
}
+ (instancetype)new {
ORKThrowMethodUnavailableException();
}
- (instancetype)init {
ORKThrowMethodUnavailableException();
return nil;
}
- (instancetype)initWithDirectory:(NSURL *)url logName:(NSString *)logName formatter:(ORKLogFormatter *)formatter delegate:(id<ORKDataLoggerDelegate>)delegate {
@@ -490,7 +491,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
@throw [NSException exceptionWithName:NSGenericException reason:[NSString stringWithFormat:@"%@ is not a class", configuration[@"formatterClass"]] userInfo:nil];
}
self = [self initWithDirectory:url logName:configuration[@"logName"] formatter:[formatterClass new] delegate:delegate];
self = [self initWithDirectory:url logName:configuration[@"logName"] formatter:[[formatterClass alloc] init] delegate:delegate];
if (self) {
// Don't notify about initial setup
[_observer pause];
@@ -502,11 +503,11 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
- (NSDictionary *)configuration {
return @{@"logName" : self.logName,
@"formatterClass" : NSStringFromClass([self.logFormatter class]),
@"fileProtectionMode" : @(self.fileProtectionMode),
@"maximumCurrentLogFileSize" : @(self.maximumCurrentLogFileSize),
@"maximumCurrentLogFileLifetime" : @(self.maximumCurrentLogFileLifetime)
return @{@"logName": self.logName,
@"formatterClass": NSStringFromClass([self.logFormatter class]),
@"fileProtectionMode": @(self.fileProtectionMode),
@"maximumCurrentLogFileSize": @(self.maximumCurrentLogFileSize),
@"maximumCurrentLogFileLifetime": @(self.maximumCurrentLogFileLifetime)
};
}
@@ -527,9 +528,9 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (_directorySource) {
dispatch_source_set_cancel_handler(_directorySource, ^{ close(dirFD); });
__weak __typeof(self) weakSelf = self;
ORKWeakTypeOf(self) weakSelf = self;
dispatch_source_set_event_handler(_directorySource, ^{
__strong __typeof(self) strongSelf = weakSelf;
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf directoryUpdated];
});
dispatch_resume(_directorySource);
@@ -594,11 +595,11 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return success;
}
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
return [self enumerateLogsUploaded:NO block:block error:error];
}
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
return [self enumerateLogsUploaded:YES block:block error:error];
}
@@ -686,7 +687,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
});
}
- (BOOL)queue_enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
- (BOOL)queue_enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
static NSArray *keys = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@@ -744,7 +745,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return (errorOut ? NO : YES);
}
- (BOOL)queue_enumerateLogsUploaded:(BOOL)uploaded block:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
- (BOOL)queue_enumerateLogsUploaded:(BOOL)uploaded block:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
return [self queue_enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
NSError *errorOut = nil;
BOOL wantUploaded = [logFileUrl ork_isUploaded];
@@ -758,7 +759,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
} error:error];
}
- (NSFileHandle *)queue_makeFileHandleWithError:(NSError * __autoreleasing *)error {
- (NSFileHandle *)queue_makeFileHandleWithError:(NSError **)error {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *url = [self currentLogFileURL];
@@ -784,7 +785,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
BOOL success = [fileManager createFileAtPath:filePath contents:nil attributes:nil];
if (!success) {
if (error) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileNoSuchFileError userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_CREATE_FILE", nil)}];
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileNoSuchFileError userInfo:@{NSLocalizedDescriptionKey: ORKLocalizedString(@"ERROR_DATALOGGER_CREATE_FILE", nil)}];
}
return nil;
}
@@ -799,7 +800,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
assert(fileHandle);
// Set file protection after opening the file, so that class B works as expected.
BOOL success = [fileManager setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(self.fileProtectionMode)} ofItemAtPath:[url path] error:error];
BOOL success = [fileManager setAttributes:@{NSFileProtectionKey: ORKFileProtectionFromMode(self.fileProtectionMode)} ofItemAtPath:[url path] error:error];
// Allow formatter to initialize the log file with header content
success = success && [self.logFormatter beginLogWithFileHandle:fileHandle error:error];
@@ -814,7 +815,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return _currentFileHandle;
}
- (NSFileHandle *)queue_fileHandleWithError:(NSError * __autoreleasing *)error {
- (NSFileHandle *)queue_fileHandleWithError:(NSError **)error {
if (!_currentFileHandle) {
_currentFileHandle = [self queue_makeFileHandleWithError:error];
@@ -824,15 +825,15 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
+ (NSURL *)nextUrlForDirectoryUrl:(NSURL *)directory logName:(NSString *)logName {
static NSDateFormatter *dfm = nil;
static NSDateFormatter *dateFromatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dfm = [NSDateFormatter new];
[dfm setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
dfm.dateFormat = @"yyyyMMddHHmmss";
dateFromatter = [NSDateFormatter new];
[dateFromatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
dateFromatter.dateFormat = @"yyyyMMddHHmmss";
});
NSString *datedLog = [NSString stringWithFormat:@"%@-%@",logName, [dfm stringFromDate:[NSDate date]]];
NSString *datedLog = [NSString stringWithFormat:@"%@-%@",logName, [dateFromatter stringFromDate:[NSDate date]]];
NSURL *destinationUrl = [directory URLByAppendingPathComponent:datedLog];
NSFileManager *fileManager = [NSFileManager defaultManager];
@@ -868,8 +869,8 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (self.fileProtectionMode == ORKFileProtectionCompleteUnlessOpen) {
// Upgrade to complete file protection after roll-over
NSError *error = nil;
if (![fileManager setAttributes:@{NSFileProtectionKey : NSFileProtectionComplete}
ofItemAtPath:[destinationUrl path] error:&error]) {
if (![fileManager setAttributes:@{NSFileProtectionKey: NSFileProtectionComplete}
ofItemAtPath:[destinationUrl path] error:&error]) {
ORK_Log_Warning(@"Error setting NSFileProtectionComplete on %@: %@", destinationUrl, error);
}
}
@@ -907,7 +908,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
[self queue_closeAndRenameLog];
}
- (BOOL)queue_append:(id)object error:(NSError * __autoreleasing *)error {
- (BOOL)queue_append:(id)object error:(NSError **)error {
[self queue_rolloverIfNeeded];
NSFileHandle *fileHandle = [self queue_fileHandleWithError:error];
@@ -925,7 +926,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return result;
}
- (BOOL)queue_appendObjects:(NSArray *)objects error:(NSError * __autoreleasing *)error {
- (BOOL)queue_appendObjects:(NSArray *)objects error:(NSError **)error {
[self queue_rolloverIfNeeded];
NSFileHandle *fileHandle = [self queue_fileHandleWithError:error];
@@ -942,13 +943,13 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return result;
}
- (BOOL)queue_markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * __autoreleasing *)error {
- (BOOL)queue_markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError **)error {
BOOL success = [url ork_setUploaded:uploaded error:error];
[self queue_setNeedsUpdateBytes];
return success;
}
- (BOOL)queue_removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * __autoreleasing *)error {
- (BOOL)queue_removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError **)error {
NSFileManager *fileManager = [NSFileManager defaultManager];
__block NSMutableArray *errors = [NSMutableArray array];
BOOL success = [self queue_enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
@@ -962,7 +963,9 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
} else {
// File was requested to be removed, but was not marked uploaded
[errors addObject:[NSError errorWithDomain:ORKErrorDomain code:ORKErrorInvalidObject userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_COULD_NOT_MAORK", nil), @"url" : logFileUrl}]];
[errors addObject:[NSError errorWithDomain:ORKErrorDomain
code:ORKErrorInvalidObject
userInfo:@{NSLocalizedDescriptionKey: ORKLocalizedString(@"ERROR_DATALOGGER_COULD_NOT_MAORK", nil), @"url": logFileUrl}]];
}
}
} error:error];
@@ -971,7 +974,9 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (errors.count) {
if (!success && error && *error) {
[errors addObject:*error];
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorMultipleErrors userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_MULTIPLE", nil), @"errors" : errors}];
*error = [NSError errorWithDomain:ORKErrorDomain
code:ORKErrorMultipleErrors
userInfo:@{NSLocalizedDescriptionKey: ORKLocalizedString(@"ERROR_DATALOGGER_MULTIPLE", nil), @"errors": errors}];
}
success = NO;
}
@@ -1042,10 +1047,12 @@ static NSInteger _ORKJSON_terminatorLength = 0;
@implementation ORKDataLoggerManager
+ (instancetype)new {
ORKThrowMethodUnavailableException();
}
- (instancetype)init {
ORKThrowMethodUnavailableException();
return nil;
}
- (instancetype)initWithDirectory:(NSURL *)directory delegate:(id<ORKDataLoggerManagerDelegate>)delegate {
@@ -1094,9 +1101,9 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
- (NSDictionary *)queue_configuration {
NSMutableArray *loggerConfigurations = [_records.allValues valueForKey:@"configuration"];
return @{PendingUploadBytesThresholdKey : @(self.pendingUploadBytesThreshold),
TotalBytesThresholdKey : @(self.totalBytesThreshold),
LoggerConfigurationsKey : loggerConfigurations };
return @{PendingUploadBytesThresholdKey: @(self.pendingUploadBytesThreshold),
TotalBytesThresholdKey: @(self.totalBytesThreshold),
LoggerConfigurationsKey: loggerConfigurations };
}
- (void)queue_synchronizeConfiguration {
@@ -1175,7 +1182,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return logNames;
}
- (BOOL)queue_enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
- (BOOL)queue_enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
BOOL success = YES;
NSMutableArray *allFiles = [NSMutableArray array];
// Collect all the log file URLs so we can sort them by date rather than enumerating by logger.
@@ -1226,7 +1233,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)queue_removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * __autoreleasing *)error {
- (BOOL)queue_removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError **)error {
BOOL success = YES;
NSMutableArray *notRemoved = [NSMutableArray array];
for (NSURL *url in fileURLs) {
@@ -1258,7 +1265,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)queue_unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * __autoreleasing *)error {
- (BOOL)queue_unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError **)error {
BOOL success = YES;
NSMutableArray<NSURL *> *notRemoved = [NSMutableArray array];
for (NSURL *url in fileURLs) {
@@ -1281,7 +1288,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError *__autoreleasing *)error {
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * __autoreleasing *)error {
__block BOOL success = YES;
dispatch_sync(_queue, ^{
success = [self queue_unmarkUploadedFiles:fileURLs error:error];
@@ -1289,7 +1296,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)queue_removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError *__autoreleasing *)error {
- (BOOL)queue_removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError **)error {
if (bytes == 0) {
for (ORKDataLogger *logger in _records) {
[logger removeAllFilesWithError:nil];
@@ -1346,7 +1353,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return (totalBytes <= bytes);
}
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError *__autoreleasing *)error {
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError * __autoreleasing *)error {
__block BOOL success = YES;
dispatch_sync(_queue, ^{
success = [self queue_removeOldAndUploadedLogsToThreshold:bytes error:error];
@@ -28,8 +28,11 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class CMDeviceMotion;
@@ -30,13 +30,16 @@
#import "ORKDeviceMotionRecorder.h"
#import "ORKHelpers.h"
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
#import "ORKDataLogger.h"
#import <CoreMotion/CoreMotion.h>
#import "ORKRecorder_Internal.h"
#import "ORKHelpers_Internal.h"
#import "CMDeviceMotion+ORKJSONDictionary.h"
@import CoreMotion;
@interface ORKDeviceMotionRecorder () {
ORKDataLogger *_logger;
@@ -85,10 +88,10 @@
[super start];
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
if (!_logger) {
[self finishRecordingWithError:err];
[self finishRecordingWithError:error];
return;
}
}
+16 -13
View File
@@ -30,12 +30,16 @@
#import "ORKFitnessContentView.h"
#import "ORKHelpers.h"
#import <CoreMotion/CoreMotion.h>
#import "ORKSkin.h"
#import "ORKActiveStepQuantityView.h"
#import "ORKTintedImageView.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@import CoreMotion;
@import HealthKit;
// #define LAYOUT_TEST 1
// #define LAYOUT_DEBUG 1
@@ -315,7 +319,7 @@
HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit meterUnit] doubleValue:displayDistance];
distanceString = [_lengthFormatter.numberFormatter stringFromNumber:@([quantity doubleValueForUnit:hkUnit]*conversionFactor)];
[self distanceView].title = [NSString stringWithFormat:ORKLocalizedString(@"FITNESS_DISTANCE_TITLE_FORMAT", nil), unitString];
[self distanceView].title = [NSString localizedStringWithFormat:ORKLocalizedString(@"FITNESS_DISTANCE_TITLE_FORMAT", nil), unitString];
[self distanceView].value = distanceString;
}
@@ -325,19 +329,18 @@
}
- (void)updateTimerLabel {
static NSDateComponentsFormatter *_formatter = nil;
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;
formatter = [NSDateComponentsFormatter new];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
});
NSString *s = [_formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = s;
_timerLabel.hidden = (s == nil);
NSString *labelString = [formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = labelString;
_timerLabel.hidden = (labelString == nil);
}
@end
+6 -1
View File
@@ -29,10 +29,13 @@
*/
#import <ResearchKit/ResearchKit.h>
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
/**
Fitness step.
@@ -45,3 +48,5 @@ ORK_CLASS_AVAILABLE
@interface ORKFitnessStep : ORKActiveStep
@end
NS_ASSUME_NONNULL_END
+1
View File
@@ -30,6 +30,7 @@
#import "ORKFitnessStep.h"
#import "ORKFitnessStepViewController.h"
@@ -29,9 +29,13 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
/**
Step view controller corresponding to `ORKFitnessStep`.
@@ -42,3 +46,5 @@ ORK_CLASS_AVAILABLE
@interface ORKFitnessStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -30,19 +30,24 @@
#import "ORKFitnessStepViewController.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepView.h"
#import "ORKFitnessContentView.h"
#import "ORKVerticalContainerView.h"
#import "ORKFitnessStep.h"
#import "ORKStepViewController_Internal.h"
#import "ORKHealthQuantityTypeRecorder.h"
#import "ORKPedometerRecorder.h"
#import "ORKActiveStepView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKFitnessStep.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@interface ORKFitnessStepViewController () <ORKHealthQuantityTypeRecorderDelegate,ORKPedometerRecorderDelegate> {
@interface ORKFitnessStepViewController () <ORKHealthQuantityTypeRecorderDelegate, ORKPedometerRecorderDelegate> {
NSInteger _intendedSteps;
ORKFitnessContentView *_contentView;
NSNumberFormatter *_hrFormatter;
@@ -29,6 +29,7 @@
*/
@import UIKit;
#import <ResearchKit/ORKRecorder.h>
@@ -30,7 +30,7 @@
#import "ORKHealthQuantityTypeRecorder.h"
#import "ORKHelpers.h"
#import "ORKHelpers_Internal.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Private.h"
#import "ORKRecorder_Internal.h"
@@ -43,12 +43,29 @@
HKHealthStore *_healthStore;
NSPredicate *_samplePredicate;
HKObserverQuery *_observerQuery;
NSInteger _anchor;
/// Either the HKQueryAnchor object *or* NSUInteger value are tracked since the initializer for
/// iOS 8 and iOS 9 use different objects. Only one will actually be referenced in the initalizer.
HKQueryAnchor *_anchor;
NSUInteger _anchorValue;
HKQuantitySample *_lastSample;
}
@end
#ifdef __IPHONE_10_0
/// Add a protocol defining the initializer for iOS 8 apps. This signature was deprecated in iOS 9
/// and deleted in iOS 10.
@interface HKAnchoredObjectQuery (iOS8)
- (instancetype)initWithType:(HKSampleType *)type
predicate:(NSPredicate *)predicate
anchor:(NSUInteger)anchor
limit:(NSUInteger)limit
completionHandler:(void (^)(HKAnchoredObjectQuery *query,
NSArray<__kindof HKSample *> *results,
NSUInteger newAnchor,
NSError *error))handler NS_DEPRECATED_IOS(8_0, 9_0);
@end
#endif
@implementation ORKHealthQuantityTypeRecorder
@@ -67,7 +84,8 @@
_quantityType = quantityType;
_unit = unit;
self.continuesInBackground = YES;
_anchor = HKAnchoredObjectQueryNoAnchor;
_anchorValue = HKAnchoredObjectQueryNoAnchor;
_anchor = [HKQueryAnchor anchorFromValue:_anchorValue];
}
return self;
}
@@ -89,7 +107,7 @@
static const NSInteger _HealthAnchoredQueryLimit = 100;
- (void)query_logResults:(NSArray *)results withAnchor:(NSUInteger)newAnchor {
- (void)query_logResults:(NSArray *)results withAnchor:(HKQueryAnchor*)newAnchor anchorValue:(NSUInteger)anchorValue {
NSUInteger resultCount = results.count;
if (resultCount == 0) {
@@ -113,6 +131,7 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
_anchor = newAnchor;
_anchorValue = anchorValue;
if (resultCount == _HealthAnchoredQueryLimit) {
// Do another fetch immediately rather than wait for an observation
@@ -128,23 +147,46 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
NSAssert(_samplePredicate != nil, @"Sample predicate should be non-nil if recording");
__weak typeof(self) weakSelf = self;
HKAnchoredObjectQuery *anchoredQuery = [[HKAnchoredObjectQuery alloc]
initWithType:_quantityType
predicate:_samplePredicate
anchor:_anchor
limit:_HealthAnchoredQueryLimit
completionHandler:^(HKAnchoredObjectQuery *query, NSArray *results, NSUInteger newAnchor, NSError *error)
{
if (error) {
// An error in the query's not the end of the world: we'll probably get another chance. Just log it.
ORK_Log_Warning(@"Anchored query error: %@", error);
return;
}
__typeof(self) strongSelf = weakSelf;
[strongSelf query_logResults:results withAnchor:newAnchor];
}];
void (^handleResults)(NSArray <__kindof HKSample *> *, HKQueryAnchor *, NSUInteger, NSError *) = ^ (NSArray *results, HKQueryAnchor *newAnchor, NSUInteger newAnchorValue, NSError *error) {
if (error) {
// An error in the query's not the end of the world: we'll probably get another chance. Just log it.
ORK_Log_Warning(@"Anchored query error: %@", error);
return;
}
__typeof(self) strongSelf = weakSelf;
[strongSelf query_logResults:results withAnchor:newAnchor anchorValue:newAnchorValue];
};
HKAnchoredObjectQuery *anchoredQuery;
if ([HKAnchoredObjectQuery instancesRespondToSelector:@selector(initWithType:predicate:anchor:limit:resultsHandler:)]) {
anchoredQuery = [[HKAnchoredObjectQuery alloc] initWithType:_quantityType
predicate:_samplePredicate
anchor:_anchor
limit:_HealthAnchoredQueryLimit
resultsHandler:
^(HKAnchoredObjectQuery *query, NSArray *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) {
handleResults(sampleObjects, newAnchor, 0, error);
}];
} else if ([HKAnchoredObjectQuery instancesRespondToSelector:@selector(initWithType:predicate:anchor:limit:completionHandler:)]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
anchoredQuery = [[HKAnchoredObjectQuery alloc] initWithType:_quantityType
predicate:_samplePredicate
anchor:_anchorValue
limit:_HealthAnchoredQueryLimit
completionHandler:
^(HKAnchoredObjectQuery *query, NSArray<__kindof HKSample *> *results, NSUInteger newAnchor, NSError *error) {
handleResults(results, nil, newAnchor, error);
}];
#pragma clang diagnostic pop
}
else {
NSAssert(NO, @"Could not instantiate an HKAnchoredObjectQuery.");
}
[_healthStore executeQuery:anchoredQuery];
}
@@ -29,7 +29,9 @@
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import "ORKTypes.h"
NS_ASSUME_NONNULL_BEGIN
@@ -30,10 +30,12 @@
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKHolePegTestPlacePegView.h"
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKDirectionView.h"
#import "ORKHelpers.h"
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKHolePegTestPlacePegView.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@@ -163,7 +165,7 @@ static const CGFloat ORKHolePegViewDiameter = 88.0f;
NSMutableArray *constraintsArray = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _pegView, _holeView, _directionView);
NSDictionary *metrics = @{@"diameter" : @(ORKHolePegViewDiameter)};
NSDictionary *metrics = @{@"diameter": @(ORKHolePegViewDiameter)};
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
@@ -29,13 +29,14 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceHoleView : UIView
@interface ORKHolePegTestPlaceHoleView : UIView <CAAnimationDelegate>
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@property (nonatomic, assign, getter = isSuccess) BOOL success;
@@ -31,6 +31,8 @@
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKHelpers_Internal.h"
static const CGFloat ORKPlaceHoleViewRotation = 45.0f;
@@ -161,9 +163,9 @@ static const CGFloat ORKPlaceHoleViewRotation = 45.0f;
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
__weak typeof(self) weakSelf = self;
ORKWeakTypeOf(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
typeof(self) strongSelf = weakSelf;
ORKStrongTypeOf(self) strongSelf = weakSelf;
strongSelf.success = NO;
});
}
@@ -29,7 +29,8 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
@@ -29,7 +29,9 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
@@ -39,7 +41,7 @@ ORK_CLASS_AVAILABLE
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign, getter = isDominantHandTested) BOOL dominantHandTested;
@property (nonatomic, assign) int numberOfPegs;
@property (nonatomic, assign) NSInteger numberOfPegs;
@property (nonatomic, assign) double threshold;
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@@ -31,6 +31,7 @@
#import "ORKHolePegTestPlaceStep.h"
#import "ORKHolePegTestPlaceStepViewController.h"
#import "ORKHelpers_Internal.h"
@implementation ORKHolePegTestPlaceStep
@@ -73,7 +74,7 @@
}
if (self.stepDuration < ORKHolePegTestMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
}
}
@@ -81,4 +82,55 @@
return NO;
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_ENUM(aDecoder, movingDirection);
ORK_DECODE_BOOL(aDecoder, dominantHandTested);
ORK_DECODE_INTEGER(aDecoder, numberOfPegs);
ORK_DECODE_DOUBLE(aDecoder, threshold);
ORK_DECODE_BOOL(aDecoder, rotated);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_ENUM(aCoder, movingDirection);
ORK_ENCODE_BOOL(aCoder, dominantHandTested);
ORK_ENCODE_INTEGER(aCoder, numberOfPegs);
ORK_ENCODE_DOUBLE(aCoder, threshold);
ORK_ENCODE_BOOL(aCoder, rotated);
}
- (instancetype)copyWithZone:(NSZone *)zone {
__typeof(self) step = [super copyWithZone:zone];
step.movingDirection = self.movingDirection;
step.dominantHandTested = self.dominantHandTested;
step.numberOfPegs = self.numberOfPegs;
step.threshold = self.threshold;
step.rotated = self.rotated;
return step;
}
- (NSUInteger)hash {
return [super hash] ^ self.movingDirection ^ self.dominantHandTested ^ self.numberOfPegs ^ (NSInteger)(self.threshold * 100) ^ self.rotated;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
(self.movingDirection == castObject.movingDirection) &&
(self.dominantHandTested == castObject.dominantHandTested) &&
(self.numberOfPegs == castObject.numberOfPegs) &&
(self.threshold == castObject.threshold) &&
(self.rotated == castObject.rotated));
}
@end
@@ -29,7 +29,9 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,11 +30,19 @@
#import "ORKHolePegTestPlaceStepViewController.h"
#import "ORKHolePegTestPlaceStep.h"
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKActiveStepViewController_internal.h"
#import "ORKStepViewController_internal.h"
#import "ORKActiveStepView.h"
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKTaskViewController.h"
#import "ORKHolePegTestPlaceStep.h"
#import "ORKNavigableOrderedTask.h"
#import "ORKResult.h"
#import "ORKHelpers_Internal.h"
@interface ORKHolePegTestPlaceStepViewController () <ORKHolePegTestPlaceContentViewDelegate>
@@ -29,7 +29,9 @@
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import "ORKTypes.h"
NS_ASSUME_NONNULL_BEGIN
@@ -30,10 +30,12 @@
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKDirectionView.h"
#import "ORKHolePegTestRemovePegView.h"
#import "ORKSeparatorView.h"
#import "ORKDirectionView.h"
#import "ORKHelpers.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@@ -156,7 +158,7 @@ static const CGFloat PegViewSeparatorWidth = 2.0f;
NSMutableArray *constraintsArray = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _container, _pegView, _separatorView, _directionView);
NSDictionary *metrics = @{@"diameter" : @(PegViewDiameter), @"separator" : @(PegViewSeparatorWidth), @"margin" : @((1 + self.threshold) * PegViewDiameter)};
NSDictionary *metrics = @{@"diameter": @(PegViewDiameter), @"separator": @(PegViewSeparatorWidth), @"margin": @((1 + self.threshold) * PegViewDiameter)};
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
@@ -29,13 +29,14 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemovePegView : UIView
@interface ORKHolePegTestRemovePegView : UIView <CAAnimationDelegate>
@property (nonatomic, assign, getter = isSuccess) BOOL success;
@@ -29,7 +29,9 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
@@ -39,7 +41,7 @@ ORK_CLASS_AVAILABLE
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign, getter = isDominantHandTested) BOOL dominantHandTested;
@property (nonatomic, assign) int numberOfPegs;
@property (nonatomic, assign) NSInteger numberOfPegs;
@property (nonatomic, assign) double threshold;
@end
@@ -30,8 +30,11 @@
#import "ORKHolePegTestRemoveStep.h"
#import "ORKHolePegTestRemoveStepViewController.h"
#import "ORKHelpers_Internal.h"
@implementation ORKHolePegTestRemoveStep
@@ -73,7 +76,7 @@
}
if (self.stepDuration < ORKHolePegTestMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
}
}
@@ -81,4 +84,51 @@
return NO;
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_ENUM(aDecoder, movingDirection);
ORK_DECODE_BOOL(aDecoder, dominantHandTested);
ORK_DECODE_INTEGER(aDecoder, numberOfPegs);
ORK_DECODE_DOUBLE(aDecoder, threshold);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_ENUM(aCoder, movingDirection);
ORK_ENCODE_BOOL(aCoder, dominantHandTested);
ORK_ENCODE_INTEGER(aCoder, numberOfPegs);
ORK_ENCODE_DOUBLE(aCoder, threshold);
}
- (instancetype)copyWithZone:(NSZone *)zone {
__typeof(self) step = [super copyWithZone:zone];
step.movingDirection = self.movingDirection;
step.dominantHandTested = self.dominantHandTested;
step.numberOfPegs = self.numberOfPegs;
step.threshold = self.threshold;
return step;
}
- (NSUInteger)hash {
return [super hash] ^ self.movingDirection ^ self.dominantHandTested ^ self.numberOfPegs ^ (NSInteger)(self.threshold * 100);
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
(self.movingDirection == castObject.movingDirection) &&
(self.dominantHandTested == castObject.dominantHandTested) &&
(self.numberOfPegs == castObject.numberOfPegs) &&
(self.threshold == castObject.threshold));
}
@end
@@ -29,7 +29,9 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,11 +30,18 @@
#import "ORKHolePegTestRemoveStepViewController.h"
#import "ORKHolePegTestRemoveStep.h"
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKActiveStepViewController_internal.h"
#import "ORKStepViewController_internal.h"
#import "ORKActiveStepView.h"
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKTaskViewController.h"
#import "ORKHolePegTestRemoveStep.h"
#import "ORKHelpers_Internal.h"
#import "ORKResult.h"
@interface ORKHolePegTestRemoveStepViewController () <ORKHolePegTestRemoveContentViewDelegate>
@@ -29,8 +29,9 @@
*/
@import UIKit;
@import CoreLocation;
#import <ResearchKit/ORKRecorder.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
+10 -7
View File
@@ -30,11 +30,14 @@
#import "ORKLocationRecorder.h"
#import <CoreLocation/CoreLocation.h>
#import "CLLocation+ORKJSONDictionary.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
#import "CLLocation+ORKJSONDictionary.h"
#import <CoreLocation/CoreLocation.h>
@interface ORKLocationRecorder () <CLLocationManagerDelegate> {
@@ -76,10 +79,10 @@
[super start];
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
if (!_logger) {
[self finishRecordingWithError:err];
[self finishRecordingWithError:error];
return;
}
}
@@ -94,7 +97,7 @@
if (!self.locationManager) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}];
userInfo:@{@"recorder": self}];
[self finishRecordingWithError:error];
return;
}
+2 -1
View File
@@ -29,7 +29,8 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import "ORKTypes.h"
#import "ORKCustomStepView_Internal.h"
+5 -3
View File
@@ -30,12 +30,14 @@
#import "ORKPSATContentView.h"
#import "ORKSkin.h"
#import "ORKBorderedButton.h"
#import "ORKPSATKeyboardView.h"
#import "ORKTapCountLabel.h"
#import "ORKBorderedButton.h"
#import "ORKVoiceEngine.h"
#import "ORKHelpers.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@interface ORKPSATContentView ()
@@ -29,7 +29,8 @@
*/
#import <ResearchKit/ResearchKit.h>
@import UIKit;
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
@@ -30,6 +30,7 @@
#import "ORKPSATKeyboardView.h"
#import "ORKBorderedButton.h"
+3 -1
View File
@@ -29,7 +29,9 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
+50
View File
@@ -30,8 +30,11 @@
#import "ORKPSATStep.h"
#import "ORKPSATStepViewController.h"
#import "ORKHelpers_Internal.h"
@implementation ORKPSATStep
@@ -90,4 +93,51 @@
return NO;
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_ENUM(aDecoder, presentationMode);
ORK_DECODE_DOUBLE(aDecoder, interStimulusInterval);
ORK_DECODE_DOUBLE(aDecoder, stimulusDuration);
ORK_DECODE_INTEGER(aDecoder, seriesLength);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_ENUM(aCoder, presentationMode);
ORK_ENCODE_DOUBLE(aCoder, interStimulusInterval);
ORK_ENCODE_DOUBLE(aCoder, stimulusDuration);
ORK_ENCODE_INTEGER(aCoder, seriesLength);
}
- (instancetype)copyWithZone:(NSZone *)zone {
ORKPSATStep *step = [super copyWithZone:zone];
step.presentationMode = self.presentationMode;
step.interStimulusInterval = self.interStimulusInterval;
step.stimulusDuration = self.stimulusDuration;
step.seriesLength = self.seriesLength;
return step;
}
- (NSUInteger)hash {
return [super hash] ^ self.presentationMode ^ (NSInteger)(self.interStimulusInterval*100) ^ (NSInteger)(self.stimulusDuration*100) ^ self.seriesLength;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
(self.presentationMode == castObject.presentationMode) &&
(self.interStimulusInterval == castObject.interStimulusInterval) &&
(self.stimulusDuration == castObject.stimulusDuration) &&
(self.seriesLength == castObject.seriesLength));
}
@end
@@ -29,7 +29,9 @@
*/
#import <ResearchKit/ResearchKit_Private.h>
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,13 +30,19 @@
#import "ORKPSATStepViewController.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKPSATContentView.h"
#import "ORKPSATStep.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepView.h"
#import "ORKPSATContentView.h"
#import "ORKPSATKeyboardView.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKPSATStep.h"
#import "ORKResult.h"
#import "ORKStepViewController_Internal.h"
#import "ORKHelpers_Internal.h"
@interface ORKPSATStepViewController () <ORKPSATKeyboardViewDelegate>
@@ -52,6 +58,7 @@
@end
@implementation ORKPSATStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
@@ -65,6 +72,7 @@
}
- (ORKPSATStep *)psatStep {
NSAssert(self.step == nil || [self.step isKindOfClass:[ORKPSATStep class]], @"Step class must be subclass of ORKPSATStep.");
return (ORKPSATStep *)self.step;
}
@@ -155,12 +163,12 @@
([self psatStep].interStimulusInterval - [self psatStep].stimulusDuration) > 0.05 ) {
// Don't show `-` if the difference between stimulusDuration and interStimulusInterval is less than timer's resolution.
__weak typeof(self) weakSelf = self;
ORKWeakTypeOf(self) weakSelf = self;
self.clearDigitsTimer = [[ORKActiveStepTimer alloc] initWithDuration:[self psatStep].stepDuration
interval:[self psatStep].interStimulusInterval
runtime:-[self psatStep].stimulusDuration
handler:^(ORKActiveStepTimer *timer, BOOL finished) {
typeof(self) strongSelf = weakSelf;
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf clearDigitsTimerFired];
}];
[self.clearDigitsTimer resume];
@@ -29,6 +29,7 @@
*/
@import UIKit;
#import <ResearchKit/ORKRecorder.h>
+12 -9
View File
@@ -30,10 +30,13 @@
#import "ORKPedometerRecorder.h"
#import "ORKDataLogger.h"
#import "CMPedometerData+ORKJSONDictionary.h"
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
#import "ORKHelpers_Internal.h"
#import "CMPedometerData+ORKJSONDictionary.h"
@interface ORKPedometerRecorder () {
@@ -91,10 +94,10 @@
_totalDistance = -1;
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
if (!_logger) {
[self finishRecordingWithError:err];
[self finishRecordingWithError:error];
return;
}
}
@@ -104,25 +107,25 @@
if (![[self.pedometer class] isStepCountingAvailable]) {
[self finishRecordingWithError:[NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}]];
userInfo:@{@"recorder": self}]];
return;
}
_isRecording = YES;
__weak __typeof(self) weakSelf = self;
ORKWeakTypeOf(self) weakSelf = self;
[self.pedometer startPedometerUpdatesFromDate:[NSDate date] withHandler:^(CMPedometerData *pedometerData, NSError *error) {
BOOL success = NO;
if (pedometerData) {
success = [_logger append:[pedometerData ork_JSONDictionary] error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
__typeof(self) strongSelf = weakSelf;
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf updateStatisticsWithData:pedometerData];
});
}
if (!success || error) {
dispatch_async(dispatch_get_main_queue(), ^{
__typeof(self) strongSelf = weakSelf;
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf finishRecordingWithError:error];
});
}
@@ -1,5 +1,5 @@
/*
Copyright (c) 2015, Apple Inc. All rights reserved.
Copyright (c) 2016, Darren Levy. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@@ -29,28 +29,23 @@
*/
#import <UIKit/UIKit.h>
#import "ORKSignatureView.h"
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
#import <ResearchKit/ORKOrderedTask.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKConsentSignatureController;
/**
The `ORKRangeOfMotionStep` class represents a step that takes a range of motion measurement.
*/
ORK_CLASS_AVAILABLE
@interface ORKRangeOfMotionStep : ORKActiveStep
@protocol ORKConsentSignatureControllerDelegate <NSObject>
@property (nonatomic, assign) ORKPredefinedTaskLimbOption limbOption; //The left and/or right limb to be tested during the task
- (void)consentSignatureControllerDidSign:(ORKConsentSignatureController *)consentSignatureController;
@end
@interface ORKConsentSignatureController : UIViewController<ORKSignatureViewDelegate>
@property (nonatomic, weak, nullable) id<ORKConsentSignatureControllerDelegate> delegate;
@property (nonatomic, strong, readonly, nullable) ORKSignatureView *signatureView;
@property (nonatomic, strong, nullable) NSString *localizedContinueButtonTitle;
- (instancetype)initWithIdentifier:(NSString *)identifier limbOption:(ORKPredefinedTaskLimbOption)limbOption;
@end
@@ -0,0 +1,101 @@
/*
Copyright (c) 2016, Darren Levy. 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 "ORKRangeOfMotionStep.h"
#import "ORKRangeOfMotionStepViewController.h"
#import "ORKHelpers_Internal.h"
@implementation ORKRangeOfMotionStep
+ (Class)stepViewControllerClass {
return [ORKRangeOfMotionStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier limbOption:(ORKPredefinedTaskLimbOption)limbOption {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldVibrateOnStart = YES;
self.shouldPlaySoundOnStart = YES;
self.shouldVibrateOnFinish = YES;
self.shouldPlaySoundOnFinish = YES;
self.shouldContinueOnFinish = YES;
self.shouldStartTimerAutomatically = YES;
self.limbOption = limbOption;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
if (self.limbOption != ORKPredefinedTaskLimbOptionLeft && self.limbOption != ORKPredefinedTaskLimbOptionRight) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:ORKLocalizedString(@"LIMB_OPTION_LEFT_OR_RIGHT_ERROR", nil)
userInfo:nil];
}
}
- (BOOL)startsFinished {
return NO;
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)copyWithZone:(NSZone *)zone {
ORKRangeOfMotionStep *step = [super copyWithZone:zone];
step.limbOption = self.limbOption;
return step;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_INTEGER(aDecoder, limbOption);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_INTEGER(aCoder, limbOption);
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame && (self.limbOption == castObject.limbOption));
}
@end
@@ -0,0 +1,50 @@
/*
Copyright (c) 2016, Darren Levy. 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 <CoreMotion/CMDeviceMotion.h>
NS_ASSUME_NONNULL_BEGIN
/**
This class is used by the `ORKRangeOfMotionStep.` Its result corresponds to the device's orientation
as recorded by CoreMotion.
*/
ORK_CLASS_AVAILABLE
@interface ORKRangeOfMotionStepViewController : ORKActiveStepViewController {
double _flexedAngle;
double _rangeOfMotionAngle;
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,216 @@
/*
Copyright (c) 2016, Darren Levy. 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 "ORKRangeOfMotionStepViewController.h"
#import "ORKCustomStepView_Internal.h"
#import "ORKHelpers_Internal.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKVerticalContainerView_Internal.h"
#import "ORKDeviceMotionRecorder.h"
#import "ORKActiveStepView.h"
#import "ORKProgressView.h"
#import "ORKSkin.h"
#define radiansToDegrees(radians) ((radians) * 180.0 / M_PI)
#define allOrientationsForPitch(x, w, y, z) (atan2(2.0 * (x*w + y*z), 1.0 - 2.0 * (x*x + z*z)))
@interface ORKRangeOfMotionContentView : ORKActiveStepCustomView {
NSLayoutConstraint *_topConstraint;
}
@property (nonatomic, strong, readonly) ORKProgressView *progressView;
@end
@implementation ORKRangeOfMotionContentView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_progressView = [ORKProgressView new];
_progressView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_progressView];
[self setUpConstraints];
[self updateConstraintConstantsForWindow:self.window];
}
return self;
}
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
[self updateConstraintConstantsForWindow:newWindow];
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray new];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView);
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_progressView]-(>=0)-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
_topConstraint = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]; // constant will be set in updateConstraintConstantsForWindow:
[constraints addObject:_topConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)updateConstraintConstantsForWindow:(UIWindow *)window {
const CGFloat CaptionBaselineToProgressTop = 100;
const CGFloat CaptionBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window);
_topConstraint.constant = CaptionBaselineToProgressTop - CaptionBaselineToStepViewTop;
}
- (void)updateConstraints {
[self updateConstraintConstantsForWindow:self.window];
[super updateConstraints];
}
@end
@interface ORKRangeOfMotionStepViewController () <ORKDeviceMotionRecorderDelegate> {
ORKRangeOfMotionContentView *_contentView;
UITapGestureRecognizer *_gestureRecognizer;
CMAttitude *_referenceAttitude;
UIInterfaceOrientation _orientation;
double _highestAngle;
double _lowestAngle;
double _lastAngle;
}
@end
@implementation ORKRangeOfMotionStepViewController
- (void)viewDidLoad {
[super viewDidLoad];
_contentView = [ORKRangeOfMotionContentView new];
_contentView.translatesAutoresizingMaskIntoConstraints = NO;
self.activeStepView.activeCustomView = _contentView;
_gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[self.activeStepView addGestureRecognizer:_gestureRecognizer];
}
- (void)handleTap:(UIGestureRecognizer *)sender {
[self calculateAndSetFlexedAndExtendedAngles];
[self finish];
}
- (void)calculateAndSetFlexedAndExtendedAngles {
_flexedAngle = fabs([self getDeviceAngleInDegreesFromAttitude:_referenceAttitude]);
BOOL rangeOfMotionMoreThan180Degrees = _highestAngle > 175 && _lowestAngle < 175;
if (rangeOfMotionMoreThan180Degrees) {
_rangeOfMotionAngle = 360 - fabs(_lastAngle);
} else {
_rangeOfMotionAngle = fabs(_lastAngle);
}
}
#pragma mark - ORKDeviceMotionRecorderDelegate
- (void)deviceMotionRecorderDidUpdateWithMotion:(CMDeviceMotion *)motion {
if (!_referenceAttitude) {
_referenceAttitude = motion.attitude;
}
CMAttitude *currentAttitude = [motion.attitude copy];
[currentAttitude multiplyByInverseOfAttitude:_referenceAttitude];
double angle = [self getDeviceAngleInDegreesFromAttitude:currentAttitude];
if (angle > _highestAngle) {
_highestAngle = angle;
}
if (angle < _lowestAngle) {
_lowestAngle = angle;
}
_lastAngle = angle;
}
/*
When the device is in Portrait mode, we need to get the attitude's pitch
to determine the device's angle. attitude.pitch doesn't return all
orientations, so we use the attitude's quaternion to calculate the
angle.
*/
- (double)getDeviceAngleInDegreesFromAttitude:(CMAttitude *)attitude {
if (!_orientation) {
_orientation = [UIApplication sharedApplication].statusBarOrientation;
}
double angle;
if (UIInterfaceOrientationIsLandscape(_orientation)) {
angle = radiansToDegrees(attitude.roll);
} else {
double x = attitude.quaternion.x;
double w = attitude.quaternion.w;
double y = attitude.quaternion.y;
double z = attitude.quaternion.z;
angle = radiansToDegrees(allOrientationsForPitch(x, w, y, z));
}
return angle;
}
#pragma mark - ORKActiveTaskViewController
- (ORKResult *)result {
ORKStepResult *stepResult = [super result];
ORKRangeOfMotionResult *result = [[ORKRangeOfMotionResult alloc] initWithIdentifier:self.step.identifier];
result.flexed = _flexedAngle;
result.extended = result.flexed - _rangeOfMotionAngle;
stepResult.results = [self.addedResults arrayByAddingObject:result] ? : @[result];
return stepResult;
}
@end
@@ -29,9 +29,12 @@
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKReactionTimeContentView : ORKActiveStepCustomView
- (void)setStimulusHidden:(BOOL)hidden;
@@ -43,3 +46,5 @@
- (void)resetAfterDelay:(NSTimeInterval)delay completion:(nullable void (^)(void))completion;
@end
NS_ASSUME_NONNULL_END
@@ -30,8 +30,9 @@
#import "ORKReactionTimeContentView.h"
#import "ORKReactionTimeStimulusView.h"
#import "ORKNavigationContainerView.h"
#import "ORKReactionTimeStimulusView.h"
@implementation ORKReactionTimeContentView {
@@ -26,11 +26,13 @@
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>
@import Foundation;
@import AudioToolbox;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN

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