Compare commits

...

1038 Commits

Author SHA1 Message Date
Pariece McKinney 9443313e96 updated docs 2025-02-19 17:43:31 -05:00
Pariece McKinney 3e79f78bbd updated docs 2025-02-19 17:37:30 -05:00
Pariece McKinney c152631578 Update documentation to 7a899026 on 'stable' 2025-02-19 14:05:00 -05:00
Pariece McKinney b33747374f initial commit 2025-02-19 13:57:23 -05:00
Pariece McKinney 7a8990260c Public Release 3.1.1 2025-02-18 18:05:13 -05:00
Pariece McKinney 9b1153da04 Public release 2.2.16 2024-04-25 17:09:00 -04:00
Louie 38d161f1bf Stable Public Release 2.2.15
Merging main into stable
2023-12-05 14:20:25 -08:00
Louie 1b9daf60ee Merge pull request #1530 from ResearchKit/cocoapod_version_bump
Point ResearchKit.podspec to 2.1.0
2022-11-29 13:11:01 -08:00
Louis Chatta e71d71cf9c Point ResearchKit.podspec to 2.1.0 2022-11-29 11:48:27 -08:00
akshay-yadav 29950b62e4 marker 2022-06-15 12:53:26 -07:00
akshay-yadav 65de4b333c README update 2022-06-15 11:44:35 -07:00
akshay-yadav 63fcf4918f Merge branch 'stable' into 'main' for housekeeping 2022-06-15 11:40:04 -07:00
akshay-yadav c9880b0139 merge stable into main
resolve merge conflicts
Bugfixes
Cleanup
merge main back to stable
2022-06-15 11:38:42 -07:00
akshay-yadav 13eabb7720 merging stable back to main
Resolving Merge conflicts
Bugfixes
Cleanup
2022-06-15 11:37:16 -07:00
Pariece McKinney 743b773ea3 Point RK to IOS 13 (#1499) 2022-04-25 09:40:44 -07:00
Pariece McKinney 249eee5dfb IOS15 Fixes (#1487) 2022-02-17 11:29:47 -08:00
aplummer-apple 90c68d0d19 Update project library search paths to compile on apple silicon (#1479)
I believe this line was in here to resolve issues with an early beta of xcode 11 and is unnecessary now
2021-11-29 10:20:27 -08:00
Pariece McKinney d10a427911 Merge pull request #1471 from Pariecemckinney-apple/pmckinney/taskVCDeprecationWarningFix
Fix ORKTaskViewController deprecation warning
2021-10-25 14:50:24 -07:00
Pariecemckinney-apple 05755a3213 initial commit 2021-10-25 11:38:50 -07:00
Corey e18a633de1 Set ORKTaskViewController nav background color (#1469) 2021-10-04 13:58:03 -07:00
Pariece McKinney 0e68cdf744 Merge pull request #1448 from stevemoser/patch-6
Fix broken Apple Forums link
2021-06-28 15:58:31 -07:00
Pariece McKinney 7f119a8d0d Merge pull request #1338 from Hengyu/hengyu
Use implied answer format for cells
2021-06-28 15:54:27 -07:00
hengyu fde1e7e957 Use implied answer format for cells 2021-06-27 14:58:31 +08:00
Erik Hornberger 0ad96d505c Merge pull request #1462 from erik-apple/nullable-return-type
Silence warning about nullable return types
2021-06-21 15:25:36 -07:00
Erik Hornberger d4ff76fc25 Silence warning about nullable return types 2021-06-21 15:08:01 -07:00
Erik Hornberger 85c1395361 Merge pull request #1461 from erik-apple/update-deprecated-method-in-keychain
Update deprecated method call
2021-06-21 14:47:45 -07:00
Erik Hornberger 1443e57c57 Replace deprecated method call 2021-06-21 14:22:10 -07:00
Erik Hornberger 3b75f6213c Updates to the predefined range of motion task (#1459) 2021-05-25 17:05:56 -07:00
gavirawson-apple e9d5de64a5 Clip step image (#1457) 2021-05-19 18:11:15 -07:00
Erik Hornberger 19c61383f6 Permission Type Updates (#1454)
* Ensure that the slider's colors match the view's tint

* New visual style for request permission step

* Add a new notifications permission type

* Add a new motion activity permission type

* Update ORKRequestPermissionButton.m

* Forward declare button

* Update ResearchKit/Common/ORKPermissionType.m

Co-authored-by: joeylabarck-apple <81833193+joeylabarck-apple@users.noreply.github.com>

* Update ResearchKit/Common/ORKPermissionType.h

Co-authored-by: joeylabarck-apple <81833193+joeylabarck-apple@users.noreply.github.com>

* Update ResearchKit/Common/ORKMotionActivityPermissionType.h

Co-authored-by: joeylabarck-apple <81833193+joeylabarck-apple@users.noreply.github.com>

* Update ResearchKit/Common/ORKPermissionType.h

Co-authored-by: joeylabarck-apple <81833193+joeylabarck-apple@users.noreply.github.com>

* Update ResearchKit/Common/ORKPermissionType.h

Co-authored-by: joeylabarck-apple <81833193+joeylabarck-apple@users.noreply.github.com>

* Add missing import

* Add missing import

Co-authored-by: joeylabarck-apple <81833193+joeylabarck-apple@users.noreply.github.com>
2021-04-16 17:02:45 -07:00
Steve Moser cb6cc97fa4 Fix broken Apple Forums link 2021-03-01 08:26:36 -05:00
srinathtm-apple 0651bf0c2a Use wheel date picker style (#1447)
* Use wheel date picker style
2021-02-11 19:16:32 -08:00
Pariece McKinney 68f9d29b66 Merge pull request #1396 from Pariecemckinney-apple/video_instruction_fix_issue_1389
Video Instruction Step Now Presents Play Button (#1389)
2020-08-03 16:29:25 -07:00
Pariecemckinney-apple 24afb1b1ec video instruction step now presents the play button so that the user can present the video intended for them 2020-08-03 16:19:07 -07:00
Kyle Seth Gray 47f44c488e Update ORKSkin.m (#1390)
literally just a misspelling of 'Margin'
2020-07-21 11:13:42 -07:00
Pariece McKinney a9b64253f1 VideoCaptureStep now corrects its state when navigating to it after pressing the back button (#1386)
Co-authored-by: Pariece McKinney <pariecemckinney@gmail.com>
2020-07-17 15:44:23 -07:00
Volodymyr Klymenko 506dc646ad Fix markdown formatting (#1383) 2020-06-24 14:21:05 -07:00
srinathtm-apple b50b759c7e RK 2.1 updates (#1384) 2020-06-24 14:20:11 -07:00
Greg Fiumara ed2602e523 Handle new UITouchPhase enumerations. (#1366)
* Handle new UITouchPhase enumerations.

Added in iOS 13.4.

* Conditionally include new UITouchPhase enums.
2020-04-05 16:36:15 -07:00
srinathtm-apple bbe376cddc Remove scripts folder, this is causing app store submission issues (#1362)
* removing scripts folder

* removing references from build phases
2020-03-26 11:25:16 -07:00
srinathtm-apple 50a2b3427a RK 2.1 updates (#1343)
* updates to RK 2.1

* adding AirPodsPro calibration data
2020-03-09 20:34:15 -07:00
Alex Wald ac7c63fc1b added missing nullability annotation in one of the initialisers (#1323) 2020-02-10 12:41:39 -08:00
srinathtm-apple b50e1d7aa4 Merge pull request #1333 from davwillev/master
Spoken instruction for TouchAnywhereStep changed from from title to text
2020-02-10 12:38:47 -08:00
David Evans 454e501cb6 Reallocated TouchAnywhereStep spoken instructions
Reallocated TouchAnywhereStep spoken instructions from task 'title' to instruction 'text'
2020-01-17 12:44:51 +00:00
David Evans 69cb1b7f2e Merge pull request #7 from ResearchKit/master
Update from master
2020-01-06 14:04:09 +00:00
srinathtm-apple 7c8917deb0 Merge pull request #1329 from xinsight/remove-tests-from-archive-2
remove tests from archive
2019-12-11 10:55:26 -08:00
Jay Moore e5e96b8db9 remove address and undef behaviour sanitizers 2019-12-11 18:04:31 +01:00
Jay Moore faffea0008 remove tests from archive 2019-12-11 13:28:29 +01:00
erik-apple e08711ff4b Retrieve tint color from view's window instead of AppDelegate's window (#1324)
We used to retrieve the view's tint color from a reference to the window held by the AppDelegate, however, iOS 13 introduced a new SceneDelegate pattern in which there may be more than one window. We now have to retrieve the tint color from window that the view belongs to, as there may be multiple windows with different tint colors.
2019-12-03 23:23:57 -05:00
srinathtm-apple c6c99a41db Merge pull request #1321 from erik-apple/2.1
ResearchKit 2.1 Update
2019-11-22 17:11:35 -08:00
erik-apple ff709e01f2 Update .travis.yml for Xcode 11 and iOS 13 2019-11-22 16:58:20 -08:00
erik-apple 666bf54dd5 Update ORKFormStep.h 2019-11-22 16:52:30 -08:00
erik-apple fbcd6adc9e Merge branch 'master' into 2.1 2019-11-22 16:48:50 -08:00
Erik Hornberger 2dc3cfb109 ResearchKit 2.1 Update 2019-11-22 16:40:08 -08:00
akshay-yadav ae9b9e57cb updates 2019-10-24 14:19:09 -07:00
srinathtm-apple e19dfbff8d Merge pull request #1298 from susom/instructionStepView-learnMore-fix
Fix displaying of Close button in ORKLearnMoreStepViewController
2019-10-23 12:03:58 -07:00
srinathtm-apple 6fc2e6d0fe Merge pull request #1308 from chrisortman/master
Fixes podspec in cocoapods 1.8.0
2019-10-23 12:03:24 -07:00
srinathtm-apple 456c3e4a45 Merge pull request #1311 from CareEvolution/sectionBug
Bugfix - Index needs to be _allSections
2019-10-23 12:02:54 -07:00
Eric Schramm eaca80f55a index needs to be _allSections 2019-10-17 08:45:10 -05:00
Chris Ortman d60ab56972 Fixes podspec in cocoapods 1.8.0 2019-10-04 16:56:39 -05:00
Paweł Kowalczyk 6b55e5ba81 Fix displaying of Close button in ORKLearnMoreStepViewController 2019-09-02 17:52:12 +02:00
David Evans 8c16ee46cc Merge pull request #6 from ResearchKit/master
Updating master to latest version
2019-07-24 12:15:53 +01:00
srinathtm-apple d56e6d5267 Merge pull request #1288 from srinathtm-apple/master
adding macro to bypass ios13 only api
2019-06-20 10:37:16 -07:00
Srinath Tupil Muralidharan 1ff84f4f96 adding macro to bypass ios13 only api 2019-06-19 16:08:14 -07:00
srinathtm-apple 3efb3ae1ae Merge pull request #1279 from CareEvolution/hideORKFormItemFix
Fix for hidePredicate changes where an ORKTableSection may contain more than one ORKFormItem
2019-06-17 14:39:02 -07:00
Eric Schramm d516d0cc0a reimplementation of hide ORKFormItem post-RK 2.1 2019-06-16 18:10:06 -05:00
Eric Schramm d2794890f8 Merge branch 'appleMaster' into hideORKFormItemFix
# Conflicts:
#	ResearchKit/Common/ORKFormStepViewController.m
2019-06-16 17:55:51 -05:00
srinathtm-apple ae70457c56 Merge pull request #1282 from ninoguba/bugfix_flash_modes
Fixed crash related to supported flash modes on certain devices
2019-06-04 13:57:27 -07:00
srinathtm-apple 800e45a27a Merge pull request #1280 from gabriel-blanco-apple/embeddedReviewStepIsEmpty-51368434
Missing embedded summary in ORKReviewStep
2019-06-04 13:56:51 -07:00
Akshay Yadav 7b6dae062c ResearchKit 2.1 Beta 2019-06-04 13:45:18 -07:00
Nino Guba 5070325d9a Fixed crash related to supported flash modes on certain devices 2019-06-03 18:48:21 -07:00
Gabriel Blanco 84511204d2 Missing embedded summary in ORKReviewStep
Bug introduced here:

commit 9ef1876c45
Author: Brian Ganninger <coder@infinitenexus.com>
Date:   Sun Nov 25 20:44:22 2018 -0800

    [code cleanup] Review mismatched nil returns (issue #1214)

——

Impact:
Causes embedded ORKReviewStep to return no steps
2019-06-03 14:52:32 -07:00
Eric Schramm ad8129efdf fixes for animation of changes 2019-06-02 22:48:57 -05:00
Eric Schramm 5f0f32f824 hideForm fix for sections which contain >1 forms 2019-05-31 15:17:59 -05:00
srinathtm-apple 7347a99520 Merge pull request #1277 from PersonalTouchProjects/mytouch
Add new activity tasks
2019-05-30 16:59:43 -07:00
Tommy Lin 12b2df63b4 Add missing header files to umbrella headers 2019-05-28 01:54:28 +08:00
Tommy Lin 00ac394379 Inherit ORKTouchAbilityScrollResult from ORKResult instead of ORKStepResult (typo) 2019-05-28 01:51:46 +08:00
srinathtm-apple 8f8cc4de14 Merge pull request #1271 from CareEvolution/Schramm/hideFormItemWithPredicate-2.0
Conditionally Hide an ORKFormItem based on an NSPredicate
2019-05-27 09:17:06 -07:00
Tommy Lin 577f612778 Fix retain cycle warnings 2019-05-27 22:31:10 +08:00
Tommy Lin e0f092decc Fix shadow declaration warning 2019-05-27 22:10:59 +08:00
Tommy Lin acacacdcce Add NSCopying, NSCoding and isEqual to ORKTouchAbility steps 2019-05-27 20:56:28 +08:00
Eric Schramm fce7172bac rename - filtered to hidden 2019-05-08 12:31:39 -05:00
Eric Schramm 264d51f1c9 explicitly compare against nil 2019-05-08 12:13:42 -05:00
Eric Schramm 6b1dd7f73d naming improvements, simplification 2019-05-08 12:08:50 -05:00
Eric Schramm ad5b4cb2fd update for renaming to hidePredicate 2019-04-24 21:44:08 -05:00
Eric Schramm 1faa99a490 rename to hidePredicate 2019-04-24 21:43:46 -05:00
Eric Schramm cf67d09e1b remove null results for filtered formItems 2019-04-24 16:00:29 -05:00
Eric Schramm 14a87b2067 fixed to corrected indexPath due to filtering 2019-04-24 15:56:53 -05:00
Eric Schramm 4f59976114 bypass non-optional formItems that are filtered 2019-04-24 15:36:34 -05:00
Eric Schramm 392dd87881 stop animated scrolling if no section show/hide changes 2019-04-19 16:06:03 -05:00
Eric Schramm fd8c973004 update didSelect to unfiltered indexPath 2019-04-19 15:16:01 -05:00
Eric Schramm ab400a203a implement hideItemPredicate in ORKFormStepVC 2019-04-19 14:43:39 -05:00
Eric Schramm 7fbd650fbb add hideItemPredicate to ORKFormItem 2019-04-19 14:39:42 -05:00
srinathtm-apple 01cc7ed79d Project updates (#1264)
* overall updates to ResearchKit, new textChoiceOtherAnswerFormat, unit tests and more..
2019-04-15 14:42:02 -07:00
Tommy Lin 62d5f17c75 Merge branch 'master' into mytouch 2019-03-28 15:48:25 +08:00
srinathtm-apple d198a8fa67 Merge pull request #1256 from yo1995/ORKSkinFix
Ork skin fix
2019-03-24 11:27:15 -07:00
Duke Mobile Center 77aa2444a2 clean comments 2019-03-24 13:01:44 -04:00
Duke Mobile Center 281b2093b1 #1255 solved the mapHeight metric and other compatibility issues. 2019-03-24 12:55:19 -04:00
srinathtm-apple 94c2b68e53 Merge pull request #1247 from srinathtm-apple/dBHLUpdates
dBHL Tone Audiometry updates
2019-02-26 18:42:30 -08:00
Srinath Tupil Muralidharan 99e3b370d5 if user taps during the preStimulusDelay, do not count it towards threshold calculation 2019-02-26 18:06:06 -08:00
srinathtm-apple 093513f01f Merge pull request #1241 from srinathtm-apple/splMeterUpdates
bugfixes for splmeter
2019-02-23 10:11:33 -08:00
srinathtm-apple 5e39fffe0d Merge pull request #1246 from rsanchezsaez-apple/rss/project-hardening-d
[Misc] Homogenize errorOut argument naming
2019-02-23 10:08:49 -08:00
Ricardo Sanchez-Saez 0ddd16b202 [Misc] Homogenize errorOut argument naming 2019-02-21 16:38:57 -08:00
David Evans 13fdd71613 Merge pull request #5 from ResearchKit/master
merge upstream
2019-02-21 12:26:25 +00:00
srinathtm-apple d000f5b45e Merge pull request #1245 from ResearchKit/rss/project-hardening-c
[Project Hardening] Improvements (III)
2019-02-20 23:40:02 -08:00
Ricardo Sanchez-Saez 19de603340 [ORKTaskViewController] More compact nil UUID check 2019-02-20 18:18:04 -08:00
Ricardo Sanchez-Saez 61af3f9b19 [ORKTaskViewController] Remove unneeded implementation 2019-02-20 18:12:44 -08:00
Ricardo Sanchez-Saez f614fda7b3 [Misc] Add a space before every ‘nil’ 2019-02-20 18:00:38 -08:00
Ricardo Sanchez-Saez 63fb484f22 [ORKSpeechRecognitionResult] Fix typo 2019-02-20 18:00:35 -08:00
Ricardo Sanchez-Saez 6e61d4f79b [ORKConsentSection] Remove unneeded import 2019-02-20 18:00:28 -08:00
Ricardo Sanchez-Saez 54feccdcff [ORKValuePicker] Undo unneeded changes 2019-02-20 17:59:51 -08:00
Ricardo Sanchez-Saez 5bc0088f16 [ORKVisualContentStepViewController] Better nullability handling 2019-02-20 17:59:44 -08:00
Ricardo Sanchez-Saez e4f7516b6f [ORKTintedImageView] Remove unneeded changes 2019-02-20 17:59:34 -08:00
Ricardo Sanchez-Saez 61290e42fa [ORKTintedImageView] Remove unneeded nullability 2019-02-20 17:59:26 -08:00
Ricardo Sanchez-Saez 82720f2978 [ORKPDFViewerStepView] Add default nullability 2019-02-20 17:59:17 -08:00
Ricardo Sanchez-Saez 08af95d3a7 [ORKTaskViewController] Better UUID nullability 2019-02-20 17:59:14 -08:00
Ricardo Sanchez-Saez 319b9f189e [ORKTableStepViewController] Better nullability 2019-02-20 17:59:10 -08:00
Ricardo Sanchez-Saez d6f71e2cdb [ORKStepNavigationRule] Improve comment 2019-02-20 17:59:02 -08:00
Ricardo Sanchez-Saez 92c2299a9d [ORKSkin] Remove unused code 2019-02-20 17:58:50 -08:00
Ricardo Sanchez-Saez ddb2c50aba [ORKReviewStep] Add braces for safety 2019-02-20 17:58:23 -08:00
Ricardo Sanchez-Saez 4d7c27a1dd [ORKReviewStep] Add extra nullable annotations 2019-02-20 17:58:20 -08:00
Ricardo Sanchez-Saez 2e0bef5490 [ORKPicker] Better nullability fix, remove unused function 2019-02-20 17:58:15 -08:00
Ricardo Sanchez-Saez 222855fabc [Misc] Nicer variable names 2019-02-20 17:58:12 -08:00
Ricardo Sanchez-Saez 97a503cf18 [ORKMultiValuePicker] Better nullability fix 2019-02-20 17:57:51 -08:00
Ricardo Sanchez-Saez 15b6204a9e [Misc] Rename findInArrayByKey to ORKFindInArrayByKey 2019-02-20 17:57:47 -08:00
Ricardo Sanchez-Saez 6f883b4acb [ORKHealthAnswerFormat] Better static analyzer fixes 2019-02-20 17:57:42 -08:00
Ricardo Sanchez-Saez 762d0350c4 Update comment to reflect code 2019-02-20 17:57:32 -08:00
Ricardo Sanchez-Saez ea01dbdbc3 Remove unneeded check 2019-02-20 17:57:24 -08:00
Ricardo Sanchez-Saez 363a1f7caa [ORKDateTimePicker] Better nullability test 2019-02-20 17:57:18 -08:00
Ricardo Sanchez-Saez 81b945a129 [ORKHealthAnswerFormat] Better nullability issue fix 2019-02-20 17:57:13 -08:00
Ricardo Sanchez-Saez 16a5da4566 [ORKGraphChartView] Simpler fix for shadowing variable declaration 2019-02-20 17:57:10 -08:00
Ricardo Sanchez-Saez 1c2af3c669 [ORKGraphChartView] Simpler fix for shadowing variable declaration 2019-02-20 17:57:06 -08:00
Ricardo Sanchez-Saez b412f47578 Rename ORKLineGraphAccessibilityElement to ORKGraphChartAccessibilityElement 2019-02-20 17:56:59 -08:00
Ricardo Sanchez-Saez d9cfb03dc6 [ORkGraphChartView] Fix wrong accessibility fix 2019-02-20 17:56:53 -08:00
Ricardo Sanchez-Saez 4baa86df01 [ORKGraphChartView] Remove unneeded change 2019-02-20 17:56:48 -08:00
Ricardo Sanchez-Saez c0c512b9ad [ORKStroopStepViewController] Change NSMutableDictionaries to NSDictionaries 2019-02-20 17:56:43 -08:00
Ricardo Sanchez-Saez 95d82db7cf [ORKAudioContentView] Do no set unneeded _timerLabel initial text 2019-02-20 17:56:24 -08:00
Ricardo Sanchez-Saez 66dbac3bb7 [Localization] Continue retuning ‘nil’ when the slider is not found 2019-02-20 17:56:20 -08:00
srinathtm-apple d969d55ab1 Merge pull request #1244 from rsanchezsaez-apple/rss/project-hardening-b
[Project Hardening] Improvements (II)
2019-02-20 17:51:09 -08:00
srinathtm-apple 95e8250194 Merge pull request #1243 from rsanchezsaez-apple/rss/project-hardening-a
[Project Hardening] Improvements (I)
2019-02-20 17:50:53 -08:00
Ricardo Sanchez-Saez 2539157e47 [Project] Disable “Missing Localization Context Comment” from static analyzer 2019-02-20 17:02:56 -08:00
Ricardo Sanchez-Saez a51b85622a [Project] Update project languages appropriately 2019-02-20 17:02:13 -08:00
Ricardo Sanchez-Saez 1e25391b0a Revert "[code cleanup] Add missing localization comments (issue #1214)"
This reverts commit c2b664f3b8.

# Conflicts:
#	ResearchKit/ActiveTasks/ORKAudioContentView.m
2019-02-20 16:57:14 -08:00
Ricardo Sanchez-Saez 9cc6255b45 [ORKSample] Update to Swift 4 2019-02-20 16:52:48 -08:00
Ricardo Sanchez-Saez 112bb1b7fa [ORKTest] Update to Swift 4 2019-02-20 16:52:38 -08:00
Ricardo Sanchez-Saez 041d015dbf [Project] Run static analyzer, in deep mode, only when building in Debug 2019-02-20 16:50:25 -08:00
Ricardo Sanchez-Saez 877edca1e6 [Project] Remove unsupported Swift 3.0 specifier from project 2019-02-20 16:50:16 -08:00
srinathtm-apple c7b2c33a29 Merge pull request #1216 from bgannin/projectHardening
Project hardening
2019-02-20 16:07:29 -08:00
srinathtm-apple ca1a18978f check if error is non-NULL before assignment 2019-02-18 20:24:30 -08:00
srinathtm-apple 0a962c6822 using NSInteger instead of NSUInteger 2019-02-18 17:56:49 -08:00
srinathtm-apple f07ae4b8f0 logical-or the missing super calls in ORKLocationSelectionView 2019-02-18 17:19:33 -08:00
srinathtm-apple b0d7eff709 logical-or the missing super calls 2019-02-18 17:16:49 -08:00
Srinath Tupil Muralidharan 390c02d2a8 bugfixes for splmeter 2019-02-14 12:25:46 -08:00
Tommy Lin 233142920f Merge master into mytouch 2019-02-14 17:10:44 +08:00
srinathtm-apple a4a147332d Merge pull request #1236 from jayway/email_fix
Fixed email regex to enforce start and end of string.
2019-02-04 08:57:26 -08:00
Gustaf Nilklint f1fdddf5d4 Fixed email regex to enforce start and end of string to eliminate the possibility to accidentally accept white space in the email adress. 2019-02-04 15:09:52 +01:00
Tommy Lin 489de1d8aa Fix ORKBorderedButton background color issue 2019-02-02 22:50:36 +08:00
Tommy Lin 52578e21fe Add internationalization strings 2019-01-28 16:26:08 +08:00
srinathtm-apple 92fc374b46 Merge pull request #1224 from srinathtm-apple/AttributedTextForSurveys
attributed text for surveys
2019-01-18 16:50:47 -08:00
Srinath Tupil Muralidharan c87b189f8a moving the assert to the designated initializer 2019-01-18 16:45:21 -08:00
Srinath Tupil Muralidharan b7cf4bc918 adding an assert if all the input params are nil 2019-01-18 16:39:51 -08:00
srinathtm-apple b803c3aab0 Merge pull request #1232 from aplummer-apple/tidy-onboarding
Minor example project onboarding cleanup
2019-01-18 15:58:56 -08:00
aplummer-apple 3094ba675c Update ORKSpatialSpanMemoryStepViewController.m 2019-01-18 15:51:23 -08:00
Andrew Plummer 88b7c9a68f Minor example project onboarding cleanup
- Tidy up localized strings
- Remove unused language config
- Delegate reference cycle
- Tidy signature access at end of onboarding

Minor syntax tidy

Minor Tidy, remove redundant check

Minor tidy, remove unnecessary variable

Minor tidy, clearer call

Fix broken “Disagree” button in example onboarding consent flow

Previously the flow let you progress as usual even if you select “disagree”

Remove development team

Clean whitespace
2019-01-10 18:38:34 -08:00
Tommy Lin 06e1e9bbfc Remove useless code 2019-01-08 14:50:11 +08:00
Srinath Tupil Muralidharan 36b8a72056 renaming an internal function 2019-01-07 17:44:10 -08:00
Srinath Tupil Muralidharan 111b983716 account for case where text is nil but primaryTextAttributedString is non-nil 2019-01-07 15:49:53 -08:00
Srinath Tupil Muralidharan 599a723dd1 call designated initializer using self 2019-01-07 15:14:03 -08:00
Srinath Tupil Muralidharan 7f37428426 support attributedText in ORKMultipleValuePickerAnswerFormat 2019-01-07 13:59:50 -08:00
Srinath Tupil Muralidharan 630a431299 support attributedText in textScaleAnswerFormat 2019-01-07 13:22:17 -08:00
Srinath Tupil Muralidharan ab081e28e1 ensure that attributedText always overrides text 2019-01-07 12:18:30 -08:00
Tommy Lin 8b912b7d25 Add touch ability instruction art works 2019-01-04 19:02:04 +08:00
Tommy Lin 375e1380d7 Add instructions before every touch ability tasks 2019-01-03 18:05:42 +08:00
Tommy Lin fdd3d7c653 Modify scroll task design 2019-01-02 20:33:42 +08:00
Tommy Lin 18ea1236e2 Rename ORKTouchAbilityScrollStep 2019-01-02 16:34:30 +08:00
Tommy Lin 18842a0e64 Add target hint label to ORKTouchAbilityScrollContentView 2018-12-25 17:13:27 +08:00
Tommy Lin 7a3d0606d5 Reset gesture recognizer events after reset tracks 2018-12-25 15:43:52 +08:00
Tommy Lin 528186535c Rename -[ORKTouchAbilityContentView startTracking] to -[ORKTouchAbilityContentView startTrial]
And also  -[ORKTouchAbilityContentView stopTracking] to  -[ORKTouchAbilityContentView endTrial]
2018-12-25 15:26:08 +08:00
Tommy Lin bd4c1a1568 Add start date and end date to ORKTouchAbilityTrial 2018-12-25 15:20:41 +08:00
Tommy Lin 08382cf7a3 Override some touch ability model descriptions 2018-12-24 19:24:01 +08:00
Tommy Lin 1080e4f08d Add ORKTouchAbilityTaskOption 2018-12-24 17:10:37 +08:00
Tommy Lin 81c9fd83e3 Refine scroll trial view 2018-12-24 16:51:13 +08:00
Tommy Lin f65b22993b Update some constraints 2018-12-24 16:37:11 +08:00
Tommy Lin e9059ee42c Add touch ability scroll ability models, views and view controllers 2018-12-22 16:48:52 +08:00
Tommy Lin f4feaffe19 Rename some protocol name and methods 2018-12-21 17:16:23 +08:00
Tommy Lin 176da46dd4 Replace auto layout codes using anchor API with traditional API 2018-12-21 17:07:26 +08:00
Tommy Lin e4a023713d Refine touch ability arrow view 2018-12-20 18:16:38 +08:00
Tommy Lin 7cfc964143 Refine pinch and rotation content view and step view controller 2018-12-20 17:40:27 +08:00
Tommy Lin b4b363cac6 Refine swipe content view and tap step view controller 2018-12-20 17:10:00 +08:00
Tommy Lin 3deaee1ef0 Refine long press content view and tap step view controller 2018-12-20 16:39:55 +08:00
Tommy Lin 330587f6f8 Refine tap content view and tap step view controller 2018-12-20 16:28:22 +08:00
Tommy Lin 7615ed631d Refine ORKTouchAbilityCustomView 2018-12-20 15:46:27 +08:00
Tommy Lin 567c1802ba Add rotation task models, views and controller 2018-12-19 17:50:21 +08:00
Tommy Lin 400ba05d8e Add pinch task models, views and controller 2018-12-17 14:36:34 +08:00
Srinath Tupil Muralidharan 3cd8cd7661 display attributed strings in picker view 2018-12-13 21:10:53 -08:00
Srinath Tupil Muralidharan 612b411dc2 adding support to provide attributed string for both primary text and detail text in ORKAnswerFormat 2018-12-13 21:10:20 -08:00
Srinath Tupil Muralidharan cd216ab1c0 setting attributed text to nil seems to override other UILabel properties, adding checks before assigning 2018-12-13 16:21:53 -08:00
Srinath Tupil Muralidharan 610d30fb0a adding support for setting attributed string to the primary text label of ORKAnswerFormat 2018-12-12 18:34:34 -08:00
Tommy Lin f81825bb78 Add touch ability swipe task 2018-12-05 18:28:32 +08:00
Tommy Lin eb5c34b35a Complete touch ability long press controller and models 2018-12-05 13:42:17 +08:00
Tommy Lin 7ea163bc14 Add property "success" to ORKTouchAbilityTapTrial 2018-12-05 13:21:38 +08:00
srinathtm-apple acc45033b7 Merge pull request #1222 from srinathtm-apple/CleanupPR1088
Cleanup for knee and shoulder range of motion
2018-12-04 17:33:47 -08:00
Srinath Tupil Muralidharan aa5bfa8142 pointing to the renamed assets for the task 2018-12-04 17:22:27 -08:00
srinathtm-apple 070950b31a Merge pull request #1088 from davwillev/master
Changes to angle calculations in Range of Motion active tasks
2018-12-04 15:16:52 -08:00
srinathtm-apple 981c1af7a8 Update ORKRangeOfMotionResult.h
adding new line spacing..
2018-12-04 13:55:36 -08:00
Tommy Lin 2cbf211613 Refine touch ability touch tracker 2018-12-04 15:33:06 +08:00
Tommy Lin 77de9ddf05 Refine touch ability tap step view controller 2018-12-04 14:58:30 +08:00
srinathtm-apple 1dfca472e2 Merge pull request #1213 from stevebaranski/issue/contributing
Correct link to ResearchKit forum in contributing guidelines
2018-12-03 13:15:23 -08:00
Tommy Lin 4b9dc94927 Add touch ability long press step, view, controller and result 2018-11-30 17:15:57 +08:00
Tommy Lin f3eec95c98 Refine tap task behavior 2018-11-30 16:10:00 +08:00
Tommy Lin 005b4b744f Refine ORKTouchAbility models 2018-11-29 17:16:51 +08:00
Tommy Lin 002939a0ec Refine property attributes 2018-11-28 17:08:00 +08:00
Brian Ganninger 35e5d5aa95 [code cleanup] Review mismatched nil returns, part II (issue #1214) 2018-11-27 22:18:03 -08:00
Brian Ganninger 547e1b5cd2 [code cleanup] Use local variable across autorelease pools (issue #1214) 2018-11-27 22:05:43 -08:00
Brian Ganninger 421e90615f [code cleanup] Resolve semantic issue with navigation buttons (issue #1214) 2018-11-27 20:40:23 -08:00
Tommy Lin 3538a50e55 Implement tap task trial points generator 2018-11-27 18:14:53 +08:00
Brian Ganninger 30a758e2b7 Tweak build settings a bit (issue #1214)
// implicit self retain in blocks, priority inversion are larger issues to tackle
2018-11-27 01:09:52 -08:00
Brian Ganninger 9ef1876c45 [code cleanup] Review mismatched nil returns (issue #1214) 2018-11-27 00:52:51 -08:00
Tommy Lin b06ffbb44e Refine code structure 2018-11-27 16:46:16 +08:00
Brian Ganninger 60076032b9 [code cleanup] Use defined enum values (issue #1214) 2018-11-25 19:12:15 -08:00
Brian Ganninger c2b664f3b8 [code cleanup] Add missing localization comments (issue #1214) 2018-11-25 13:08:51 -08:00
Brian Ganninger fc61990e03 [code cleanup] Address missing prototypes for functions (issue #1214) 2018-11-24 21:39:47 -08:00
Brian Ganninger ca81287311 [code cleanup] Resolve shadow declarations (issue #1214) 2018-11-24 19:33:28 -08:00
Brian Ganninger db995e3b35 [code cleanup] Fix dead code stores (issue #1214) 2018-11-24 17:46:16 -08:00
Brian Ganninger 1a902eefdd [code cleanup] Security fixes for random, loop counter (issue #1214) 2018-11-24 17:32:31 -08:00
Brian Ganninger 5c3fe6eaef [code cleanup] Fix unknown pragmas (issue #1214) 2018-11-24 17:27:06 -08:00
Brian Ganninger a033e1cc5e [code cleanup] Remove extraneous semicolons (issue #1214) 2018-11-24 15:42:54 -08:00
Brian Ganninger fbb7892ea6 [code cleanup] Add missing newlines (issue #1214) 2018-11-24 15:36:33 -08:00
Brian Ganninger 336096f680 [code cleanup] Fix memory management/mutability mismatch (issue #1214) 2018-11-24 01:13:05 -08:00
Brian Ganninger f3929e0e12 [code cleanup] Resolve generics type mismatch (issue #1214) 2018-11-24 01:10:20 -08:00
Brian Ganninger 3736cf573e [code cleanup] Resolve missing super calls (issue #1214) 2018-11-24 00:55:43 -08:00
Brian Ganninger 336ab0e21b Enable a swath of new compiler and analyzer flags and shallow analyze on build 2018-11-24 00:49:40 -08:00
Brian Ganninger 6459a4a5a0 Merge pull request #1 from ResearchKit/master
Merge ORK-latest
2018-11-21 15:38:04 -08:00
Tommy Lin d04c38b4a0 Add target view in ORKTouchAbilityTapContentView 2018-11-20 18:27:48 +08:00
stevebaranski 535cec7f08 Correct link to ResearchKit forum in contributing guidelines 2018-11-19 10:21:41 -08:00
Tommy Lin 843895e1e4 Add ORKTouchAbilityCustomView 2018-11-13 18:30:54 +08:00
Tommy Lin fe29159d14 Add ORKTouchAbilityTouchTracker 2018-11-13 16:31:39 +08:00
srinathtm-apple 7c883966d0 Merge pull request #1200 from bgannin/chartFontCustomization
Chart font customization
2018-11-10 13:12:26 -08:00
srinathtm-apple 332c8299fa Merge pull request #1210 from srinathtm-apple/runUnitTests
run unit tests on iPhone X iOS12.0 simulator
2018-11-08 17:27:42 -08:00
Srinath Tupil Muralidharan 120612cae0 run unit tests on iPhone X iOS12.0 simulator 2018-11-08 17:12:38 -08:00
srinathtm-apple dbb525a469 Merge pull request #1188 from CareEvolution/field-content-types
Add support for textContentType from UITextInputTraits to ORKAnswerFormat
2018-11-08 13:32:51 -08:00
Tommy Lin 4dea6d8a7b Make ORKTouchAbilityTouch, ORKTouchAbilityTrack, ORKTouchAbilityGestureRecognizer and ORKTouchAbilityTrial confirm to NSCopying and NSSecureCoding 2018-11-08 15:52:22 +08:00
srinathtm-apple c57d3a1e1f Merge pull request #1107 from rsanchezsaez/rsanchezsaez/optional-pie-legend
[ORKPieChartView] Allow skipping segment legend labels
2018-11-07 14:30:01 -08:00
Tommy Lin 77a15aa734 Add ORKTouchAbilityTrial class 2018-11-07 16:27:57 +08:00
srinathtm-apple aa482452e0 Merge pull request #1209 from srinathtm-apple/FixForIssue1205
fix for issue #1205
2018-11-06 21:09:17 -08:00
Srinath Tupil Muralidharan f1f322d442 fix for issue #1205 2018-11-06 20:56:55 -08:00
Tommy Lin 8191a977b7 Add basic touch ability data models, views and view controller 2018-11-06 15:39:16 +08:00
srinathtm-apple 54c3333b81 Merge pull request #1204 from srinathtm-apple/badgeForBuildStatus
adding badge for CI build status
2018-10-31 13:12:40 -07:00
Srinath Tupil Muralidharan ad755bb222 adding badge for CI build status 2018-10-31 13:06:52 -07:00
srinathtm-apple 920127d096 Merge pull request #1199 from susom/replace_deprecated_uiwebview
Replace deprecated UIWebView
2018-10-30 17:19:25 -07:00
srinathtm-apple 2696f2377b Merge pull request #1192 from bgannin/documentationTweak
Documentation tweaks
2018-10-30 16:52:02 -07:00
srinathtm-apple 81fdbdac57 Merge pull request #1187 from bgannin/testFixes
ORKTest unit tests fail
2018-10-30 16:44:17 -07:00
Brian Ganninger dd04625562 Updates per PR review 2018-10-30 16:23:46 -07:00
srinathtm-apple 98e8c8e09a Merge pull request #1185 from tobiasjungnickel/ScreenType_iPhone_MAX_XR
ScreenType iPhone Max & XR
2018-10-29 20:20:02 -07:00
srinathtm-apple 2da27dddd6 Merge pull request #1196 from xldrx/patch-1
Fixing a typo/bug in TaskList.
2018-10-29 20:14:28 -07:00
srinathtm-apple e40be2e5f6 Merge pull request #1201 from srinathtm-apple/setupTravisCI
Setup travis ci
2018-10-29 19:52:11 -07:00
Srinath Tupil Muralidharan 79228e8ab7 switching to ResearchKit unit tests 2018-10-29 18:07:37 -07:00
Srinath Tupil Muralidharan 161149d2df adding .travis.yml file 2018-10-29 17:39:03 -07:00
Brian Ganninger a38561bfed Add font changes for all chart types to ORKTest (issue #1158) 2018-10-27 16:55:40 -07:00
Paweł Kowalczyk 74f44435ef Replace deprecated UIWebView in ORKConsentReviewController 2018-10-26 12:56:12 +02:00
Paweł Kowalczyk 66a754d24f Replace deprecated UIWebView in ORKConsentLearnMoreViewController 2018-10-26 12:54:03 +02:00
Paweł Kowalczyk 258e2623f3 Replace deprecated UIWebView in ORKHTMLPDFWriter 2018-10-26 12:51:22 +02:00
Paweł Kowalczyk 7043316b90 Fix unit tests related to Two Finger Tapping Interval Task 2018-10-26 12:51:08 +02:00
Paweł Kowalczyk fcb980beb8 Fix unit tests related to adding new css style to handle signamture image 2018-10-26 12:46:19 +02:00
Brian Ganninger d186e5c6df Expose graph chart view fonts (issue #1158) 2018-10-24 20:18:00 -07:00
Brian Ganninger 5822caa980 Expose pie chart view fonts (issue #1158) 2018-10-23 22:18:19 -07:00
Sayed Hadi Hashemi bb55a603db Fixing a typo/bug in TaskList.
passcodeTask identifier has to be ".passcodeTask" not ".passcodeStep".
2018-10-21 15:47:01 -05:00
Brian Ganninger a75938f6bb Add flair (badge) for DVCS to README for clarity 2018-10-21 12:09:28 -07:00
Brian Ganninger 23ba6e97a8 Add badge flair for project attributes/status on README 2018-10-19 18:16:07 -07:00
Brian Ganninger 053625a0a1 Add prerequisites to the dependency management doc (fixes issue #1184) 2018-10-19 17:41:29 -07:00
Tobias Jungnickel 682cd83213 adding XS term to screen types for XSMax model 2018-10-18 10:30:04 +02:00
Eric DeLabar 55a2833c6e Address code review comments by @srinathtm-apple 2018-10-17 10:15:15 -04:00
Brian Ganninger c6e2df2a6e Additional cleanup 2018-10-16 23:41:46 -07:00
Brian Ganninger a3b6732406 Remove spurious initializer change; silence surfaced serialization failure properly (PR feedback) 2018-10-16 23:35:58 -07:00
Eric DeLabar d2fade561b Add support for textContentType from UITextInputTraits
* Add support for passwordFormat to support automatic secure passwords
2018-10-16 09:45:43 -04:00
Brian Ganninger ab6600eaf2 Pre-PR cleanup 2018-10-13 18:12:31 -07:00
Brian Ganninger 815f5bf60a Ignore shoulder range of motion step for now as it fails deserialization (issue #1151) 2018-10-13 13:43:28 -07:00
Brian Ganninger e9ecae2720 Minor code tweaks 2018-10-12 23:36:28 -07:00
Tobias Jungnickel c9f49d9f18 adding iPhone Max 2018-10-11 10:06:08 +02:00
srinathtm-apple 73faa2e59f Merge pull request #1182 from MacroYau/feature/cancelable-task
Allow task view controller to be canceled directly
2018-10-11 13:28:33 +05:30
srinathtm-apple 70889a0671 Merge pull request #1181 from bgannin/scaleHideValueLabel
Add option to hide selected value in slider scale (#657)
2018-10-11 13:27:55 +05:30
Brian Ganninger 26101d0068 Fix remaining issues for -testSecureCoding (issue #1151) 2018-10-10 22:23:55 -07:00
Brian Ganninger 340c5abdc0 Minor cleanup 2018-10-09 02:49:16 -07:00
Brian Ganninger 0c121f283b Properly init test data for clinical recorder configuration (issue #1151) 2018-10-08 20:53:50 -07:00
Brian Ganninger f50587eaf4 Add missing nullability keywords 2018-10-08 19:10:06 -07:00
Brian Ganninger fad50b20e0 Fix precision of equality check in speech recognition step (issue #1151) 2018-10-08 19:08:24 -07:00
Brian Ganninger 99be8240b0 Fix initialization and serialization issues for numeric answer format (issue #1151) 2018-10-08 18:14:10 -07:00
Brian Ganninger b6028a9eef Update known exceptions for serialization checking (issue #1151) 2018-10-08 18:09:32 -07:00
Brian Ganninger fcad24f94b Update known exceptions for serialization checking (issue #1151) 2018-10-07 23:31:05 -07:00
Brian Ganninger 211aa5a118 Fix serialization equality test failures (issue #1151) 2018-10-07 22:43:19 -07:00
Brian Ganninger 53842c3231 Fix addResult test failures (issue #1151) 2018-10-07 18:38:05 -07:00
Brian Ganninger b6ab7414fd Fix comment misspelling 2018-10-07 12:53:42 -07:00
Brian Ganninger e56ac6b2e9 Fix test failure by marking phone number related properties not serialized (issue #1151) 2018-10-07 12:52:08 -07:00
Brian Ganninger 0da343ea6f Fix serialization test failure for dB HL tone audiometry onboarding step (issue #1151) 2018-10-07 12:42:24 -07:00
Brian Ganninger 1fc475e826 Fix serialization test failure for Amsler grid result (issue #1151) 2018-10-07 12:29:25 -07:00
Brian Ganninger dc0890233f Rename variable for spelling and clarity 2018-10-07 12:17:37 -07:00
Brian Ganninger 15a8deba02 Fix serialization test failure for health clinical recorder configuration [iOS 12+ only] (issue #1151) 2018-10-07 12:16:28 -07:00
Brian Ganninger ac27b6d8fa Fix serialization test failure for Amsler grid step (issue #1151)
// also align whitespace for several entries
2018-10-06 20:31:30 -07:00
Brian Ganninger 8625fa19d6 Fix serialization test failure for speech recognition step (issue #1151) 2018-10-06 20:18:56 -07:00
Brian Ganninger 6e0a3a5c4a Fix serialization test failure for environment SPL meter result (issue #1151) 2018-10-06 19:17:56 -07:00
Brian Ganninger 388a20a79b Fix serialization test failure for streaming audio recorder configuration (issue #1151) 2018-10-06 16:48:55 -07:00
Brian Ganninger ef0c8d0495 Fix serialization test failure for Environment SPL Meter step (issue #1151) 2018-10-06 13:51:31 -07:00
Brian Ganninger 97fb686ad4 Fix serialization test failure for Speech in Noise step (issue #1151) 2018-10-06 13:50:44 -07:00
Brian Ganninger 2c0a6d7761 Fix serialization test failure for PDF Viewer step (issue #1151) 2018-10-06 13:49:57 -07:00
Brian Ganninger 0070d3ca04 Fix serialization test failure for tone audiometry step (issue #1151) 2018-10-05 23:43:48 -07:00
Macro Yau 6d0c331aba Fix typo 2018-10-05 14:30:21 +08:00
Macro Yau 0d81a9c696 Rename cancelable to discardable 2018-10-05 14:23:49 +08:00
srinathtm-apple 1e7d2c2460 Merge pull request #1179 from MacroYau/feature/custom-minute-interval
Allow custom minute interval setting for UIDatePicker with date and time, and time of day answer formats
2018-10-05 11:13:03 +05:30
Brian Ganninger 3197a62a3a Update TaskFactory+QuestionSteps.m
Fix incorrect comment
2018-10-04 14:57:26 -07:00
Brian Ganninger 4cdffbd061 Consistency cleanup from PR feedback. 2018-10-04 12:46:31 -07:00
Brian Ganninger fad570f6e9 Explicitly initialize per PR feedback 2018-10-04 10:26:10 -07:00
Macro Yau 05e4011f2a Remove unused getters 2018-09-29 18:43:49 +08:00
Macro Yau b28785d160 Allow task view controller to be cancelable regardless of step type 2018-09-28 19:15:13 +08:00
Brian Ganninger 2b25f66086 Remove hideSelectedValue from serialization test after initializer changes 2018-09-27 23:20:02 -07:00
Brian Ganninger 54f7a9b53a Update initializer 2018-09-27 23:13:05 -07:00
Brian Ganninger 0d6bd0e3c4 Whitespace tweak again 2018-09-27 23:11:29 -07:00
Brian Ganninger ed3d787972 Flipped parameters accidentally 2018-09-27 23:10:39 -07:00
Brian Ganninger 834e992bf0 Whitespace fix take 2 2018-09-27 23:09:27 -07:00
Brian Ganninger 4a894d2b3c Whitespace fix 2018-09-27 23:07:32 -07:00
Brian Ganninger 6848c067d0 Remove copyright attribution 2018-09-27 23:04:16 -07:00
Brian Ganninger ff3fe765f1 Remove hideSelectedValue from initializers, utilize only via settable property per PR review. 2018-09-27 23:01:24 -07:00
Macro Yau ecc6d2b6f9 Remove minute interval parameter from constructors 2018-09-27 16:45:50 +08:00
Brian Ganninger 8f633dcb43 Add copyright attribution per guidelines 2018-09-26 19:25:16 -07:00
Brian Ganninger a62b853500 Fix whitespace to match coding guidelines for project 2018-09-26 19:20:36 -07:00
Brian Ganninger 0a12a96af5 Add an extra step for testing text choice scale with no selected value; update serialization tests 2018-09-26 19:13:01 -07:00
Brian Ganninger 62bba0b6c9 Fix whitespace to match coding guidelines for project 2018-09-26 18:51:11 -07:00
Brian Ganninger b7c6772266 Add copyright attribution per guidelines 2018-09-25 22:56:27 -07:00
Brian Ganninger 224ce04a41 Redo initializers and Scale section of OKRTest to include hiding the selected value for all variants (#657) 2018-09-25 22:46:48 -07:00
Macro Yau 05b6f308e3 Allow custom minute interval setting for UIDatePicker with date and time, and time of day answer formats 2018-09-25 14:06:59 +08:00
Brian Ganninger 3f96750424 Port changes from pull request #446 to latest master 2018-09-24 20:33:23 -07:00
srinathtm-apple e7e501c087 Merge pull request #1175 from king7532/master
NSHealthShareUsageDescription must be longer than one word
2018-09-24 20:18:37 -06:00
Benjamin King 3aeb8dd9f9 NSHealthShareUsageDescription must be longer than one word, otherwise HealthKit will throw a runtime exception during the on-boarding or profile view controller 2018-09-19 11:05:31 -04:00
David Evans d30331a403 Slight change to RoM instructions
Made a slight improvement to the wording of the knee and shoulder range of motion tasks, in line with the new 'maximum' and 'minimum' angle calculations, following feedback after testing with volunteers.
2018-09-19 10:03:46 +01:00
David Evans 1726f5353d Trying to resolve file conflict by updating to latest RK version 2018-09-05 09:32:13 +01:00
Srinath Tupil Muralidharan b46a5f4d83 Updating podspec, readme and project settings for ResearchKit 2.0 stable release 2018-09-04 19:30:52 -07:00
Srinath Tupil Muralidharan e1d47c2882 Adding remaining audio files for Speech in Noise to Git LFS 2018-09-04 19:21:11 -07:00
Srinath Tupil Muralidharan dbc21a1c2a Changing lfsconfig to recursively track the LFS-files folder 2018-09-04 19:13:28 -07:00
Srinath Tupil Muralidharan f73645127c Adding proof of concept LFS file for speech in noise 2018-09-04 19:04:17 -07:00
Akshay 95425a81ae Stable Release 2.0 2018-09-04 16:58:27 -07:00
srinathtm-apple 8a44bceb99 Merge pull request #1170 from srinathtm-apple/FixForIssue1168
adding new css style class to handle signature image
2018-09-04 17:19:16 -06:00
Srinath Tupil Muralidharan 543fb892b1 adding new css style class to handle signature image 2018-09-04 16:17:01 -07:00
David Evans e3fad9e1d9 Final changes for angle calculations 2018-09-03 16:41:38 +01:00
David Evans 9f2e77d103 Updated version for consistency with latest RK version 2018-09-03 16:39:18 +01:00
David Evans 0478b552dc Made final changes to knee and shoulder angle calculations 2018-09-03 16:34:58 +01:00
srinathtm-apple 0598cbdbd3 Merge pull request #1167 from srinathtm-apple/FixForIssue1136
navigationFooterView should adopt app tint color
2018-08-28 23:27:29 -06:00
Srinath Tupil Muralidharan c1e6dc0a54 navigationFooterView should adopt app tint color 2018-08-28 17:44:32 -07:00
srinathtm-apple c4968de7d7 Merge pull request #1161 from overcyn/patch-1
Allow autoplay and inline media playback in ORKWebViewStep
2018-08-28 12:12:11 -06:00
srinathtm-apple f02d401737 Merge pull request #1162 from srinathtm-apple/FixForIssue1142
Fix for issue #1142
2018-08-28 12:08:20 -06:00
David Evans 19ee558b57 Adjusted for phone landscape orientation issue
Changed the 'range' result to the absolute difference between maximum and minimum angles, which deals with the problem of the phone being in opposite landscape orientations, and the device recording 'positive' or 'negative ' results accordingly
2018-08-22 12:08:21 +01:00
David Evans 8fde58535b Changed angle results calculations
This needed changes to allow for the negative direction of pitch during knee and shoulder RoM tasks. Counterintuitively, min and max values needed to be exchanged for these particular tasks
2018-08-22 11:49:17 +01:00
Srinath Tupil Muralidharan ec33ec5f8c minor change in import which was causing build failure 2018-08-20 12:42:19 -07:00
Srinath Tupil Muralidharan d23db60948 pass the fhir data object directly to the logger 2018-08-20 12:41:51 -07:00
Kevin Dang fd36ad5463 Update to use latest WKWebView api 2018-08-17 11:51:26 -07:00
Kevin Dang 06360f246d Allow autoplay and inline media playback in ORKWebViewStep 2018-08-16 14:47:39 -07:00
srinathtm-apple 7f1226e74a Merge pull request #1109 from rsanchezsaez/rsanchezsaez/xcode-9.3
[Misc] Fix Xcode 9.3 warnings and rename some methods
2018-08-15 10:46:22 -06:00
srinathtm-apple 0799ec32c9 Merge pull request #1155 from kasemset-apple/trail_making_dynamic_type
Improvements to Dynamic Type support in the Trail Making Test.
2018-08-08 16:09:07 -06:00
srinathtm-apple ae2333f2e4 Merge pull request #1156 from kasemset-apple/tapping_button_ax
Improve usability of tests that use ORKRoundTappingButton.
2018-08-08 16:08:44 -06:00
srinathtm-apple 6da6842adb Merge pull request #1157 from ysf199711/master
Update Consent Doc
2018-08-07 17:35:03 -06:00
srinathtm-apple a016834614 Merge pull request #1139 from joshavant/add-docset
Add docset
2018-08-07 17:33:44 -06:00
Sifan Ye 6d0e6e1931 Apply changes to old document 2018-08-08 02:37:55 +08:00
Sifan Ye 65c5ca082b Added suggested changes
Will update original consent doc
2018-08-08 02:25:01 +08:00
srinathtm-apple a8bbd7d4d8 Merge pull request #1135 from CareEvolution/consentMustScroll
Option to require scrolling to the bottom of ORKConsentReviewStep
2018-08-06 17:53:42 -06:00
Eric Schramm b5cdb5b7fe cond scrollView delegate, check if unscrollable
- minimize callbacks if not needed - make UIScrollViewDelegate only if needed
- if a short consent is used and no scrolling is needed on device, re-enable Agree button
2018-08-06 17:38:34 -05:00
srinathtm-apple 781c080033 Merge pull request #1153 from kasemset-apple/speech_recognition_dynamic_type
Improved Dynamic Type support for the Speech Recognition recording view.
2018-08-06 12:28:13 -06:00
srinathtm-apple cd8e0ebb00 Merge pull request #1152 from kasemset-apple/speech_recognition_transcript_ax
Accessibility fixes for the transcript view in the Speech Recognition task.
2018-08-06 12:27:56 -06:00
Sifan Ye b32c87a3b2 Merge pull request #1 from ResearchKit/master
Merge Updates
2018-08-03 12:21:38 +02:00
srinathtm-apple 9ea3d8bb09 Merge pull request #1150 from kasemset-apple/speech_recognition_waveform_axlabel
Make the waveform accessible so that low vision users are aware that it is present.
2018-08-02 12:38:23 -06:00
srinathtm-apple a1600c6e0b Merge branch 'master' into speech_recognition_waveform_axlabel 2018-08-02 12:37:01 -06:00
Sifan Ye ebc0eeef7d Update pdf code -> swift 2018-08-02 17:47:48 +02:00
Sifan Ye 020b21f261 consentShare -> swift 2018-08-02 17:42:51 +02:00
Sifan Ye 403ef4e6ee Oops, wrong code block 2018-08-02 17:39:45 +02:00
Sifan Ye 74d3f60562 Code block 4 -> swift 2018-08-02 17:37:22 +02:00
Sifan Ye bf3b66e6ff Code block 3 -> Swift 2018-08-02 17:30:12 +02:00
Sifan Ye 9265d45878 Code block 2 -> Swift 2018-08-02 17:22:53 +02:00
Sifan Ye f07c4fe7ff Correct some label typos 2018-08-02 17:11:48 +02:00
Sifan Ye 81e106dde0 First code block -> swift 2018-08-02 17:09:53 +02:00
Sifan Ye cb45004eb0 Init, prepare to replace objc with swift 2018-08-02 16:57:59 +02:00
Sifan Ye f683a494df Update more image formatting and add syntax highlighting 2018-08-02 16:56:31 +02:00
Sifan Ye f7e2e39e1c Update headers and image formats 2018-08-02 16:34:27 +02:00
Sifan Ye 6147283a63 Rename to InformedConsent-template-ObjC.markdown 2018-08-02 16:00:17 +02:00
David Evans c424ada8fd Adjusted 'finish' angle calculation in line with ORKRangeOfMotionStepViewController 2018-08-01 11:55:09 +01:00
Clare Kasemset 2a02e94987 Merge branch 'master' into tapping_button_ax 2018-08-01 17:04:14 +09:00
Clare Kasemset 2be7575a93 Improve usability of tests that use ORKRoundTappingButton.
- In the tone audiometry test, the user has a chance to determine the location of the buttons during the practice step. Once the test begins, the buttons become directly tappable.
- In the two finger tapping interval test, the user can also determine the location of the buttons first. Then on the first activation of either button, the buttons become directly tappable, but the tap is not registered yet.
- In the dBHL tone audiometry test, the user is given instructions about the button and it is directly tappable.
- In the trailmaking test, the user is given instructions about the buttons and they are directly tappable.
2018-08-01 17:01:11 +09:00
Ricardo Sanchez-Saez 326e44b055 [Project] Update to Xcode 9.4 recommended settings 2018-07-31 22:58:26 -07:00
David Evans ba58b4dbad Removed min and max +90.0 adjustment 2018-07-31 22:27:40 +01:00
David Evans 0ee66f6a26 Removed +90.0 adjustment from min and max results 2018-07-31 22:26:34 +01:00
David Evans 261ef01f93 Adjusting maximum and minimum results by +90.0 2018-07-31 21:57:59 +01:00
David Evans f1083cf096 Adjusted minimum and mximum results by +90.0 2018-07-31 21:26:10 +01:00
David Evans 4b5a587eb8 Removed 'fabs' from rangeOfMotionMoreThan180Degrees function 2018-07-31 20:40:02 +01:00
David Evans 4bdd148b53 Removed 'phonesoundwaves' image 2018-07-31 11:42:27 +01:00
David Evans 6bad43fb9f Delete phonesoundwaves_inverted@3x.png 2018-07-31 11:36:29 +01:00
David Evans 34040ac1cd Delete phonesoundwaves_inverted@2x~ipad.png 2018-07-31 11:36:19 +01:00
David Evans 4a58bff1fd Delete phonesoundwaves_inverted@2x.png 2018-07-31 11:36:09 +01:00
David Evans d8391522db Delete Contents.json 2018-07-31 11:34:34 +01:00
Clare Kasemset 4ce1635da5 Improvements to Dynamic Type support in the Trail Making Test.
- Make sure the text doesn't grow outside the bubbles
- Make sure the "Starting text in" text doesn't get truncated
- Scale the timer and error text
2018-07-31 17:44:31 +09:00
Ricardo Sanchez-Saez 26c7884002 [Project] Make ORKHTMLPDFPageRenderer.h private again 2018-07-31 00:59:51 -07:00
Ricardo Sanchez-Saez 3bc160c5b2 [Tests] Fix ResearchKit unit tests 2018-07-31 00:43:51 -07:00
Clare Kasemset 7e21d2486d Improved Dynamic Type support for the Speech Recognition recording view.
- The phrase to be recorded now scales with dynamic type.
- The Start Recording button expands if needed to fill the available width.
2018-07-31 16:39:00 +09:00
srinathtm-apple 1921a72f26 Merge pull request #1149 from kasemset-apple/amsler_grid_direct_touch_ax
Make the Amsler Grid a direct touch area, so the task can be completed easily by low vision users using VoiceOver.
2018-07-31 01:00:14 -06:00
srinathtm-apple ce93665ba2 Merge pull request #1148 from kasemset-apple/speech_in_noise_button_axtraits
Use UIAccessibilityTraitStartsMediaSession on the Play Audio button, so that VoiceOver doesn't speak the button title when you activate it.
2018-07-31 00:59:56 -06:00
srinathtm-apple e7f72ffde2 Merge pull request #1147 from kasemset-apple/speech_recognition_button_axtraits
Use UIAccessibilityTraitStartsMediaSession on the Start Recording button, so that VoiceOver doesn't speak the button title when you activate it.
2018-07-31 00:59:19 -06:00
Clare Kasemset 94a4e8b261 Accessibility fixes for the transcript view in the Speech Recognition task.
- Expose only one element for the text view.
- Expose a custom action to allow dismissing the keyboard.

Resolves rdar://problem/42294608. Tested on iPhone 7 with VoiceOver and Switch Control.
2018-07-31 15:29:51 +09:00
Ricardo Sanchez-Saez f605a10dfb Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez/xcode-9.3 2018-07-30 22:27:33 -07:00
Ricardo Sanchez-Saez aa2fd02c67 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez/optional-pie-legend 2018-07-30 22:21:09 -07:00
David Evans acf5f194f0 Updated calculation for minimum angle 2018-07-30 23:19:46 +01:00
srinathtm-apple 69e2aeb202 Merge pull request #1129 from karimhm/master
Add calls to remove self from the notification center observers after deallocation.
2018-07-30 13:55:37 -06:00
srinathtm-apple ebc948a8cc Merge pull request #1132 from ysf199711/master
Update Chart & Graph Doc
2018-07-30 13:55:02 -06:00
Clare Kasemset 584302cd2f Also add a hint so users know they can simply double tap to end recording. 2018-07-30 13:54:01 +09:00
Clare Kasemset b4bfe14641 Make the waveform accessible so that low vision users are aware that it is present.
Resolves rdar://problem/42294396. Tested on iPhone 7.
2018-07-30 13:48:21 +09:00
Clare Kasemset 57ca376732 Make the Amsler Grid a direct touch area, so the task can be completed easily by low vision users using VoiceOver.
Also give it an appropriate label and hint.

Resolves rdar://problem/42293953. Tested on iPhone 7.
2018-07-30 13:35:25 +09:00
Clare Kasemset bb30966458 Use UIAccessibilityTraitStartsMediaSession on the Play Audio button, so that VoiceOver doesn't speak the button title when you activate it.
Resolves rdar://problem/42294815. Tested on iPhone 7.
2018-07-30 12:53:09 +09:00
srinathtm-apple a40b67f458 Merge pull request #1144 from conorhughes-apple/completion_check_axlabel
Use fixed accessibility label for the completion view.
2018-07-29 20:49:50 -06:00
srinathtm-apple d0897d7166 Merge pull request #1143 from conorhughes-apple/pdf_button_axlabels
Add accessibility labels to PDF Viewer action buttons.
2018-07-29 20:49:28 -06:00
Clare Kasemset 729fc5355a Use UIAccessibilityTraitStartsMediaSession on the Start Recording button, so that VoiceOver doesn't speak the button title when you activate it.
Resolves rdar://problem/42294456. Tested on iPhone 7.
2018-07-30 11:38:00 +09:00
David Evans b83684fac9 Update ResearchKit.strings
Updated instructions for range of motion tasks
2018-07-27 08:50:01 +01:00
David Evans 6ea0e4d248 Update ORKRangeOfMotionStepViewController.m 2018-07-26 23:06:12 +01:00
David Evans f730ed5a00 Update ORKRangeOfMotionStepViewController.m 2018-07-26 23:04:35 +01:00
David Evans 30e5a09c0c Update ORKRangeOfMotionStepViewController.m 2018-07-26 23:03:51 +01:00
David Evans 98e2ae73e4 Add files via upload 2018-07-26 22:38:12 +01:00
David Evans 100f744827 Add files via upload 2018-07-26 22:03:30 +01:00
David Evans 9ea558d233 Delete shoulder_flexed@3x.png 2018-07-26 21:57:58 +01:00
David Evans d3ceaabce0 Delete shoulder_flexed@2x~ipad.png 2018-07-26 21:57:48 +01:00
David Evans cf62288080 Delete shoulder_flexed@2x.png 2018-07-26 21:57:39 +01:00
David Evans a8e541a462 Delete Contents.json 2018-07-26 21:57:29 +01:00
David Evans 3c29db9917 Delete shoulder_extended@3x.png 2018-07-26 21:57:06 +01:00
David Evans 2b682cd197 Delete shoulder_extended@2x~ipad.png 2018-07-26 21:56:57 +01:00
David Evans cf753bea67 Delete shoulder_extended@2x.png 2018-07-26 21:56:48 +01:00
David Evans a4e1d13bad Delete Contents.json 2018-07-26 21:56:37 +01:00
David Evans 268af9b05d Delete shoulder_extended@3x.png 2018-07-26 21:56:19 +01:00
David Evans 9b47a271a4 Delete shoulder_extended@2x~ipad.png 2018-07-26 21:56:10 +01:00
David Evans 8608143e40 Delete shoulder_extended@2x.png 2018-07-26 21:55:59 +01:00
David Evans 01534209ac Delete Contents.json 2018-07-26 21:55:51 +01:00
David Evans ce75fc84bb Delete knee_flexed@3x.png 2018-07-26 21:55:29 +01:00
David Evans 4f1b8e1b89 Delete knee_flexed@2x~ipad.png 2018-07-26 21:55:20 +01:00
David Evans bb6be3bde1 Delete knee_flexed@2x.png 2018-07-26 21:55:11 +01:00
David Evans 52046a60bc Delete Contents.json 2018-07-26 21:55:02 +01:00
David Evans aba6fb5889 Delete knee_flexed@3x.png 2018-07-26 21:54:47 +01:00
David Evans 239ad2d8c9 Delete knee_flexed@2x~ipad.png 2018-07-26 21:54:37 +01:00
David Evans c220e6dfbd Delete knee_flexed@2x.png 2018-07-26 21:54:28 +01:00
David Evans 5d0cfbf9de Delete Contents.json 2018-07-26 21:54:19 +01:00
David Evans 644a563d20 Delete knee_extended@3x.png 2018-07-26 21:54:03 +01:00
David Evans c49ff60d73 Delete knee_extended@2x~ipad.png 2018-07-26 21:53:54 +01:00
David Evans 892713bec4 Delete knee_extended@2x.png 2018-07-26 21:53:45 +01:00
David Evans 60ca971d8e Delete Contents.json 2018-07-26 21:53:34 +01:00
David Evans e8f695ee32 Delete knee_extended@3x.png 2018-07-26 21:53:17 +01:00
David Evans 7941f76033 Delete knee_extended@2x~ipad.png 2018-07-26 21:53:01 +01:00
David Evans f871fafed6 Delete Contents.json 2018-07-26 21:52:51 +01:00
David Evans fbd02ffc59 Delete knee_extended@2x.png 2018-07-26 21:52:41 +01:00
David Evans 371c729a48 Delete shoulder_flexed@3x.png 2018-07-26 21:51:36 +01:00
David Evans 9f9cbd9fee Delete Contents.json 2018-07-26 21:51:21 +01:00
David Evans 1341070411 Delete shoulder_flexed@2x~ipad.png 2018-07-26 21:51:08 +01:00
David Evans ed26df05ae Delete shoulder_flexed@2x.png 2018-07-26 21:50:58 +01:00
David Evans 6583215cda Add files via upload
Added new results to range of motion tasks, and renamed flexed and extended
2018-07-26 21:41:54 +01:00
David Evans c77823dfa8 Add files via upload
Added a new image (phonesoundwaves_inverted) to range of motion tasks.
Added additional spoken instruction to 'tap anywhere' stage in range of motion tasks.
2018-07-26 21:36:39 +01:00
David Evans ec62232d9f Add files via upload 2018-07-26 21:28:45 +01:00
David Evans a54a266335 Add files via upload 2018-07-26 21:27:29 +01:00
David Evans 734e85ead6 Add files via upload
Added new results
2018-07-26 21:24:04 +01:00
David Evans 5182776e1f Add files via upload 2018-07-26 21:17:44 +01:00
David Evans 57f896b86f Add files via upload 2018-07-26 21:14:56 +01:00
David Evans abea94060e Update ORKRangeOfMotionStepViewController.m 2018-07-26 17:31:26 +01:00
David Evans 8a21932d62 Update ORKRangeOfMotionStepViewController.m 2018-07-26 17:30:48 +01:00
David Evans 07469cf2c1 Update ORKRangeOfMotionStepViewController.m 2018-07-26 17:28:43 +01:00
David Evans b684c9f2f8 Update ORKRangeOfMotionStepViewController.m 2018-07-26 17:27:56 +01:00
Ricardo Sanchez-Saez d58ac3982c [ORKTowerOfHanoiStep] Fix warning by removing unallowed init 2018-07-25 23:36:20 -07:00
Conor Hughes fbdca00cf2 Use fixed accessibility label for the completion view.
The completion view looks like it's now just always a check in a blue
circle. Update the label to a fixed string. This avoids interpolating
nil, which was happening because captionLabel is not visible here (and
as such moving focus to it with a screen change is also inappropriate).

Resolves rdar://problem/42294298. Tested on iPhone 8.
2018-07-24 19:52:18 -07:00
Conor Hughes 49677ea0f8 Add accessibility labels to PDF Viewer action buttons.
Resolves rdar://problem/42255725. Tested on iPhone 8.
2018-07-24 19:17:57 -07:00
Josh Avant a00a237c29 Add docset 2018-07-23 19:30:47 -05:00
Shannon Young caed724ce2 Merge pull request #1137 from tobiasjungnickel/ScreenType_iPad_10_5
ScreenType for iPad 10.5
2018-07-23 09:08:20 -07:00
Tobias Jungnickel cbd1ccb13d adding iPad 10.5 2018-07-21 12:12:36 +02:00
Eric Schramm fa23b2a841 reverted back to original initializer 2018-07-18 13:38:03 -05:00
Eric Schramm d853c54935 adjusted for backwards compatibility
- restored initial initializer as a convenience initializer
- fixed documentation text to address new parameter
2018-07-17 15:30:07 -05:00
Eric Schramm 8c0236e33a implement requires scroll to bottom to agree 2018-07-17 07:44:47 -05:00
srinathtm-apple ac18d816ee Merge pull request #1134 from anaglik/cocoapods-fix
Fixed position of ORK_CLASS_AVAILABLE
2018-07-13 16:34:30 -06:00
Andrzej Naglik 143184f792 Fixed position of ORK_CLASS_AVAILABLE. 2018-07-13 16:38:41 +02:00
Sifan Ye 6beb7bfbf1 Comment indentation 2018-07-11 01:07:35 +02:00
Sifan Ye b2707702f1 Indentation 2018-07-11 01:06:52 +02:00
Sifan Ye 1e87138b9a Update syntax in code example 2018-07-11 01:06:09 +02:00
Sifan Ye 91c6e0e7da Added how to update a chart graph 2018-07-11 01:00:06 +02:00
Sifan Ye 5c6e8662c5 Remove Fig Captions
where the line above the figure is clear enough to explain
2018-07-11 00:46:25 +02:00
Sifan Ye 25444b68fd Update ChartsAndGraphs-template.markdown 2018-07-11 00:41:44 +02:00
Sifan Ye d9f2e1171e Update ChartsAndGraphs-template.markdown 2018-07-11 00:41:19 +02:00
Karim H 101e792254 Add calls to remove self from the notification center observers after deallocation. 2018-07-08 20:58:25 +01:00
Akshay 266b9f1c71 updating ResearchKit 2.0 Release notes 2018-06-04 16:20:42 -07:00
Akshay dcae4e5775 adding ResearchKit 2.0 Release notes 2018-06-04 16:17:31 -07:00
Akshay edc9f445ab ResearchKit 2.0 2018-06-04 14:24:57 -07:00
Akshay a23a22f7bf Merging updates 2018-06-04 14:03:29 -07:00
srinathtm-apple aea49a7950 Merge pull request #1104 from srinathtm-apple/toneAudiometryCleanup
ORKToneAudiometry cleanup
2018-04-12 21:19:31 -07:00
Srinath Tupil Muralidharan e7a74e4951 updating property in predefined active tasks 2018-04-12 21:17:29 -07:00
Srinath Tupil Muralidharan 78ac8e03f2 renaming bool property per objc conventions 2018-04-12 21:09:28 -07:00
David Evans acc5ff2ba9 Update ORKRangeOfMotionStepViewController.m 2018-04-05 22:20:47 +01:00
David Evans 28d431c664 Update ORKRangeOfMotionStepViewController.m 2018-04-05 22:18:03 +01:00
Ricardo Sanchez-Saez 9f980e1144 [Tests] Fix ORKHTMLPDFWriter tests 2018-04-05 00:22:06 -07:00
Ricardo Sanchez-Saez 259446fc8c [Misc] Rename methods to be more Obj-C compliant 2018-04-04 23:56:40 -07:00
Ricardo Sanchez-Saez 95223d3011 [Projects] Update Swift version to 4.0 2018-04-04 23:31:34 -07:00
Ricardo Sanchez-Saez b61f071020 [Xcode 9.3] Update all projects to avoid warnings 2018-04-04 22:50:24 -07:00
Ricardo Sanchez-Saez be31c5784d [ORKHTMLPDFWriter] Fix nullability warning and rename method 2018-04-04 22:26:01 -07:00
Ricardo Sanchez-Saez 14f8d7ee6c [Xcode 9.3] Add new shared data file 2018-04-04 22:16:41 -07:00
Ricardo Sanchez-Saez b32f3db623 [ORKHTMLPDFPageRenderer] Fix warning 2018-04-04 22:16:22 -07:00
Ricardo Sanchez-Saez 19a3cd7074 [ORKPieChart] Fix delegate optionality 2018-04-04 22:01:37 -07:00
Ricardo Sanchez-Saez fe8f0a2234 [ORKPieChart] Reuse more code 2018-04-04 21:57:27 -07:00
srinathtm-apple 4b9c70ed73 Merge pull request #1103 from srinathtm-apple/FixForIssue1102
fix for issue #1102
2018-04-04 15:08:23 -07:00
Ricardo Sanchez-Saez 5592966027 [ORKPieChartView] Allow skipping segment legend labels 2018-04-04 03:20:43 -07:00
Srinath Tupil Muralidharan a9a0946c7e removing duplicate code 2018-04-03 20:18:44 -07:00
Srinath Tupil Muralidharan 8ff4db8384 fix for issue #1102 2018-04-03 01:33:24 -07:00
srinathtm-apple 4019c380eb Merge pull request #1093 from srinathtm-apple/FixForIssue1014
fix for #1014
2018-03-22 03:02:43 -07:00
Srinath Tupil Muralidharan fe7fc48901 fix for #1014 2018-03-19 13:53:43 -07:00
srinathtm-apple 7634eabd0a Merge pull request #1090 from srinathtm-apple/FixForIssue1022
fix for #1022
2018-03-16 15:51:58 -07:00
srinathtm-apple 3089a3bef5 Merge pull request #1075 from srinathtm-apple/timedWalkTaskCleanup
Timed walk task cleanup
2018-03-12 10:58:40 -07:00
Srinath Tupil Muralidharan cc3afe5102 include turnAroundTimeStep only for positive values 2018-03-12 10:50:22 -07:00
srinathtm-apple d75ba09918 Merge pull request #1092 from MacroYau/patch/passcode-input-overflow
Suppress ORKPasscodeTextField input overflow
2018-03-12 10:32:52 -07:00
Macro Yau 5376359c1f Suppress ORKPasscodeTextField input overflow 2018-03-10 15:11:16 +08:00
Srinath Tupil Muralidharan 9102800ced fix for #1022 2018-03-07 12:14:46 -08:00
David Evans 3133dd38df Merge pull request #1 from davwillev/davwillev-patch-1
Changes to angle calculations in Range of Motion active tasks
2018-03-05 13:28:28 +00:00
David Evans bd8ca78ed1 Add files via upload
Added quaternion to Euler definitions for Roll and Yaw.
Replaced the attitude.roll implementation for the device in landscape orientation with the quaternion for Roll.
Modified the calculation for 'flexed' and 'extended' angles.
2018-03-05 13:21:18 +00:00
srinathtm-apple 92fdcf46a6 Merge pull request #1065 from akshay-yadav-apple/defaultAnswerProperty
Adding default answer property to ORKTextAnswerFormat and ORKNumericA…
2018-03-04 22:42:57 -08:00
srinathtm-apple 2134d5fe3a Merge pull request #1081 from srinathtm-apple/consentSignatureFix
fix for #1071
2018-03-04 22:28:40 -08:00
srinathtm-apple 44a5e21fd0 Merge pull request #1080 from susom/Fix-For-1019-Toolbar
[ResearchKit] fix for issue #1019 - toolbar
2018-02-23 12:56:11 -08:00
Srinath Tupil Muralidharan 2aa0463673 fix consent name and date layout 2018-02-21 15:20:16 -08:00
Paweł Kowalczyk f39f8b01a5 [ResearchKit] fix for issue #1019 - toolbar 2018-02-21 23:05:51 +01:00
akshay-yadav-apple b28b37c4ed Merge pull request #1062 from ninoguba/picker_dynamic_type
Added support for Dynamic Types to answer formats that use picker views
2018-02-21 02:26:15 -08:00
akshay-yadav-apple d7ddf072aa Merge pull request #1074 from srinathtm-apple/FixForIssue1073
Fix for issue 1073: error in localization
2018-02-21 02:23:58 -08:00
Srinath Tupil Muralidharan 0610718029 using non-localized string as value, based on feedback 2018-02-20 01:42:52 -08:00
Srinath Tupil Muralidharan 2d4b6a566a any negative value will bypass turnAroundTime step 2018-02-20 01:42:13 -08:00
srinathtm-apple b71a07c108 Merge pull request #1069 from Br35Ba56/master
Added phone number form item for ORKRegistrationStep #1068
2018-02-20 01:26:47 -08:00
Srinath Tupil Muralidharan 16bb829e6a create an array of ORKTextChoice instead of an array of NSString 2018-02-19 18:52:05 -08:00
Srinath Tupil Muralidharan 65985167c0 deprecating one of the initializers for timedWalkTask to avoid duplicate code paths 2018-02-19 18:14:40 -08:00
srinathtm-apple 0f0e95473a Merge pull request #1064 from CareEvolution/camera-layout
Make the ORKImageCaptureCameraPreviewView take the full width of the screen.
2018-02-19 15:21:37 -08:00
akshay-yadav-apple 0032b6708a Merge pull request #1067 from danielemden/bugs/ShowTimeLeftLabelForAudioTask
Show time-left-label for audio task
2018-02-19 15:21:14 -08:00
Srinath Tupil Muralidharan 425b858206 reverting to using ternary operator to determine key based on limb type 2018-02-19 14:50:10 -08:00
Anthony Schneider 5787764eaf Added .includePhoneNumber to ORKCatalog accountCreationTask. 2018-02-14 20:04:48 -06:00
Anthony Schneider b829641bd0 Issue #1068 Added option for phone number to ORKRegistrationStep. 2018-02-14 19:53:16 -06:00
Daniel Emden ac7cab60dd Show time-left-label for audio task
Probably due to a typo. The formatter which is used to format the string showing the remaining time for the audio task is always nil.
2018-02-13 23:41:09 +01:00
Akshay 5fe7c7f49e Adding default answer property to ORKTextAnswerFormat and ORKNumericAnwerFormat 2018-02-12 15:26:57 -08:00
Kevin Dang 403d93d064 Fix capturedImageView layout 2018-02-12 14:35:55 -08:00
Kevin Dang ca68d65605 Fix capturedImageView layout 2018-02-12 14:26:39 -08:00
Kevin Dang 4c6ff1c90c Make the ORKImageCaptureCameraPreviewView take the full width of the screen rather than being dependent on templateImage size. 2018-02-12 12:14:40 -08:00
Nino Guba c463359725 Added support for Dynamic Types to ORKMultipleValuePicker 2018-02-10 14:02:58 -08:00
Nino Guba decab237e8 Added support for Dynamic Types to ORKHeightPicker and ORKWeightPicker 2018-02-10 13:52:10 -08:00
Nino Guba 6577436bd4 Added support for Dynamic Types to ORKValuePicker 2018-02-10 13:44:10 -08:00
srinathtm-apple 4132c20897 Merge pull request #1054 from rsanchezsaez/rss/reviewing-guidelines
[docs] Add first draft of the ResearchKit Reviewing Guidelines
2018-02-09 11:06:36 -08:00
Ricardo Sanchez-Saez d520f2963d [docs] Add first draft of the ResearchKit Reviewing Guidelines 2018-01-25 20:13:47 -08:00
kelseydedoshka-apple 6da912d08a Merge pull request #1041 from srinathtm-apple/master
[ResearchKit] fix for issue #1024
2018-01-11 14:40:06 -08:00
srinathtm-apple 4e61599b1f Merge pull request #1052 from akshay-yadav-apple/Fix-For-1019
[ResearchKit] fix for issue #1019
2018-01-11 14:39:22 -08:00
Akshay c8566b00bf [ResearchKit] fix for issue #1019 2018-01-10 10:32:18 -08:00
kelseydedoshka-apple e567a5071c Merge pull request #1025 from tobiasjungnickel/attributedInstructionStep
WIP: ORKInstructionStep detailText as NSAttributedString
2017-12-19 15:48:30 -08:00
Tobias Jungnickel 87fec7ce3a adding additional attributed detail text that overrides detail text if set 2017-12-19 21:25:41 +01:00
Tobias Jungnickel 51e4761e27 Merge branch 'master' into attributedInstructionStep 2017-12-19 19:02:07 +01:00
srinathtm-apple 774e638ca7 Merge pull request #1046 from akshay-yadav-apple/master
[ResearchKit] Fix for issue #1043
2017-12-18 10:22:51 -08:00
srinathtm-apple 79b2095fbd Merge pull request #856 from chrisortman/pdf-interface-1.4.1
Allow customization of rendered PDF
2017-12-15 14:39:17 -08:00
Chris Ortman 05d716c5a2 Remove .swift-version file 2017-12-15 16:10:36 -06:00
Akshay 3a1f004452 Removing duplicate code 2017-12-13 14:23:56 -08:00
Akshay f0db5c3a11 [ResearchKit] Fix for issue #1043 2017-12-13 12:38:23 -08:00
Srinath Tupil Muralidharan d513fbd6f3 [ResearchKit] fix for issue #1015 2017-12-06 15:34:42 -08:00
akshay-yadav-apple c2dfba9870 Merge pull request #1010 from ninoguba/weight_answer_format
Added ORKWeightAnswerFormat
2017-12-06 10:13:24 -08:00
Nino Guba 1dc28a703b Merge pull request #5 from rsanchezsaez/rss/weight-answer-format-merge-master-b
Merge master again
2017-12-06 07:16:46 -08:00
Ricardo Sanchez-Saez d43c1168e5 Merge branch 'master' of github.com:ResearchKit/ResearchKit into ninoguba/weight_answer_format
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
2017-12-06 01:01:30 -08:00
Srinath Tupil Muralidharan 1d2715afb4 [ResearchKit] fix for issue #1024 2017-12-05 17:30:05 -08:00
Pariece McKinney 33609c0fd8 Merge pull request #956 from Sage-Bionetworks/pr/split-ORKResult
Split ORKResult code files into separate files.
2017-12-04 14:03:17 -08:00
Shannon Young e2f178c0e9 Fix more issues that were accepted into master of buggy code.
Issues with ORKToneAudiometryResult and ORKWebViewStep discovered during unit testing of ORKTest.
2017-12-04 12:59:55 -08:00
Shannon Young 80720c1281 Fixes to classes introduces since last March that fail unit tests. 2017-12-04 12:36:46 -08:00
Shannon Young a118762015 Fix definition of the ORKQuestionStepViewController 2017-12-04 11:17:06 -08:00
Shannon Young 1a5d537030 Split out results for stroop and web view. 2017-12-04 10:53:01 -08:00
Nino Guba f1664e5901 Merge pull request #4 from rsanchezsaez/rss/weight-answer-format-merge-master
[Weight Answer Format] Merge master
2017-12-04 09:18:19 -08:00
Ricardo Sanchez-Saez 16dfd0e677 Merge branch 'master' of github.com:ResearchKit/ResearchKit into ninoguba/weight_answer_format
# Conflicts:
#	Testing/ORKTest/ORKTestTests/ORKESerialization.m
2017-12-03 22:31:08 -08:00
Shannon Young e10bb71e03 Merge branch 'master' into pr/split-ORKResult
# Conflicts:
#	ResearchKit/Common/ORKResult.h
#	ResearchKit/Common/ORKResult.m
2017-12-01 15:37:19 -08:00
kelseydedoshka-apple 580e8c9347 Merge pull request #1040 from Medable/issue992_htmlReviewContentNoSignature
Fixes #992. "Consent PDF with htmlReviewContent doesn't add signature page
2017-11-30 10:28:30 -08:00
Fer 51b4c2e539 Fixes #992. "Consent PDF with htmlReviewContent doesn't add signature page 2017-11-30 15:06:44 -03:00
kelseydedoshka-apple 715d5a7301 Merge pull request #1035 from CareEvolution/FormStepSkipFix
Fix for ORKFormStepViewController getting stuck in a "skipped" state
2017-11-29 09:00:38 -08:00
Mike Mertsock c8195bddbc ORKTest: Add shouldPresentStep validation example to exercise skip logic in form step 2017-11-28 18:05:20 -05:00
Mike Mertsock bd2319e74d Reset skipped state when user updates answers in form step 2017-11-28 18:04:00 -05:00
kelseydedoshka-apple ee443eadee Merge pull request #929 from tobiasjungnickel/tableStepSectionHeader
Extend ORKTableStepSource for custom section header
2017-11-26 15:41:44 -08:00
kelseydedoshka-apple 39056d50ab Merge pull request #965 from Medable/issue833_DateStep
Fixes #833. "Date Step - Mismatch between picker.date and what is shown in the UIDatePicker”.
2017-11-26 15:22:56 -08:00
kelseydedoshka-apple feebf2f932 Merge pull request #971 from benjamin-42/update-readme-swift-syntax
Update README.md Swift example code to latest Swift syntax
2017-11-22 13:16:14 -08:00
kelseydedoshka-apple f49b3015c1 Merge pull request #1032 from rsanchezsaez/rss/fix-additional-warnings
[Misc] Fix additional Xcode 9.1 warnings
2017-11-21 16:54:17 -08:00
kelseydedoshka-apple 470582b176 Merge pull request #1030 from CareEvolution/WebViewStep
Add "ORKWebViewStep"
2017-11-21 16:53:09 -08:00
chrisnowak 6c4075258b Add back to ORKTest 2017-11-21 16:44:58 -05:00
chrisnowak 4bf5df0a19 Merge flog 2017-11-21 16:40:02 -05:00
chrisnowak fbb39e1cc5 Fix merge flog 2017-11-21 16:37:54 -05:00
chrisnowak 6319d2861e Remove external url 2017-11-21 16:18:17 -05:00
chrisnowak 9c6c08380b Merge branch 'master' of https://github.com/ResearchKit/ResearchKit into WebViewStep2 2017-11-21 16:11:54 -05:00
Nino Guba 25a71c950d Merge pull request #3 from rsanchezsaez/rss/weight-answer-format-fix-tests
[ORKWeightAnswerFormat] Fix unit tests
2017-11-21 09:21:33 -08:00
Ricardo Sanchez-Saez 271bbba44b [ORKWeightAnswerFormat] Fix serialization tests 2017-11-20 22:39:27 -08:00
Ricardo Sanchez-Saez 83d28ede08 [ORKWeightAnswerFormat] Fix typos 2017-11-20 22:36:08 -08:00
Ricardo Sanchez-Saez f10573e71b Merge branch 'master' of github.com:ResearchKit/ResearchKit into ninoguba/weight_answer_format 2017-11-20 21:32:00 -08:00
Ricardo Sanchez-Saez 06a58fab3a [Misc] Fix additional Xcode 9.1 warnings 2017-11-20 21:30:58 -08:00
kelseydedoshka-apple b9c5ed66bb Merge pull request #1031 from rsanchezsaez/rss/fix-unit-tests
[Misc] Fix unit tests
2017-11-17 11:35:59 -08:00
Shannon Young db51765a9b Merge branch 'master' into pr/split-ORKResult 2017-11-17 09:39:52 -08:00
srinathtm-apple 5a05aed6ee Merge pull request #1029 from rsanchezsaez/rss/Xcode-9.1
[Projects] Update projects to recommended Xcode 9.1 settings and fix all the warnings
2017-11-16 20:56:27 -08:00
Ricardo Sanchez-Saez d50a51c769 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rss/Xcode-9.1
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2017-11-16 20:41:42 -08:00
Nino Guba d922ed87f5 Merge pull request #2 from rsanchezsaez/rss/weight_answer_format
[ORKWeightAnswerFormat] Merge master and resolve conflicts
2017-11-16 16:49:14 -08:00
Nino Guba 15cc58b874 Merge pull request #1 from rsanchezsaez/rss/weight_answer_format-no-merge
[ORKWeightAnswerFormat] Improvements
2017-11-16 12:48:58 -08:00
Ricardo Sanchez-Saez 18b730169f [ORKWeightAnswerFormat] Re-add ORKTest examples 2017-11-16 01:17:37 -08:00
Ricardo Sanchez-Saez 7a1d69a9d1 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rss/weight_answer_format
# Conflicts:
#	ResearchKit/Common/ORKTypes.h
#	ResearchKit/Common/ORKTypes.m
#	Testing/ORKTest/ORKTest/MainViewController.m
2017-11-16 01:10:40 -08:00
Ricardo Sanchez-Saez 2d6efeb430 [ORKCatalog] Capitalize displayed text for ORKWeightAnswerFormat examples 2017-11-16 00:50:22 -08:00
Ricardo Sanchez-Saez 9cbba81572 [ORKWeightPicker] Update localized measure string to ‘lb’ 2017-11-16 00:42:32 -08:00
Ricardo Sanchez-Saez 3108e24830 [ORKWeightPicker] Update ORKTest sample code placeholders 2017-11-16 00:40:39 -08:00
Ricardo Sanchez-Saez 2eefc77cbe [ORKWeightPicker] Rename fraction methods 2017-11-16 00:35:24 -08:00
Ricardo Sanchez-Saez e61c9463a5 [ORKWeightPicker] Add extra properties to NSSecureCoding and equality 2017-11-16 00:34:08 -08:00
Ricardo Sanchez-Saez c1567e8ae6 [ORKWeightPicker] Reuse more code in kg <-> lb converting options; increase conversion precision 2017-11-16 00:26:10 -08:00
Ricardo Sanchez-Saez af08beeb4c [ORKTests] Fix ORKImageChoice serialization tests 2017-11-16 00:03:25 -08:00
Ricardo Sanchez-Saez 86beb05399 [ORKNumericAnswerFormat] Rename ‘scale’ to ‘maximumFractionDigits’ and fix serialization tests 2017-11-15 23:47:52 -08:00
Ricardo Sanchez-Saez 7b8b4dd2ce [ORKRecorderTest] Decrease ork_doubleEqual() precision to pass location recorder tests on the simulator 2017-11-15 23:29:38 -08:00
Ricardo Sanchez-Saez b3dfb08f50 [ORKWeightAnswerFormat] Use ‘double’ instead of ’NSNumber’ for numeric parameters 2017-11-15 22:54:43 -08:00
Ricardo Sanchez-Saez b0bf985469 [ORKWeightAnswerFormat] Change order of parameters 2017-11-15 21:55:52 -08:00
akshay-yadav-apple 7e4967ca06 Merge pull request #959 from Sage-Bionetworks/pr/split-task-modules
Split out ORKOrderedTask task modules into a separate file.
2017-11-15 12:41:44 -08:00
kelseydedoshka-apple e8ed8d2c7e Merge pull request #953 from rsanchezsaez/rss/ORKTest-refactor-b
[ORKTest] Extract task-creating methods to new TaskFactory class
2017-11-15 10:10:51 -08:00
Ricardo Sanchez-Saez d55689dc5e [ORKWeightPicker] Replace ‘valueInterval’ and ‘additionalPrecision’ by ‘numericPrecision’ 2017-11-15 00:46:50 -08:00
Ricardo Sanchez-Saez e2a52c7188 [Height and Weight Pickers] Reuse code by leveraing answerFormat’s -stringForAnswer: method 2017-11-14 22:23:21 -08:00
Ricardo Sanchez-Saez c7ea76a983 [ORKWeightAnswerFormat] Simplify -stringForAnswer: method 2017-11-14 22:22:41 -08:00
Ricardo Sanchez-Saez 73aa1157e6 Revert "[Misc] Update my copyright"
This reverts commit cb94f06094.

# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2017-11-14 14:40:44 -08:00
chrisnowak 0a40250aea Add to ORKTest 2017-11-14 09:46:42 -05:00
chrisnowak c3e7db8c0f Revert "Remove invalid ResearchKit.framework references"
This reverts commit eba62c4857.
2017-11-14 09:07:35 -05:00
Ricardo Sanchez-Saez a0ef5b1715 [Assets] Xcode 9.1 insists on reordering some xcassets fields 2017-11-14 01:17:36 -08:00
Ricardo Sanchez-Saez 6f45964342 [ORKTextChoice] Remove deprecated code 2017-11-14 00:50:52 -08:00
Ricardo Sanchez-Saez 31a86204a9 [Misc] Fix ORKTextChoice warnings 2017-11-14 00:42:10 -08:00
Ricardo Sanchez-Saez 2844102696 [ORKAnswerFormat] Fix convenience initializer being marked as designated 2017-11-14 00:30:17 -08:00
Ricardo Sanchez-Saez 82bb27199a [Misc] Fix strict-prototypes warnings 2017-11-14 00:29:58 -08:00
Ricardo Sanchez-Saez a3f9680006 [Projects] Update all projects to the recommended Xcode 9.1 settings 2017-11-14 00:27:10 -08:00
chrisnowak f851397de0 Set appropriate end time 2017-11-12 11:25:05 -05:00
chrisnowak e998d0747c Add loading indicator 2017-11-12 11:22:47 -05:00
chrisnowak 3682da0aab Check answer for type information 2017-11-12 11:10:46 -05:00
chrisnowak 973beb0fa8 Add embedded html in sample webviewstep 2017-11-12 11:03:52 -05:00
chrisnowak e8e1c36692 Allow embedding html instaed of a url 2017-11-12 10:19:06 -05:00
chrisnowak b7ddc6d195 Add to ORKCatalog 2017-11-11 10:17:02 -05:00
chrisnowak 24dca514a7 Add web view step result 2017-11-11 09:50:42 -05:00
chrisnowak 60ccc4bfad Adding base web view step 2017-11-11 09:33:55 -05:00
kelseydedoshka-apple 9efac8e6a2 Merge pull request #1026 from corduroy/cameraMicrophonePermissions
Add Info.plist keys for microphone and camera access
2017-11-09 14:39:56 -08:00
Joshua McKinnon 0695468020 Add Info.plist keys for microphone and camera access 2017-11-02 16:49:40 +11:00
Tobias Jungnickel b5e625b46f migrating detailText from NSString to NSAttributedString 2017-10-31 06:24:59 +01:00
Pariece McKinney 3e39509af2 Merge pull request #1016 from ninoguba/image_choice_vertical
Added vertical layout option and multiple choice to ORKImageChoiceAnswerFormat
2017-10-09 15:36:42 -07:00
Srinath Tupil Muralidharan ea00c5862e Merge branch 'docs_august17' into 'master'
Docs august17

See merge request !83
2017-10-03 13:12:06 -07:00
Srinath Tupil Muralidharan e6b3ad79f0 [Docs] removing all references to Utility and adding back Passcode 2017-09-26 17:04:15 -07:00
Nino Guba ef1c55cb8e Added valueInterval attribute and defaulted .5 intervals to metric weight values to match Medical ID weight picker 2017-09-20 21:06:46 -07:00
Pariece McKinney b3b484ab61 Merge pull request #1013 from ninoguba/bugfix_height_answer_format
Fix for #1012 to prevent inch value from decrementing unexpectedly
2017-09-20 13:42:26 -07:00
Nino Guba 51acba1999 Added support for multiple choice in ORKImageChoiceAnswerFormat 2017-09-18 23:07:30 -07:00
Nino Guba a984ace443 Added vertical layout option to ORKImageChoiceAnswerFormat 2017-09-18 20:35:00 -07:00
Nino Guba b0a915a30c Fix for #1012 to prevent inch value from decrementing unexpectedly 2017-09-16 10:57:22 -07:00
Nino Guba 5d9bb6c833 Corrected the HK units to match corresponding canonical unit for Weight and Height 2017-09-16 10:25:58 -07:00
Nino Guba 87e9e49519 Fixed HealthKit data handling for Weight and Height; Added example steps using HealthKit quantities for Weight and Height in ORKCatalog 2017-09-16 10:18:54 -07:00
Nino Guba d772f3885a Fixed weight value conversion discrepancies; Limit ounce picker values from 0 to 15 2017-09-15 21:56:33 -07:00
Nino Guba 6b7277cf72 Added minimum and maximum value validations 2017-09-14 21:44:23 -07:00
Nino Guba 45e7f6b529 Added checking min and max values 2017-09-14 20:26:03 -07:00
Nino Guba feae58cde6 Added support for initializing ORKWeightAnswerFormat with default/min/max values and additional precision 2017-09-14 20:02:02 -07:00
Nino Guba 9a635b7227 Added ORKWeightAnswerFormat 2017-09-05 14:50:24 -07:00
Shannon Young 292ad92204 Merge branch 'master' into pr/split-task-modules
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	ResearchKit/Common/ORKOrderedTask.h
#	ResearchKit/Common/ORKOrderedTask.m
2017-09-05 10:20:23 -07:00
Shannon Young 2ba1e8a2fd Fix merge from master 2017-09-05 10:08:50 -07:00
Shannon Young 75d8e0d167 Merge branch 'master' into pr/split-ORKResult
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	ResearchKit/Common/ORKResult.h
#	ResearchKit/Common/ORKResult.m
2017-09-05 10:08:37 -07:00
Joanna Brodbeck 8e2d6a1f34 Removed example of Video Step 2017-08-22 15:39:29 -07:00
Joanna Brodbeck 30f434f18f update screenshot 2017-08-07 16:29:46 -07:00
Joanna Brodbeck 4645015361 Active Tasks: Edits per SM. Overview and Creating Surveys: new content. 2017-08-07 12:13:10 -07:00
Joanna Brodbeck aa15382dc1 Added screenshots and text to Active Tasks. 2017-08-03 19:38:37 -07:00
Akshay 1e8f90f0c8 Merge branch 'Github_master' into Gitlab_master 2017-07-24 12:26:34 -07:00
Pariece McKinney 6886f9345c Merge pull request #987 from Science37/feature/ORKNumericAnswerFormat-decimal-scale
Added decimal scale limit to `ORKNumericAnswerFormat`
2017-07-23 13:12:27 -07:00
Akshay f561f2c51d Merge remote-tracking branch 'origin/stable'
merging stable
2017-07-19 10:58:21 -07:00
Pariece McKinney 7b40d16da2 Merge pull request #974 from hasiniran/master
Issue #973
2017-07-17 11:38:02 -07:00
Akshay 184b1938e5 Version Fixes 2017-07-13 11:51:31 -07:00
Akshay a2d2b13d58 COnvergence 2017-07-06 18:15:56 -07:00
Akshay e52e22e8f5 Convergence 2017-07-06 15:48:38 -07:00
Kelly Chu 56c3d19cb1 Added decimal scale limit to ORKNumericAnswerFormat 2017-06-28 14:20:06 -07:00
Ricardo Sánchez-Sáez 724dd34bac [ORKTest] Re-add Stroop Task 2017-06-21 00:48:32 -07:00
Ricardo Sánchez-Sáez 7c6e83a0fc Merge branch 'master' of github.com:ResearchKit/ResearchKit into rss/ORKTest-refactor-b
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
#	Testing/ORKTest/ORKTest/Tasks/TaskFactory.swift
2017-06-21 00:43:31 -07:00
kelseydedoshka-apple 11228283fa Merge pull request #972 from benjamin-42/fix-passcode-view-controller-layout-glitch
[ORKPasscodeStepViewController] Make sure the view has been laid out before showing the keyboard
2017-06-20 11:03:18 -07:00
kelseydedoshka-apple fa0f23320b Merge pull request #966 from cheif/master
Fix class visibility for new types of Steps, fixes #649
2017-06-19 22:49:03 -07:00
Akshay 05be5f9ae7 Convergence 2017-06-07 10:49:07 -07:00
Akshay e6e4698306 Convergence 2017-06-07 10:10:19 -07:00
Umer Khan 2efdb9d56f Merge pull request #976 from netbe/fix/bundle-version
Update bundle version
2017-05-04 13:45:40 -07:00
François Benaiteau 6907cedf95 Update bundle version 2017-05-02 19:20:49 +08:00
Akshay 113b29ba56 Merge branch 'master' of https://github.com/ResearchKit/ResearchKit
* 'master' of https://github.com/ResearchKit/ResearchKit: (95 commits)
  [Deprecation] Restore deprecated methods which are removed in other PRs
  [ORKTest] Fix serialization tests
  [Deprecation] Re-add ORKTextAnswerFormat and ORKRegistrationStep regex methods
  [Project] Remove unneeded podspec file
  [ORKLocation] Revert wrong 'copy' to 'assign' ivar change
  [Misc] Fix Xcode 8.3 warnings and error
  Closes #922 redefinition of module error
  Fix Redefinition of module error in Xcode 8.3
  Fixed bug with ORKTextChoice not using the correct tint color
  Changed upper duration limit from 120 to 1200
  [ORKESerialization] Fix typo
  [ORKJSONSerializationTests] Simplify property initialization by generalizing usage of the orktest_init helper
  [ORKAnswerFormat] Indentation fixes
  [ORKESerialization] Fix ORKTextAnswerFormat tests
  [ORKTextAnswerFormat] Replace 'validationRegex' (the patterm) and 'validationRegexOptions' properties by 'validationRegularExpression' (an NSRegularExpression object)
  [ORKRegistrationStep] Clarify 'passcodeValidation' serialization comments
  [ORKTextAnswerFormat] Change 'validationRegexOptions' default value to 0
  [ORKTextAnswerFormat] Fix merge issue
  Fix localization for formatted strings so that they will localize correctly left-to-right.
  Fix documentation
  ...
2017-04-28 00:48:57 -07:00
Chris Ortman 221996b73a Removing bundler files 2017-04-26 22:15:19 -05:00
Chris Ortman c309d69349 Update copyright 2017-04-26 22:13:47 -05:00
hasiniran 4dffafc10d Issue #973
in ORKPasscodeStepViewController, supported interface orientation is
set to UIInterfaceOrientationMaskPortrait. To support any orientation
this was changed to UIInterfaceOrientationMaskAll.
2017-04-13 12:43:09 -04:00
Benjamin Randazzo b46ebf3ded [ORKPasscodeStepViewController] Make sure the view has been laid out before showing the keyboard
This is a fix for issue #960, -viewDidAppear: is called but the view isn't on screen yet when the view controller is set in a UIPageViewController
2017-04-08 21:17:26 +02:00
Benjamin Randazzo b9351232fc Update README.md Swift example code to latest Swift syntax 2017-04-08 17:54:34 +02:00
Umer Khan b04a5aa6a4 Merge pull request #969 from rsanchezsaez/rss/deprecation
[Deprecation] Re-add ORKTextAnswerFormat and ORKRegistrationStep regex methods
2017-04-07 15:41:03 -07:00
Ricardo Sanchez-Saez 76cec79983 [Deprecation] Restore deprecated methods which are removed in other PRs
This partially reverts commit c3d25d6edc.
2017-04-07 00:48:08 -07:00
Ricardo Sanchez-Saez 3697e01b6f [ORKTest] Fix serialization tests 2017-04-06 02:15:26 -07:00
Ricardo Sanchez-Saez c3d25d6edc [Deprecation] Re-add ORKTextAnswerFormat and ORKRegistrationStep regex methods
Also, move every deprecated method to the new ORKDeprecated.h/.m files. Add specific deprecation attributes and comments.
2017-04-06 02:02:47 -07:00
Ricardo Sanchez-Saez 261bc598f0 [Project] Remove unneeded podspec file 2017-04-06 01:16:22 -07:00
Scott Guelich eba62c4857 Remove invalid ResearchKit.framework references
Was showing up as duplicate entry under ResearchKit/Products
and causing embedding this framework in other targets to fail
2017-04-04 07:33:49 -07:00
Dan Berglund a4e49d490d Fix class visibility for new types of Steps, fixes #649 2017-04-03 17:04:20 -04:00
Ricardo Sanchez-Saez 6bde09345f [ORKTest] Homogenize step and item identifiers 2017-04-02 23:13:11 -07:00
Ricardo Sanchez-Saez a81c577fc3 [ORKTest] Convert iterruptible example to block based interface 2017-04-01 01:13:02 -07:00
Shannon Young 2058936108 Fix equality for ORKLocation 2017-03-31 17:00:16 -07:00
Shannon Young 5be15107b3 Merge branch 'master' into pr/split-ORKResult
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	ResearchKit/Common/ORKResult.h
#	ResearchKit/Common/ORKResult.m
#	ResearchKit/Common/ORKResult_Private.h
2017-03-31 12:41:29 -07:00
Shannon Young fb6dd4782a Fix issues with ORKLocation merge from master 2017-03-31 11:23:34 -07:00
Shannon Young 4a944cc972 Merge branch 'master' into pr/split-task-modules 2017-03-31 10:51:07 -07:00
Fernando Waigandt 022144ad28 Fixes #833. "Date Step - Mismatch between picker.date and what is shown in the UIDatePicker”. 2017-03-31 10:59:54 -03:00
Ricardo Sanchez-Saez 238cae5d31 [ORKTest] Consolidate the rest of examples that use 'stepViewControllerWillAppear:' 2017-03-30 21:52:52 -07:00
Ricardo Sanchez-Saez 0870abc22b [ORKTest] Consolidate stepViewControllerWillAppear: examples in new "Step Will Appear" test
Also, reimplement 'stepViewControllerWillDisappear:' example using the block based approach; and delete a few no longer needed task helper properties.
2017-03-30 21:22:02 -07:00
Ricardo Sanchez-Saez 3b74dd93f6 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rss/ORKTest-refactor-b 2017-03-30 20:19:54 -07:00
Umer Khan d82eae5f94 Merge pull request #964 from rsanchezsaez/rss/xcode-8.3-warnings
[Misc] Fix Xcode 8.3 warnings and error
2017-03-30 14:33:51 -07:00
Umer Khan 14b27ada27 Merge pull request #963 from stevemoser/patch-5
Fix Redefinition of module error in Xcode 8.3
2017-03-30 14:33:01 -07:00
Ricardo Sanchez-Saez 56a261eb27 [ORKLocation] Revert wrong 'copy' to 'assign' ivar change 2017-03-30 10:48:51 -07:00
Tobias Jungnickel 988371fb28 Merge pull request #1 from syoung-smallwisdom/syoung-pr/tableStepSectionHeader
Fix the loop for the case where the UITableViewDelegate and this protocol clash
2017-03-30 19:25:03 +02:00
Ricardo Sanchez-Saez 0a377eda53 [ORKTest] Begin removal of taskViewController:stepViewControllerWillAppear: test code
Use a block associated to the relevant ORKStep instead.
2017-03-29 22:35:42 -07:00
Ricardo Sanchez-Saez 1fc013742a [ORKTest] Get rid of task identifier constants
It now uses the automatically generated task identifiers. This also adds a NSObject (TaskFactory) helper category for commicating task intent to the MainViewController.
2017-03-29 21:12:26 -07:00
Ricardo Sanchez-Saez 2a196bc768 [ORKTest] Update copyright headers for new files 2017-03-28 20:13:12 -07:00
Ricardo Sanchez-Saez 6bb2313a1f [TaskFactory+Forms] Resolve merge conflict 2017-03-28 20:07:55 -07:00
Ricardo Sanchez-Saez dcd0be1132 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rss/ORKTest-refactor-b
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2017-03-28 20:03:19 -07:00
Ricardo Sanchez-Saez 8ba80ac79d [Misc] Fix Xcode 8.3 warnings and error
Starting on Xcode 8.3, the 'module.modulemap' file caused the compilation error described in https://github.com/ResearchKit/ResearchKit/issues/922. Renaming it to 'ResearchKit.modulemap' seems to fix the issue.
2017-03-28 19:48:28 -07:00
Steve Moser ceca4baf42 Closes #922 redefinition of module error 2017-03-28 20:53:47 -04:00
Steve Moser e83c26208b Fix Redefinition of module error in Xcode 8.3 2017-03-28 20:50:02 -04:00
Umer Khan 30fd3c0cc6 Merge pull request #958 from ninoguba/textchoice_tintcolor_fix
Fixed bug with ORKTextChoice not using the correct tint color
2017-03-28 11:54:11 -07:00
Umer Khan 22f6aeb066 Merge pull request #952 from rsanchezsaez/rss/nsregularexpression-options
[ORKTextAnswerFormat] Replace the validation regex pattern by a NSRegularExpression object
2017-03-28 11:45:32 -07:00
Ricardo Sanchez-Saez 343be912d0 [ORKtest] Reorganize TaskFactory into categories
Also, reorganize some project files.
2017-03-28 01:23:30 -07:00
Ricardo Sanchez-Saez 0972a789a4 [ORKTest] Remove unneeded import 2017-03-27 22:13:22 -07:00
Ricardo Sanchez-Saez fe994cea75 [TaskFactory] Add missing 'introStep' on the Navigable Ordered Task 2017-03-23 21:47:13 -07:00
Ricardo Sanchez-Saez 7fe617e765 [ORKTest] Dynamically calculate the task identifier
This allows removing a bunch of boilerplattery '-itemTitleButtonTapped:' methods.

Also, reorder and rename task identifiers in the TaskFactory to support this.
2017-03-23 21:47:13 -07:00
Ricardo Sanchez-Saez d451b26788 [ORKTest] Remove 'Task' from all item names 2017-03-23 21:47:13 -07:00
Ricardo Sanchez-Saez 6632633322 [ORKTest] Replace coupled section arrays by array of dictionaries
This is easier to maintain.

Also:
- Set 'adjustsFontSizeToFitWidth' to YES for button labels.
- Improve Image Choice Task name and text.
2017-03-23 21:47:13 -07:00
Ricardo Sanchez-Saez 2841a8f348 [ORKTest] Reorganize main sections
Includes:
- Create a few new sections.
- Alphabetically order sections (except 'Miscellaneous' which is kept last).
- Alphabetically order items within each section.
- Rename some items for consistency.
2017-03-23 21:47:13 -07:00
Ricardo Sanchez-Saez a0e1317c22 [TaskFactory] Add missing CompletionStepTask to task switch 2017-03-23 21:46:56 -07:00
Shannon Young bfe3e691e1 Split the predefined Active Task modules into a separate file. 2017-03-22 11:42:00 -07:00
Shannon Young 392ee67733 Move temp file back to original file name. 2017-03-22 10:43:00 -07:00
Shannon Young a3b9ec6d3d Merge branch 'task/splitA' into pr/split-task-modules
# Conflicts:
#	ResearchKit/Common/ORKOrderedTask+TaskModules.h
#	ResearchKit/Common/ORKOrderedTask+TaskModules.m
#	ResearchKit/Common/ORKOrderedTask.h
#	ResearchKit/Common/ORKOrderedTask.m
#	ResearchKit/Common/ORKOrderedTask_temp.h
#	ResearchKit/Common/ORKOrderedTask_temp.m
2017-03-22 10:41:23 -07:00
Shannon Young 109f69b9df temp split of ORKOrderedTask 2017-03-22 10:23:14 -07:00
Shannon Young 79d61223c6 Split out ORKOrderedTask task modules into a separate file. 2017-03-22 10:20:55 -07:00
Shannon Young f97b4923b6 Fix nullable for ORKLocation 2017-03-21 23:46:12 -07:00
Nino Guba e391fbf254 Fixed bug with ORKTextChoice not using the correct tint color 2017-03-21 15:40:56 -07:00
Shannon Young 8de0d5c755 Split ORKPasscodeResult into a separate file. 2017-03-21 14:38:09 -07:00
Shannon Young e030fff263 Split ORKSignatureResult and ORKConsentSignatureResult into separate file. 2017-03-21 14:32:53 -07:00
Shannon Young f4753aacf1 Split ORKVideoInstructionStepResult into a separate file. 2017-03-21 14:17:50 -07:00
Shannon Young 2075cf8fb1 Split ORKQuestionResult subclasses into a separate file. 2017-03-21 14:00:34 -07:00
Shannon Young e9e165e10d Remove unused private ORKDataResult subclass. 2017-03-21 13:34:50 -07:00
Shannon Young 121507db1c Split ORKCollectionResult subclasses into separate file. 2017-03-21 13:33:04 -07:00
Shannon Young 139ad4f8b6 Split ORKResult into separate files for each active task result.
`ORKResult` is getting huge, difficult to maintain, and difficult to handle merge conflicts. I’ve separated out all the active task results into a file for each module result type. Additionally, I split out the `ORKQuestionResult` subclasses into a separate file and the `ORKCollectionResult` subclasses into a separate file.
2017-03-21 13:03:14 -07:00
Umer Khan 96712fcfcd Merge pull request #954 from rochoSC/bug-fix-917
Fix for issue #917
2017-03-21 11:30:04 -07:00
Roger Solis bac6fff8f1 Changed upper duration limit from 120 to 1200 2017-03-21 11:45:14 -05:00
Ricardo Sanchez-Saez cb94f06094 [Misc] Update my copyright 2017-03-20 22:18:51 -07:00
Ricardo Sanchez-Saez 377120ac38 [TaskFactory] Update copyright 2017-03-20 22:17:34 -07:00
Ricardo Sanchez-Saez 161e56c738 [ORKESerialization] Fix typo 2017-03-20 11:54:16 -07:00
Umer Khan ce50dbccea Merge pull request #951 from Sage-Bionetworks/pr/fix-localization-strings
Fix localization for formatted strings so that they will localize correctly left-to-right.
2017-03-20 11:04:15 -07:00
Ricardo Sanchez-Saez 4ff30c68fe [ORKTest] Extract task-creating methods to new TaskFactory class 2017-03-19 19:30:08 -07:00
Ricardo Sanchez-Saez 8e3aaa4246 [ORKJSONSerializationTests] Simplify property initialization by generalizing usage of the orktest_init helper 2017-03-19 18:30:21 -07:00
Ricardo Sanchez-Saez 4f087ce783 [ORKAnswerFormat] Indentation fixes 2017-03-19 18:05:13 -07:00
Ricardo Sanchez-Saez f03084534d [ORKESerialization] Fix ORKTextAnswerFormat tests
Adds NSRegularExpression serialization/deserialization. Note that the tests are ignoring the 'validationRegularExpression' for the hash test becuase it's purposefully not included there.

Also, slight fix to the CLCircularRegion serialization (a nil CLCircularRegion must be serialized into an empty dict, not into a nil object). Otherwise it'll crash if you try to add nil to the parent serialization dictionary.
2017-03-19 17:56:30 -07:00
Ricardo Sanchez-Saez 4da2747943 [ORKTextAnswerFormat] Replace 'validationRegex' (the patterm) and 'validationRegexOptions' properties by 'validationRegularExpression' (an NSRegularExpression object) 2017-03-19 17:53:40 -07:00
Ricardo Sanchez-Saez 10bb15f253 [ORKRegistrationStep] Clarify 'passcodeValidation' serialization comments 2017-03-19 15:35:48 -07:00
Ricardo Sanchez-Saez 15601c420a [ORKTextAnswerFormat] Change 'validationRegexOptions' default value to 0
And update documentation accordingly.
2017-03-19 15:34:45 -07:00
Ricardo Sanchez-Saez 8d8b2e3db6 [ORKTextAnswerFormat] Fix merge issue 2017-03-19 15:17:27 -07:00
Ricardo Sanchez-Saez 945d5e9f25 Merge branch 'master' of github.com:ResearchKit/ResearchKit into nsregularexpression-options
# Conflicts:
#	ResearchKit/Common/ORKAnswerFormat.m
#	Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m
2017-03-19 15:15:17 -07:00
Shannon Young b87babb66c Fix localization for formatted strings so that they will localize correctly left-to-right.
When using string formatting, Apple’s recommendation is to use `localizedStringWithFormat:` for cases where the string may be displayed in a language that reads from left-to-right.
2017-03-16 10:56:10 -07:00
Chris Ortman c5d864dbb4 Updating license & copyright 2017-03-16 10:36:27 -05:00
Chris Ortman 9e9ba10a52 Add swift-version file for pod lint
pod lib lint --allow-warnings now passes
2017-03-16 09:50:03 -05:00
Chris Ortman 06fe8e8ce9 Add bundler to ensure consistent version of cocoapods 2017-03-16 09:50:03 -05:00
Chris Ortman 692d7b50a4 Allow the renderer to declare it's own width & height 2017-03-16 09:50:03 -05:00
Chris Ortman 55dd93238e Modify ORKConsentDocument to allow passing a renderer 2017-03-16 09:50:03 -05:00
Umer Khan 69e642792d Merge pull request #896 from Sage-Bionetworks/pr/add-multicomponent-picker-format
Add answer format for handling a multiple component picker.
2017-03-15 10:30:09 -07:00
Shannon Young 4c0afc0037 Merge branch 'master' into pr/add-multicomponent-picker-format
# Conflicts:
#	ResearchKit/Common/ORKAnswerFormat.h
#	ResearchKit/Common/ORKAnswerFormat.m
2017-03-15 10:27:20 -07:00
Umer Khan a8777b84b5 Merge pull request #947 from stevemoser/patch-4
Add NSHealthShareUsageDescription key
2017-03-15 10:16:06 -07:00
Umer Khan 5c4d36c398 Merge pull request #934 from Sage-Bionetworks/pr/fix-passcodeFlow-equality-coding-copying
Fix missing passcodeFlow serialization, copying, encoding and equality
2017-03-15 10:13:04 -07:00
Umer Khan c25a9954b2 Merge pull request #941 from MacroYau/feature/custom-boolean-answer
Add custom yes and no strings option for ORKBooleanAnswerFormat
2017-03-15 10:09:54 -07:00
Macro Yau a7bb837e4b Fix documentation 2017-03-15 12:05:42 +08:00
Macro Yau ca99dcbc2d Add example to ORKTest's Selection Survey 2017-03-15 11:53:52 +08:00
Macro Yau 9f06cc0575 Implement factory method in ORKAnswerFormat 2017-03-15 11:52:14 +08:00
Macro Yau 2dba4fd450 Add documentation 2017-03-15 11:30:27 +08:00
Macro Yau 47fc7c8475 Override hash() in ORKBooleanAnswerFormat 2017-03-15 11:18:31 +08:00
Macro Yau f7c9ad2692 Fix copyWithZone() implementation 2017-03-15 11:16:55 +08:00
Steve Moser a600a87480 Add NSHealthShareUsageDescription key
This prevents a crash during the fitness task.
2017-03-14 21:07:47 -04:00
Shannon Young 1cd821b2da Fix encoding to use ENUM instead. 2017-03-14 16:46:11 -07:00
Umer Khan 563a081168 Merge pull request #938 from MacroYau/feature/charts-decimal-place
Allow custom decimal places in ORKGraphChartView
2017-03-14 15:36:19 -07:00
Shannon Young b3f7f0ad90 Fixed code review issues with formatting 2017-03-14 14:12:35 -07:00
Umer Khan d3dd1934c6 Merge pull request #901 from Sage-Bionetworks/pr/open-navigation-rule
Allow interhitance of navigation rules outside ResearchKit
2017-03-14 13:53:22 -07:00
Shannon Young a133f6a3a0 Merge branch 'master' into pr/add-multicomponent-picker-format 2017-03-14 13:50:20 -07:00
Umer Khan 442968c622 Merge pull request #944 from stevemoser/fix-app-delegate-for-swift-3
Fix app delegate for swift 3
2017-03-14 13:23:02 -07:00
Umer Khan 4f6af4ed83 Merge pull request #865 from Sage-Bionetworks/pr/update-healthkit-answerformat
Add missing HealthKit characteristic types to answer format.
2017-03-14 13:21:59 -07:00
Umer Khan 47191bfdbc Merge pull request #915 from joshbruhin/Bridge-1684
Call becomeFirstResponder with dispatch to main queue after delay
2017-03-14 13:00:31 -07:00
Umer Khan 0f5dca38e4 Merge pull request #880 from faraz-hussain/pr/add-module-trailmaking-test
Add module for trail making test
2017-03-14 12:22:53 -07:00
Umer Khan 161001357d Merge pull request #902 from Sage-Bionetworks/pr/add-result-to-stepViewController
Add method to ORKStepViewController to allow adding a result
2017-03-14 12:04:13 -07:00
Umer Khan 2de86b189e Merge pull request #840 from Sage-Bionetworks/pr/ui-step-footnote
Add footnote label displayed at the bottom of an instruction or form step.
2017-03-14 11:55:57 -07:00
Umer Khan f739fed350 Merge pull request #804 from Sage-Bionetworks/pr/add-memory-copyright
There is a copyright that should be included with the memory game.
2017-03-14 11:54:10 -07:00
Umer Khan 3a6fc380cf Merge pull request #910 from Sage-Bionetworks/pr/add-primitive-number-to-equality-test
Added equality testing for primitive double, int and bool properties
2017-03-14 11:50:08 -07:00
Umer Khan 2208a8bcfd Merge pull request #940 from johnsaigle/readmeUpdate
Update README to reflect new ORK syntax
2017-03-14 10:30:30 -07:00
Steve Moser 76b6b1e995 Fix app delegate methods not being called
Because of the changes to Swift 3 the sample app’s delegate methods
were not being called which made the apps fail in ways that aren’t
apparent at first launch.
2017-03-12 13:51:50 -04:00
Steve Moser 56243d7cd6 Merge branch 'ResearchKit/master' 2017-03-12 13:42:58 -04:00
Macro Yau 28c5e75375 Fix serialization and add tests 2017-03-11 16:06:59 +08:00
Macro Yau df4be2f4c4 Add NSCoder support 2017-03-11 15:22:17 +08:00
Macro Yau 9a778eafcd Add example to ORKCatalog 2017-03-11 11:55:37 +08:00
Macro Yau 4c8a05251c Add custom yes and no strings option for ORKBooleanAnswerFormat 2017-03-11 11:42:52 +08:00
John Saigle c0851d8f2e Update README to reflect new ORK syntax 2017-03-09 13:52:01 -05:00
Macro Yau 5c69459f6b Add customizable decimal place option for ORKYAxisView value labels 2017-03-09 16:16:29 +08:00
Macro Yau 66adcfd387 Add customizable decimal place option for ORKGraphChartView scrubber label 2017-03-09 16:08:21 +08:00
Shannon Young 1a6f84b706 Fix the loop for the case where the UITableViewDelegate and this protocol clash
It you point the `ORKTableStepSource` at the view controller then this will result in an infinite loop of wacky madness. Change the protocol to match the other methods in the protocol that provide a pointer to the table view as the last parameter.
2017-03-07 22:04:47 -08:00
Shannon Young 82dc103bbf Fixes in response to code review. 2017-03-07 15:17:16 -08:00
Shannon Young c17e90d775 fix code review issue. 2017-03-07 14:26:13 -08:00
Shannon Young d649b4a14d Fixed code review issues 2017-03-07 14:23:56 -08:00
Shannon Young 7a6dd5c580 Fix code review issues. 2017-03-07 13:50:38 -08:00
Shannon Young 65537987df use self.footnote.hash 2017-03-07 13:23:50 -08:00
Shannon Young 1ae3f86279 Fix missing passcodeFlow serialization, copying, encoding and equality 2017-03-07 11:41:05 -08:00
Umer Khan e4d2187871 Merge pull request #877 from sroymdsol/Expose_passcode_flow_types
Expose passcode flow types
2017-03-06 11:25:35 -08:00
Shannon Young 9499035725 Update to check programmatically for iOS 10 or watchOS 3 availability 2017-03-03 13:37:11 -08:00
Shannon Young 3680d05f38 Fix HKCharacteristicTypeIdentifierWheelchairUse iOS10 issue 2017-03-03 12:33:42 -08:00
Shannon Young 42a2d0efb8 Check for iOS10 for HKCharacteristicTypeIdentifierWheelchairUse 2017-03-03 11:07:51 -08:00
Shannon Young 0a8165ca35 Fix tests for ORKVideoCaptureStep 2017-03-03 00:54:22 -08:00
Shannon Young 325142bec2 Merge branch 'master' into pr/add-primitive-number-to-equality-test 2017-03-03 00:39:57 -08:00
Shannon Young 9b137318e0 Add space between imports and @implementation 2017-03-01 14:11:01 -08:00
Shannon Young 2330a21426 Cleanup in response to code review. 2017-03-01 14:07:07 -08:00
Shannon Young a09b5f3a70 For direct inheritance from ORKStepViewController, use parent results rather than added results. 2017-03-01 10:00:50 -08:00
Shannon Young e57e99b290 Merge remote-tracking branch 'origin/master' into pr/add-result-to-stepViewController 2017-03-01 09:29:59 -08:00
Shannon Young 64780981f2 Merge branch 'master' into pr/add-multicomponent-picker-format
# Conflicts:
#	ResearchKit/Common/ORKAnswerFormat.m
2017-02-28 15:44:37 -08:00
Tobias Jungnickel 787844d2a0 extend ORKTableStepSource to return custom title and view for header in section 2017-02-28 11:17:19 +01:00
Umer Khan ac74dfc416 Merge pull request #899 from Medable/issue834_ContinuousScaleStep
Fixes #834. "Continuous Scale Step - UI value and result value mismatch when using fraction digits."
2017-02-27 13:12:29 -08:00
Umer Khan 8f9f2f6de5 Merge pull request #908 from joshbruhin/BridgeTask-1513
Adding specific images for Tremor test left and right hand
2017-02-27 13:11:10 -08:00
Akshay 56d45c3a96 Merging latest public master 2017-02-23 14:58:10 -08:00
Shannon Young f45a6f629f Merge branch 'master' into pr/update-healthkit-answerformat 2017-02-17 09:35:45 -08:00
Josh Bruhin 0d11c9f9fd Bridge-1684 call becomeFirstResponder with dispatch to main queue after delay to prevent invisible keyboard when user hits ‘cancel’ in touch ID context 2017-02-09 15:17:49 -07:00
Umer Khan 2843759bcc Merge pull request #913 from stevemoser/patch-3
Add missing height question
2017-02-09 10:15:58 -08:00
Steve Moser a6509da0b1 Add missing height question 2017-02-07 15:51:48 -05:00
Shannon Young fc8c18ec0a Move healthkit read permissions to ORKStep
# Conflicts:
#	ResearchKit/Common/ORKOrderedTask.m
2017-02-03 11:21:32 -08:00
Kelsey Dedoshka badfbf0ad1 [Update] ResearchKit (1.4.1) 2017-02-01 15:10:08 -08:00
Faraz Hussain 3a630b3959 Adding timer label and error scores to trail making test 2017-01-31 13:30:04 -06:00
Shannon Young a2a6fef6aa Added test for checking the hash to equality tests. 2017-01-30 14:04:39 -08:00
Shannon Young 2986d85f58 Added equality testing for primitive double, int and bool properties
This adds equality checking for primitive types for the double, int and bool properties.

Note: this *only* checks equality and does not test these properties for encoding, though I have also fixed the encoding for those classes that failed the equality tests.
2017-01-30 13:10:16 -08:00
Josh Bruhin 5ee602bbee Deleting previous Tremortest2 image, replaced by TremortestLeft and TremortestRight 2017-01-30 12:22:33 -07:00
Josh Bruhin ee317862bb Adding specific images for Tremor test left and right hand instead of simply flipping the right-handed image for use as the left. 2017-01-30 12:17:29 -07:00
Umer Khan 182cb27551 Merge pull request #904 from stevemoser/patch-2
Fix ORKTimedWalkResult isEqual: and copyWithZone:
2017-01-30 08:54:35 -08:00
Umer Khan e54f09d973 Merge pull request #903 from stevemoser/patch-1
Fix fashion typo
2017-01-30 08:52:35 -08:00
Steve Moser dd7eb78775 Fix ORKTimedWalkResult isEqual: and copyWithZone:
It appears this was most likely the result of a copy and paste error. IMHO tests should be created for this class to catch small bugs like this one.
2017-01-28 15:33:22 -05:00
Steve Moser eae5eb5458 Fix fashion typo 2017-01-28 14:59:08 -05:00
Shannon Young a70323b73a Add method to ORKStepViewController to allow adding a result
Add a result to the step view controller's `ORKStepResult`. By default, the property for the step view controller's result will instantiate a copy of the result each time it is called. Therefore, the result cannot be mutated by adding a result to it's result array.

This method can be called by a delegate to add a result to a given step in a way that will be retained by the step, but will allow both the step and the ORKResult to be immutable when passed to the task view controller.

We have been finding that many of the researchers and developers we work with assume that this is possible and then become frustrated and confused when it doesn’t work.
2017-01-27 16:05:55 -08:00
Shannon Young d36b53336b Fixed warnings about int cast. 2017-01-26 16:23:37 -08:00
Faraz Hussain 0a2c937ef2 Redrawing graphics in UIView
Lines connecting dots are now redrawn if orientation is changed from
portrait to landscape or vice versa to maintain line coherence
2017-01-26 16:01:23 -06:00
Shannon Young 3d5dfec624 Allow interhitance of navigation rules outside ResearchKit
This will still throw an exception if the developer attempts to initialize an instance of the base class without inheriting it but allows developers to create navigation rules that inherit directly from the base class.
2017-01-26 11:40:59 -08:00
Fernando Waigandt e9569123fd Pull request #899 - Requested changes - Added Medable Copyright. 2017-01-25 21:35:38 -03:00
Fernando Waigandt d5ac624b24 Pull request #899 - Requested changes. 2017-01-25 21:28:43 -03:00
Faraz Hussain 5aade34809 Clarified instruction wording for trail making test 2017-01-25 15:06:30 -06:00
Faraz Hussain d7b44f890e Merge branch 'master' into pr/add-module-trailmaking-test 2017-01-25 15:00:30 -06:00
Shannon Young 250a18ee26 Merge branch 'master' into pr/ui-step-footnote
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2017-01-25 10:54:55 -08:00
Umer Khan 1446df4559 Merge pull request #898 from rsanchezsaez/rss/ORKSignatureView-top
[ORKSignatureStepViewController] Fix not being able to start traces on the top part of the signature view
2017-01-25 10:45:32 -08:00
Umer Khan 1afe85b259 Merge pull request #769 from oliverschaefer/videoInstructionStep
Video Instruction Step
2017-01-25 10:43:52 -08:00
Steve Roy a93e0c15b8 Moved the passcodeFlow property and associated enums to be a property of ORKPasscodeStep instead of the view controller. 2017-01-25 11:01:51 -05:00
Fernando Waigandt d0c261b36b Medable - Fixes #834. "Continuous Scale Step - UI value and result value mismatch when using fraction digits." 2017-01-25 12:06:57 -03:00
Oliver Schäfer b1bc2e649d Merge pull request #7 from MacroYau/feature/videoinstructionstep
Implement requested changes in Video Instruction Step
2017-01-25 08:38:56 +01:00
Macro Yau 61eb619e3d Update ORKESerializer 2017-01-25 14:10:01 +08:00
Ricardo Sanchez-Saez 807d24b76e [ORKSignatureStepViewController] Rename 'ORKConsentSignatureWrapperView' to 'ORKSignatureWrapperView'
This makes all signature UI classes coherent. The result and data model classes still have the `ORKConsentSignature...` prefix (to differentiate from an automatically calculated electronic signature).
2017-01-24 20:57:19 -08:00
Ricardo Sanchez-Saez 80d707b094 [ORKSignatureView] Remove needless '_' prefix from method names 2017-01-24 20:48:35 -08:00
Ricardo Sanchez-Saez 601692b991 [ORKSignatureStepViewController] Fix not being able to start traces on the top part of the signature view 2017-01-24 20:46:27 -08:00
Macro Yau 4b143997b8 Implement requested changes 2017-01-25 11:02:42 +08:00
Macro Yau 6438c4770a Resolve merge conflicts 2017-01-25 10:56:39 +08:00
Shannon Young ab20d025e3 Merge branch 'master' into pr/add-multicomponent-picker-format
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
2017-01-24 14:16:20 -08:00
Shannon Young e8660e83ad Merge branch 'master' into pr/update-healthkit-answerformat
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
2017-01-24 14:13:33 -08:00
Shannon Young ddc90812d1 Merge branch 'master' into pr/ui-step-footnote
# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	Testing/ORKTest/ORKTest/MainViewController.m
2017-01-24 14:06:01 -08:00
Umer Khan c024cbd503 Merge pull request #758 from Sage-Bionetworks/pr/ui-add-ORKPageStepViewController
Add ORKPageStep and ORKPageStepViewController
2017-01-24 13:49:10 -08:00
Umer Khan 0c9fb3b357 Merge pull request #848 from Sage-Bionetworks/pr/fix-tremor-navigation
Add ORKStepModifier to navigable task.
2017-01-24 13:23:35 -08:00
Umer Khan 7212f3c663 Merge pull request #845 from Sage-Bionetworks/pr/tablestep-source
ORKTableStepViewController improvements
2017-01-24 13:19:46 -08:00
Umer Khan 9a68704218 Merge pull request #894 from rsanchezsaez/rss/ORKSignatureView
[ORKSignatureView] Increase height and distance of signing line to bottom
2017-01-24 13:19:14 -08:00
Umer Khan b85949bf7b Merge pull request #897 from Sage-Bionetworks/pr/fix-regex-validation
Fix ORKTextAnswerFormat regex to be case sensitive.
2017-01-24 13:17:57 -08:00
Faraz Hussain a9d1ef573d Minor formatting changes requested during merge 2017-01-24 14:48:33 -06:00
Shannon Young dc185c69e4 Fix merge conflicts 2017-01-24 12:43:33 -08:00
Shannon Young 32abf1f6f5 Merge branch 'master' into pr/ui-add-ORKPageStepViewController
# Conflicts:
#	ResearchKit/Common/ORKResult_Private.h
#	ResearchKit/ResearchKit.h
#	ResearchKit/ResearchKit_Private.h
#	Testing/ORKTest/ORKTest/MainViewController.m
2017-01-24 12:17:18 -08:00
faraz-hussain 742b6f01ab Merge branch 'master' into pr/add-module-trailmaking-test 2017-01-24 14:13:54 -06:00
Shannon Young 2af14cfa68 Cleanup code style. 2017-01-24 12:03:39 -08:00
Umer Khan 2a3ffd2b18 Merge pull request #890 from rsanchezsaez/rss/ib-designable
[Charts] IBDesignable improvements
2017-01-24 11:56:11 -08:00
Shannon Young 2f72c15451 Cleaned up code style. 2017-01-24 11:55:52 -08:00
Shannon Young 74a8a0ec6d Merge branch 'master' into pr/tablestep-source 2017-01-24 11:52:00 -08:00
Shannon Young 06ce98338a Merge branch 'master' into pr/ui-step-footnote
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2017-01-24 11:51:02 -08:00
Umer Khan 541ae005b6 Merge pull request #807 from slichlyter12/master
Added gesture recognizer to MapView for ORKLocationAnswerFormat
2017-01-24 11:47:19 -08:00
Umer Khan 090877e5d9 Merge pull request #859 from rsanchezsaez/umbrella-headers
[Umbrella headers] Update #imports to framework format
2017-01-24 11:45:27 -08:00
Shannon Young 3b41a38158 Fix warnings about the designated initializer 2017-01-24 11:42:05 -08:00
Umer Khan f57ec43e1f Merge pull request #837 from Sage-Bionetworks/pr/ui-completion-step-done-button
Add a flag to allow displaying the continue button in the standard position for the compltion step.
2017-01-24 11:32:58 -08:00
Umer Khan e17fb8008d Merge pull request #828 from Sage-Bionetworks/pr/fix-navigation-result-loop
Fix navigation looping to return unique results for each step.
2017-01-24 11:31:49 -08:00
Oliver Schäfer e818d99489 Merge pull request #6 from MacroYau/feature/videoinstructionstep
Resolve merge conflicts
2017-01-24 09:33:21 +01:00
Macro Yau 2fe68f6ac0 Fix ORKCatalog example 2017-01-24 14:00:20 +08:00
Macro Yau ec839b490c Resolve merge conflicts 2017-01-24 13:54:07 +08:00
Macro Yau a2ae36e08c Resolve merge conflicts 2017-01-24 13:18:21 +08:00
Ricardo Sanchez-Saez e9e6e781ae Merge branch 'master' of github.com:ResearchKit/ResearchKit into umbrella-headers 2017-01-23 19:27:40 -08:00
Ricardo Sanchez-Saez b97d728f7a Merge branch 'master' of github.com:rsanchezsaez/ResearchKit into umbrella-headers
# Conflicts:
#	ResearchKit/ResearchKit.h
#	ResearchKit/ResearchKit_Private.h
2017-01-23 19:27:26 -08:00
Ricardo Sanchez-Saez b2ec0051ba [ORKSignatureView] Better fit on iPhone 4 sizes 2017-01-23 19:20:49 -08:00
Shannon Young 2769f3f880 Show a separator between components. 2017-01-23 15:54:59 -08:00
Shannon Young 99195db143 Fix ORKTextAnswerFormat regex to be case sensitive. 2017-01-23 14:39:51 -08:00
Umer Khan 44ba432e8a Merge pull request #854 from Sage-Bionetworks/pr/optional-previous-result-override
Allow optional check of default result source before using previous.
2017-01-23 11:50:13 -08:00
Umer Khan 33673f320a Merge pull request #814 from celteeka/bug/issue812
PR for fixing issue812.
2017-01-23 11:42:13 -08:00
Umer Khan d90c266151 Merge pull request #809 from oliverschaefer/issue784
ORKSignatureView invalid graphics context bugfix
2017-01-23 11:23:31 -08:00
Umer Khan a5115044eb Merge pull request #889 from rsanchezsaez/result-predicate-comment
[ORKResultPredicate] Clarify comment on '+ predicateForConsentWithRes…ultSelector:didConsent:' usage
2017-01-23 11:22:35 -08:00
Umer Khan d0fc7490fd Merge pull request #872 from Sage-Bionetworks/pr/fix-audio-task-start-resume-bug
Fix audio step duplicate file creation bug
2017-01-23 11:22:03 -08:00
Umer Khan e6c4055dec Merge pull request #892 from rsanchezsaez/rss/warning-fixes
[Misc] Fix warnings
2017-01-23 11:21:14 -08:00
Shannon Young 8c1a53cfdf Add answer format for handling a multiple component picker. 2017-01-20 15:48:12 -08:00
Shannon Young 1635216e5c Merge branch 'master' into pr/update-healthkit-answerformat 2017-01-19 13:20:03 -08:00
Ricardo Sanchez-Saez f616083f3c [ORKSignatureView] Increase height and distance of signing line to bottom 2017-01-18 19:54:27 -08:00
DanKeen a4991240e2 Merge pull request #893 from coreygans/patch-1
Update ChartsAndGraphs-template.markdown
2017-01-17 13:41:34 -08:00
coreygans ac0817adf1 Update ChartsAndGraphs-template.markdown
Needed to change the Chart1.png to chart1.png so that the link would resolve.
2017-01-17 10:14:32 -08:00
Ricardo Sanchez-Saez bdf5f25335 [Projects] Update last upgrade checks to Xcode 8.2 2017-01-09 23:35:09 -08:00
Ricardo Sanchez-Saez 849aba6a3d [ORKStepHeaderView] Fix nil attribute warning 2017-01-09 23:26:09 -08:00
Ricardo Sanchez-Saez 5e08420307 [Charts] Add IB sample data source for bar graph
Also, fix an issue in which each data source subclass needs its own 'sharedInstance' method.
2017-01-08 13:23:42 -08:00
Ricardo Sanchez-Saez ad08365514 [Charts] Better encapsulation of IB_DESIGNABLE sample data sources
Also, fix typos due to 'ORKRangedPoint' to 'ORKValueRange' rename.
2017-01-08 11:57:49 -08:00
Shannon Young 1f574ba055 Add missing method call that was lost by merge. 2017-01-06 00:00:28 -08:00
Ricardo Sanchez-Saez 956e338c98 [ORKResultPredicate] Clarify comment on '+ predicateForConsentWithResultSelector:didConsent:' usage 2017-01-05 19:56:56 -08:00
Shannon Young 017a28e736 Added unit test and additional comments for usage. 2017-01-05 14:32:39 -08:00
Shannon Young 48e5e0baf7 consolidate getting or creating a previous result. 2017-01-03 16:50:43 -08:00
Shannon Young 607c96b5d3 Change trailmaking identifiers to ork_extern 2016-12-22 19:51:39 -08:00
Shannon Young 8b7eb71b1f Update externally defined healthkit string enums. 2016-12-22 19:48:32 -08:00
Shannon Young c8a43499c5 Merge branch 'master' into pr/ui-step-footnote
# Conflicts:
#	ResearchKit/Common/ORKInstructionStep.m
#	Testing/ORKTest/ORKTest/MainViewController.m
2016-12-20 16:50:06 -08:00
Umer Khan 02828eff5a Merge pull request #763 from md0u80c9/predicateTests
PredicateTests
2016-12-20 18:14:26 -06:00
Umer Khan 06f16e780b Merge pull request #825 from Sage-Bionetworks/pr/fix-nil-startDate
Always set a date for non-nil ORKResult startDate
2016-12-19 18:02:54 -06:00
Umer Khan e4918e28bd Merge pull request #861 from rsanchezsaez/typos
[Misc] Fix some typos
2016-12-16 15:38:05 -08:00
Shannon Young 919ba1e7b2 Fix the class of the trialmaking task and remove duplicate text. 2016-12-15 11:09:10 -08:00
Shannon Young e8e00503a4 set type for the trailmaking result array of taps. 2016-12-14 23:37:10 -08:00
Shannon Young bf0450af0a Merge branch 'master' into third-party/add-module-trailmaking-test
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2016-12-14 15:32:57 -08:00
Shannon Young 7752710d0a Fix serialization tests 2016-12-14 15:30:58 -08:00
Shannon Young c7ac9c9a35 Merge branch 'master' into pr/update-healthkit-answerformat 2016-12-14 15:17:28 -08:00
Shannon Young e57fa02765 Fix serialization tests 2016-12-14 15:17:03 -08:00
Shannon Young d42cc93683 Merge branch 'master' into pr/ui-completion-step-done-button
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2016-12-14 15:01:14 -08:00
Shannon Young 4ad73b30e4 Fix serialization tests 2016-12-14 14:54:13 -08:00
Shannon Young f885de099b Merge branch 'master' into pr/ui-add-ORKPageStepViewController
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2016-12-14 14:46:40 -08:00
Shannon Young 8abaa9e3d7 Merge branch 'master' into pr/tablestep-source 2016-12-14 14:35:46 -08:00
Shannon Young f50bfc7ff6 Fix serialization tests 2016-12-14 14:28:59 -08:00
Shannon Young c737c14188 Merge branch 'master' into pr/fix-tremor-navigation 2016-12-14 12:24:34 -08:00
Umer Khan 67dbd30e87 Merge pull request #838 from Sage-Bionetworks/pr/ui-step-header-image
Added property to instruction set to allow setting icon image on header view.
2016-12-14 11:40:36 -08:00
Shannon Young 75b7c2d4e3 Merge branch 'master' into pr/ui-step-footnote 2016-12-14 11:31:15 -08:00
Shannon Young 449b4c056f Merge branch 'master' into pr/ui-step-header-image 2016-12-14 11:06:59 -08:00
Umer Khan 92d63e3a8b Merge pull request #862 from rsanchezsaez/serialization-tests
[ORKESerialization] Fix ORKLocation unit tests
2016-12-14 10:44:29 -08:00
Umer Khan 33dd18300d Merge pull request #831 from doreilly/correct-ios10-layout-bugs
Revert ResearchKit PR #806
2016-12-13 14:17:51 -08:00
Umer Khan b77119a510 Merge pull request #842 from 2020Deception/master
fixes crash when tapping results on ORKCatalog
2016-12-13 14:00:20 -08:00
Shannon Young ce0cfe50f3 More project keys 2016-12-13 13:02:54 -08:00
Shannon Young 69160ed4a4 More fixes for project pointers 2016-12-13 12:52:50 -08:00
Shannon Young 8819cefdd7 Remove references to private developer team 2016-12-13 12:46:06 -08:00
Shannon Young d238065e25 Fixed ORKTest serialization for trailmaking objects. 2016-12-13 11:48:20 -08:00
Faraz Hussain 89d1860902 Trail Making Test complete 2016-12-13 07:55:11 -08:00
Roland Rabien ea113f7b66 Make buttons tapped in error turn red 2016-12-12 16:36:28 -08:00
Roland Rabien 677e6db943 Adding the Trails active task to the ORKCatalog app 2016-12-10 08:46:32 -08:00
Roland Rabien aef19ea441 Add ORKTrailmakingStep to ResearchKit 2016-12-09 14:30:21 -08:00
Steve Roy c41536905e Fixed typo. 2016-12-09 10:33:36 -05:00
Steve Roy ba5e03e247 Replaced !(==) by !=. 2016-12-09 10:32:58 -05:00
Steve Roy e88c3ad800 Modify ORKPasscodeStepViewController to account for the flow type possibly being changed to authentication while in a task. 2016-12-09 10:30:46 -05:00
Shannon Young 97b680d61e Constrain the width of the icon image. 2016-12-08 16:39:50 -08:00
Shannon Young 2cb6fea5bd Correct the constraints for icon image with no title. 2016-12-08 14:58:25 -08:00
Shannon Young 2508623efa Added property to instruction set to allow setting icon image on header view.
This allows an instruction step to display an icon image *above* the title and text for the image.
2016-12-08 14:58:24 -08:00
Steve Roy dcf59ccd67 Moved the passcodeFlow property and associated enums out of the internal header. 2016-12-08 15:24:16 -05:00
Erin Mounts 7448431a3a Fix audio step duplicate file creation bug
Start was getting called in viewDidAppear:, creating an audio file, and meanwhile the superclass viewDidAppear: had dispatched a block to main that then saw the recorder was started and called resume, creating another audio file, only one of which was included in the results, leaving the other which the caller didn't know about and wasn't aware needed to be deleted, using up storage space over time. The fix is to use the shouldStartTimerAutomatically flag to let the superclass viewDidAppear: start the recorder, rather than override that method in the audio step view controller to start it explicitly.
2016-12-02 07:56:38 -08:00
Shannon Young 0779f9ca1a Added methods to transform ResearchKit enum to HealthKit enum 2016-12-01 22:51:59 -08:00
Shannon Young 883004f331 Fixed issues with the health kit result unit. 2016-11-18 16:19:34 -08:00
Andrew Hill ed2ffabb8e Change wording of predicate test 3 2016-11-17 06:16:10 +00:00
Shannon Young dd96c41fa5 Add missing HealthKit characteristic types to answer format.
This commit does a few changes:

1. Add the missing characteristics of Fitzpatrick Skin Type and Wheelchair Use to the `ORKHealthKitCharacteristicTypeAnswerFormat`

2. Add `shouldRequestAuthorization` flag to both defined HealthKit answer format subclasses to allow *not* requesting authorization for access to HealthKit if this does not meet the UI/UX requirements for the app.

3. Publicly expose the `impliedAnswerFormat` method to allow for subclasses to replace the default implied answer format with their own representation.
2016-11-15 11:28:18 -08:00
Andrew Hill a4f69dca57 Slight question changes (from R. Sanchez-Saez's review). 2016-11-15 07:33:00 +00:00
Andrew Hill 9eba881ce2 Removed unnecessary optional lines. 2016-11-14 23:55:55 +00:00
Shannon Young aa9596b4bb Fix typos 2016-11-14 11:18:05 -08:00
Andrew Hill e1103d8547 Style changes and fix to regular expressions following review by Ricardo Sanchez-Saez. 2016-11-14 07:06:55 +00:00
Ricardo Sanchez-Saez a0a74e83e7 [ORKDataCollectionTets] Fix '-testDelegateRejectDelivery' tests
Also:
- Rename 'testDelegateRejectDelivery' to 'testDataCollectionDelegateDeliveryRejection'.
- Reorder code for consistency between 'testDataCollection' and 'testDataCollectionDelegateDeliveryRejection'
- Rename 'testDataCollectionWithoutCollector' to 'testDataCollectionWithoutCollectors'.
- Remove needless whitespace and fix padding.
2016-11-13 20:10:59 -08:00
Ricardo Sanchez-Saez 8c8072cdec [ORKOperation] Fix error message typos 2016-11-13 20:04:15 -08:00
Umer Khan 7a4dd58df6 Merge pull request #746 from vtourraine/timed-walk-back-instructions
[ORKTimedWalkStepViewController] Add Turn Around step
2016-11-09 13:10:57 -08:00
Vincent Tourraine 8314e7d9a1 Update Swift syntax 2016-11-09 16:30:07 +01:00
Vincent Tourraine 7696d28f05 Merge upstream master 2016-11-09 16:26:09 +01:00
Umer Khan c4fe887fe5 Merge branch 'master' of https://github.com/ResearchKit/ResearchKit
* 'master' of https://github.com/ResearchKit/ResearchKit:
  templatized arrays
  [Projects] Update to Xcode 8.1 recommended settings
  Implementing @umerkhan-apple comments
  Fix typo in podspec version quoting characters.
  Touch Anywhere Active Task Range of Motion Active Tasks:       - Knee       - Shoulder
2016-11-08 17:44:12 -08:00
Umer Khan f38e31936e Merge pull request #863 from malhal/master
Templatized arrays in ORKOrderedTask.m
2016-11-08 11:58:02 -08:00
Umer Khan 339d364b40 Merge pull request #860 from rsanchezsaez/xcode-8.1
[Projects] Update to Xcode 8.1 recommended settings
2016-11-08 11:56:40 -08:00
Umer Khan 519ad1aaf9 Merge pull request #816 from darrenlevy/range-of-motion
Range of Motion Active Task
2016-11-08 11:52:45 -08:00
Malcolm Hall 203f48f8dc templatized arrays 2016-11-08 17:16:43 +00:00
Ricardo Sanchez-Saez a4cb2723da [ORKDataCollectionTests] Fix some typos 2016-11-08 01:11:11 -08:00
Ricardo Sanchez-Saez cb4e06a4c9 [ORKESerialization] Fix CLCircularRegion unit tests 2016-11-08 00:53:22 -08:00
Ricardo Sanchez-Saez 01f4312dce [Misc] Fix some typos 2016-11-07 22:50:24 -08:00
Ricardo Sanchez-Saez f1457b69b1 [Projects] Update to Xcode 8.1 recommended settings 2016-11-07 22:34:12 -08:00
Ricardo Sanchez-Saez 692ec6e007 [ORKESerialization] Add extra ResearchKit import to silence error 2016-11-07 22:30:33 -08:00
Ricardo Sanchez-Saez 28ceb9ebe5 [Umbrella headers] Change #imports to framework format 2016-11-07 22:14:17 -08:00
Darren Levy 9a69dbbd67 Implementing @umerkhan-apple comments 2016-11-07 18:08:15 -05:00
Shannon Young 9bd4df0996 Fix default initializer warnings. 2016-11-01 12:01:27 -07:00
Shannon Young 7dd98c8033 Fix init for ORKKeyValueStepModifier 2016-11-01 11:04:18 -07:00
Shannon Young b3934066ed Allow setting checkmark color and hide cancel. 2016-10-28 14:29:50 -07:00
Shannon Young 57058a66f5 Allow option check of default result source before using previous. 2016-10-27 12:29:53 -07:00
Umer Khan 0e5f58736a Merge branch 'master' of https://github.com/ResearchKit/ResearchKit
* 'master' of https://github.com/ResearchKit/ResearchKit: (113 commits)
  Updating podspec
  Updating podspec.
  convergence
  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
  ...

# Conflicts:
#	ResearchKit.xcodeproj/project.pbxproj
#	ResearchKit/ActiveTasks/HKSample+ORKJSONDictionary.m
#	ResearchKit/Common/ORKTaskViewController.m
#	ResearchKit/Common/ORKTextButton.h
#	Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m
2016-10-26 13:49:10 -07:00
Shannon Young 737fa76bc9 Fix another typo in comment 2016-10-25 12:05:10 -07:00
Shannon Young a1b84fbf1e Fix typo in comment. 2016-10-25 11:05:40 -07:00
Shannon Young 82eb17de13 Add ORKStepModifier to navigable task.
`ORKStepModifier` was designed to allow optional modifications to an existing step in an  `ORKNavigableOrderedTask`. This allows changing the step based on navigation results. This class is used to fix a bug with the spoken instruction in the tremor task if the participant skips performing the task with one of their hands.
2016-10-25 10:00:04 -07:00
Shannon Young 5c3072b791 Remove TODO warning. 2016-10-24 11:17:30 -07:00
Shannon Young 740a7a4bf7 Fix resultForIdentifier to use reverse-enumeration to get last result. 2016-10-20 13:03:20 -07:00
Shannon Young 5029c7f3a8 Update to ORKTableStepViewController to use plain-style table for single section. 2016-10-20 11:29:13 -07:00
Shannon Young 4cac405737 Update the ORKTableStepViewController to use a protocol for the source
Replace the pointer in `ORKTableStepViewController` to `ORKTableStep` with a protocol. This will allow subclasses of `ORKStep` that do not subclass from `ORKTableStep` to implement the protocol instead. For example, a subclass of `ORKFormStep` that uses custom cells for the display of form items.
2016-10-18 12:11:56 -07:00
Brian Bowman 4025e0f427 fixes crash when tapping results
checks for results instead of assuming they are present
2016-10-15 13:50:04 -04:00
Shannon Young 67643271ae Add footnote label displayed at the bottom of an instruction or form step.
This is useful in displaying disclaimer or copyright information.
2016-10-13 12:40:04 -07:00
Shannon Young e207270b5d Add a flag to allow displaying the continue button in the standard position for the compltion step.
We are finding that many of our users are confused as to how to dismiss a task because the continue button is moved to the upper right corner for the last step.  This commit allows overriding the default behavoir of moving that button and places it in the standard position for a continue button.
2016-10-12 11:26:45 -07:00
Shannon Young cdc8edf78f Track the initial results separately from the mutating results set. 2016-10-03 11:35:42 -07:00
Darren Levy f5b3bbc4dd Touch Anywhere Active Task
Range of Motion Active Tasks:
      - Knee
      - Shoulder

    The Touch Anywhere Active Task was included to allow the user to get their device in the proper position before beginning the Range of Motion Step.

    Range of Motion's result contains two properties: flexed and extended. These correspond to the measurements a doctor may read when using a goniometer.
2016-10-02 15:39:46 -04:00
doreilly ef0164900a Revert ResearchKit PR #806
Reverted Pull Request #806 to fix errors identified in ResearchKit issue #824
2016-09-29 11:46:58 -04:00
Shannon Young b08a2a8627 Merge branch 'master' into pr/ui-add-ORKPageStepViewController
# Conflicts:
#	Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m
2016-09-28 13:21:13 -07:00
Shannon Young 90c2ee018e Fix navigation looping to return unique results for each step.
Previous to this commit, `ORKTaskViewController` only tracked the *last* result, inserting that result into the returned array of results for each instance of the step result with that identifier. This commit fixes that bug so that an `ORKNavigableOrderedTask` with a looping navigation will return the unique result for each loop.
2016-09-28 12:59:53 -07:00
Shannon Young cc1bfbf7eb Always set a date for non-nil ORKResult startDate 2016-09-28 12:57:08 -07:00
Shannon Young ea6b1278ce Change memory copyright to be a learn more link 2016-09-28 12:55:28 -07:00
Shannon Young 956e846eb4 There is a copyright that should be included with the memory game. 2016-09-28 12:55:28 -07:00
Yuan Zhu 358ffcab78 Update README.md 2016-09-26 14:56:43 -07:00
Vincent Tourraine cc6bfe72e5 [ORKTimedWalkStepViewController] Fix progress view layout 2016-09-06 12:01:44 +02:00
Vincent Tourraine 7fe111b750 [ORKTimedWalkStepViewController] Add distinct method for turn around step #746 2016-09-06 11:57:26 +02:00
Vincent Tourraine 043f6258a3 Merge branch 'master' into timed-walk-back-instructions 2016-09-06 11:42:05 +02:00
Sebastian Ricaldoni 2f55113c11 Fixes issue around 'symbol not found...' when subclassing ORKQuestionStepCellHolderView
See https://github.com/ResearchKit/ResearchKit/issues/812
2016-09-01 16:38:56 -03:00
Oliver Schäfer 01e6728926 PR changes 2016-08-31 07:18:12 +02:00
Oliver Schäfer 9f03f45d1b PR changes 2016-08-31 07:17:37 +02:00
Oliver Schäfer 08dfa3fa8d Initial commit 2016-08-31 07:15:06 +02:00
Sam Lichlyter 26f2563a1a Added gesture recognizer to MapView for ORKLocationAnswerFormat 2016-08-30 13:36:24 -07:00
Oliver Schäfer ed1aa683df PR changes 2016-08-27 10:32:20 +02:00
Oliver Schäfer 22589511bb Merge remote-tracking branch 'apple/master' into videoInstructionStep 2016-08-27 10:19:03 +02:00
Oliver Schäfer 4a00ebb8c5 PR changes 2016-08-27 10:15:04 +02:00
Shannon Young 1e3b3f24fa Merge remote-tracking branch 'origin/master' into pr/ui-add-ORKPageStepViewController
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2016-08-26 11:25:40 -07:00
Oliver Schäfer c204c39daa play button with sharp edges 2016-08-23 13:12:58 +02:00
Oliver Schäfer d9198f5d13 PR changes 2016-08-23 13:07:10 +02:00
Oliver Schäfer 8c98958d17 PR changes 2016-08-23 13:02:30 +02:00
Oliver Schäfer cc18572956 Merge remote-tracking branch 'apple/master' 2016-08-21 18:31:30 +02:00
Oliver Schäfer fe2e5820c4 PR changes 2016-08-21 18:27:48 +02:00
Oliver Schäfer 85bea88d6a PR changes 2016-08-21 17:56:43 +02:00
Shannon Young 396b9c8e13 Clean up and clearly differentiate between ORKPageStep and ORKNavigablePageStep 2016-08-18 22:37:44 -07:00
Shannon Young 937e615377 Hide the implementation detail of using a pageTask from the base class of ORKPageStep 2016-08-18 18:58:50 -07:00
Shannon Young 6e052a8b1a Fix back button for the case where this is the first step in the subtask 2016-08-18 17:11:48 -07:00
Steve Moser b71eb952b3 Merge branch 'ResearchKit/master' 2016-08-17 20:24:12 -04:00
Oliver Schäfer c6bb31f514 PR changes 2016-08-17 23:14:53 +02:00
Oliver Schäfer 24c540e70c Merge remote-tracking branch 'apple/master' 2016-08-17 23:11:12 +02:00
Oliver Schäfer 0361f242a0 PR changes 2016-08-17 21:51:45 +02:00
Oliver Schäfer 9d614ded2e Merge branch 'master' into videoInstructionStep 2016-08-17 21:41:35 +02:00
Shannon Young 3e9cc99324 Fixed outdated comment 2016-08-16 13:46:19 -07:00
Shannon Young 43ce339890 Fix merge errors 2016-08-16 13:42:46 -07:00
Shannon Young 3be5fe1925 Merge remote-tracking branch 'origin/master' into pr/ui-add-ORKPageStepViewController
# Conflicts:
#	ResearchKit/ResearchKit.h
#	ResearchKitTests/ORKStepTests.m
2016-08-16 13:27:36 -07:00
Oliver Schäfer 90d403e62b PR changes 2016-07-29 22:54:02 +02:00
Oliver Schäfer 7f0ca4ec88 PR changes 2016-07-29 21:53:13 +02:00
Oliver Schäfer fc36bca1bd PR changes 2016-07-29 21:49:37 +02:00
Oliver Schäfer 951193cdb8 PR changes 2016-07-28 23:13:23 +02:00
Oliver Schäfer 0cb0f5c8ff PR changes 2016-07-28 22:57:23 +02:00
Oliver Schäfer 2ff5a335e2 Initial commit 2016-07-27 17:14:13 +02:00
Oliver Schäfer 6a222529af Merged remote-tracking branch master 2016-07-27 16:32:08 +02:00
Oliver Schäfer fd2edde5a4 Merge remote-tracking branch 'apple/master' 2016-07-27 16:29:37 +02:00
Shannon Young 38c379476b Expose method for going to a given step 2016-07-26 23:33:17 -07:00
Shannon Young 45eb65e721 When going back to an ORKPageStep, go back to the last step with a result. 2016-07-25 13:08:31 -07:00
Shannon Young 7099ed295a Add accessor for getting the individual step results 2016-07-21 16:00:09 -07:00
Shannon Young 963935d659 Allow initializing ORKPageStep with steps as a desgnated initializer 2016-07-21 10:36:02 -07:00
Andrew Hill 1aa39859e9 Added a series of Predicate tests to ORKTest. This should test a range of different predicate conditions and enable us to ensure that Predicates are working as expected.
NB predicate tests which use 'match' don't seem to be working as expected in these tests. In the choice match test we try to match against Cat*; but only an exact match for Cat seems to pass the test.

Test 7 - to check a text string for a match *og causes a SigAbt. This may be that the match strings are incorrect for these tests, or it may be an issue with the match predicate functions.
2016-07-17 04:54:10 +01:00
Shannon Young 64e6c8c9a7 Fix warnings and issues introduced with change to using a task. 2016-07-13 23:55:37 -07:00
Shannon Young 0f3c8a88b8 Update ORKPageStep default initializer to be json serializable. 2016-07-13 15:25:47 -07:00
Shannon Young b596e6580d Include a navigable task in the page step example. 2016-07-13 12:54:44 -07:00
Shannon Young ea848aacf9 Change ORKPageStep to use an ORKTask to navigate. 2016-07-13 12:35:43 -07:00
Shannon Young 99195dde40 Add ORKPageStep and ORKPageStepViewController
The ORKPageStep can be used to group a set of steps together and return a single flattened ORKStepResult for a group of steps. It uses a page step view controller to present the steps.
2016-07-12 18:08:03 -07:00
Yuan Zhu 3ef94e0958 Merge branch 'master' of https://github.com/ResearchKit/ResearchKit
Conflicts:
	ResearchKit/ActiveTasks/ORKHealthQuantityTypeRecorder.m
	Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m
2016-07-06 15:58:23 -07:00
Vincent Tourraine 38a0394005 [ORKTimedWalkStepViewController] Add turn around time limit parameter
As suggested in #606
2016-06-28 17:14:58 +02:00
Vincent Tourraine 541e159792 [ORKTimedWalkStepViewController] Add Turn Around step to Timed Walk active task
Transfer changes from shazino:timed-walk-back-instructions, as discussed in #606
2016-06-28 17:08:07 +02:00
Yuan Zhu 888ff9aea3 Merge branch 'bugfix/26015217' into 'master'
Fix for <rdar://problem/26015217> Building ResearchKit against a iOS 9.0 or high…

Added compile time checks for new iOS 9.0 APIs to that they are called if the base SDK is newer.

See merge request !42
2016-05-18 10:15:14 -07:00
Rajit Shinh 427b1a3aea Fix a few things that Yuan pointed out from code reviewing the changes. 2016-05-05 19:48:14 -07:00
Oliver Schäfer 711f39eca9 Merge remote-tracking branch 'apple/master' 2016-05-03 17:01:49 +02:00
Rajit Shinh 13cfe54a3e Fix for <rdar://problem/26015217> Building ResearchKit against a iOS 9.0 or higher deployment target results in warnings. 2016-05-02 16:40:41 -07:00
Oliver Schäfer 2e6643022e Merge remote-tracking branch 'apple/master' 2016-04-20 15:43:47 +02:00
Oliver Schäfer 44db125626 Merge remote-tracking branch 'apple/master' 2016-03-30 06:45:54 +02:00
Oliver Schäfer c7be2b44ee Merge remote-tracking branch 'apple/master' 2016-03-28 13:20:22 +02:00
Oliver Schäfer a4777c8a42 Merge remote-tracking branch 'apple/master' 2016-01-17 11:34:26 +01:00
Oliver Schäfer 7ceda4a9c3 PR updates 2016-01-12 17:23:12 +01:00
Ryan J. Liljestrom 24a03d6ecf Expose NSRegularExpressionOptions for ORKTextAnswerFormat and via a transparent property in ORKRegistrationStep 2015-11-20 14:31:11 -05:00
4960 changed files with 642213 additions and 158368 deletions
+1
View File
@@ -0,0 +1 @@
LFS-Files/** filter=lfs diff=lfs merge=lfs -text
+2
View File
@@ -0,0 +1,2 @@
[lfs]
fetchexclude = *
-187
View File
@@ -1,187 +0,0 @@
Contributing to the ResearchKit Framework
===========================
This page focuses on code contributions to the existing
codebase. However, other types of contributions are welcome too, in
keeping with the ResearchKit™ framework [best practices](../../wiki/best-practices). For example,
contributions of original free-to-use survey content, back-end integrations,
validation data, and analysis or processing tools are all welcome. Ask
on [researchkit-dev](https://lists.apple.com/mailman/listinfo/researchkit-dev) or [contact us](https://developer.apple.com/contact/researchkit/) for guidance.
Contributing software
---------------------
This page assumes you already know how to check out and build the
code. Contributions to the ResearchKit framework are expected to comply with the
[ResearchKit Contribution Terms and License Policy](#contribution); please familiarize yourself
with this policy prior to submitting a pull request. For any contribution, ensure that you own
the rights or have permission from the copyright holder. (e.g. code, images, surveys, videos
and other content you may include)
To contribute to ResearchKit:
1. [Choose or create an issue to work on.](#create)
2. [Create a personal fork of the ResearchKit framework.](#fork)
3. [Develop your changes in your fork.](#develop)
4. [Run the tests.](#test)
5. [Submit a pull request.](#request)
6. Make any changes requested by the reviewer, and update your pull request as needed.
7. Once accepted, your pull request will be merged into master.
Choosing an issue to work on<a name="create"></a>
----------------------------
To find an issue to work on, either pick something that you need for
your app, or select one of the issues from our [issue list](../../issues). Or,
consider one of the areas where we'd like to extend ResearchKit:
* Faster 'get started' to a useful app
* More active tasks
* Data analysis for active tasks
* More consent sections
* Back end integrations
If in doubt, bring your idea up on [researchkit-dev](https://lists.apple.com/mailman/listinfo/researchkit-dev).
Creating a personal fork<a name="fork"></a>
------------------------
On GitHub, it's easy to create a personal fork. Just tap the "Fork"
button on the top right, and clone your new repository.
Develop your changes in your fork<a name="develop"></a>
---------------------------------
Develop your changes using your normal development process. If you
already have code from an existing project, you may need to adjust its
style to more closely match the [ResearchKit framework coding style](./docs-standalone/coding-style-guide.md).
New components may need to expose new Public or Private
headers. Public headers are for APIs that are likely to be a stable
part of the interface of the ResearchKit framework. Private headers are for APIs that
may need to be accessed from app-side unit tests, or that are more
subject to change than the public interface. All other headers should
be internal, "Project" headers.
Please review and ensure that any contributions you make comply with
the [ResearchKit Contribution Terms and License Policy](#contribution).
Add automated tests for your feature, where it is possible to do
so. For UI driven components where it is harder to write automated
tests, add UI to at least one test application so that the new
features can be reviewed and tested. Consider also whether to add new
code to other existing demo apps to exercise your feature.
When adding UI driven components, make sure that they are accessible.
Follow the steps outlined in the [Best Practices](../../wiki/best-practices)
section under Accessibility. Before submitting the pull request, you should
audit your components with Voice Over (or other relevant assistive technologies)
enabled.
Keep changes that fix different issues separate. For bug fixes,
separate bugs should be submitted as separate pull requests. A good
way to do this is to create a new branch in your fork for each new
bug work on.
Any new user-visible strings should be included in the English
`ResearchKit.strings` table so that they can be picked up and
localized in the next release cycle.
Run the tests<a name="test"></a>
-------------
All unit tests should pass, and there should be no warnings. Also
verify that test apps run on both device and simulator.
Where your code affects UI presentation, also test:
* Multiple device form factors (for instance, iPhone 4S, iPhone 5, iPhone 6, iPhone 6 Plus).
* Dynamic text, especially at the "Large" setting.
* Rotation between portrait and landscape, where appropriate.
You can use the apps in the `Testing` and `samples` directories to
test your changes.
Submit a pull request<a name="request"></a>
---------------------
The reviewers may request changes. Make the changes, and update your
pull request as needed. Reviews will focus on coding style,
correctness, and design consistency.
This process does not take the place of an ethical review, for example
by an institutional review board (IRB) or ethics committee.
After acceptance<a name="after"></a>
----------------
Once your pull request has been accepted, your changes will be merged
to master. You are still responsible for your change after it is
accepted. Stay in contact, in case bugs are detected that may require
your attention.
When the project is next branched for release, your changes will be
incorporated. Queries may come back to you regarding localization,
documentation, or other issues during this process.
Release process
-----------------
The `master` branch is used for work in progress. On `master`:
* All test apps should build and run error free.
* Unit tests should all pass.
* Everything should be continuously in working order in English (the
base language).
The project will make periodic releases. When preparing a stable release, we
will branch from `master` to a convergence branch. During this process,
changes will be made first to the convergence branch, and then merged into
`master`. On the convergence branch, changes will be made only to:
* Fix high priority issues.
* Update documentation.
* Bring localization up to date.
* Ensure good behavior across all supported devices.
After the converging process is completed, we will merge everything to the
`stable` branch and tag with a new release number. The most recent release
will be highlighted in the [README](../..).
ResearchKit Contribution Terms and License Policy<a name="contribution"></a>
=======================================
Thank you for your interest in contributing to the ResearchKit
community. In order to maintain consistency and license compatibility
throughout the project, all contributions must comply with our
licensing policy and terms for contributing code to the ResearchKit
project:
1. If you are submitting a patch to the existing codebase, you
represent that you have the right to license the patch, including
all code and content, to Apple and the community, and agree by
submitting the patch that your changes are
licensed under the existing license terms of the file you are
modifying (i.e., [ResearchKit BSD license](LICENSE)).
You confirm that you have added your copyright (name and year) to
the relevant files for changes that are more than 10 lines of code.
2. If you are submitting a new file for inclusion in the ResearchKit
framework (no code or other content is copied from another source), you
have included your copyright (name and year) and a copy of the ResearchKit
BSD license. By submitting your new file you represent that you have the
right to license your file to Apple and the community, and agree that your
file submission is licensed under the ResearchKit BSD license.
3. If you aren't the author of the patch, you agree that you have
the right to submit the patch, and have included the original copyright
notices and licensing terms with it, to the extent that they exist.
If there wasn't a copyright notice or license, please make a note of it
in your response. Generally we can only take in patches that are
BSD-licensed in order to maintain license compatibility within the project.
-28
View File
@@ -1,28 +0,0 @@
Copyright (c) 2015, 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:
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.
+144 -249
View File
@@ -1,283 +1,178 @@
![ResearchKit](https://github.com/user-attachments/assets/0384c1a6-ec67-45d3-be68-136a2e4cacff)
ResearchKit Framework
===========
![VCS](https://img.shields.io/badge/dvcs-Git%20%2B%20LFS-tomato.svg) ![Platform](https://img.shields.io/cocoapods/p/ResearchKit.svg) ![CocoaPods](https://img.shields.io/cocoapods/v/ResearchKit.svg) ![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-yellow.svg?style=flat) [![License](https://img.shields.io/badge/license-BSD-green.svg?style=flat)](https://github.com/ResearchKit/ResearchKit#license) ![](https://travis-ci.com/ResearchKit/ResearchKit.svg?branch=master)
The *ResearchKit™ framework* is an open source software framework that makes it easy to create apps
for medical research or for other research projects.
# Table of Contents
* [Requirements](#requirements)
* [Documentation](#documentation)
* [Getting Started](#gettingstarted)
* Documentation:
* [Programming Guide](http://researchkit.org/docs/docs/Overview/GuideOverview.html)
* [Framework Reference](http://researchkit.org/docs/index.html)
* [Best Practices](../../wiki/best-practices)
* [Contributing to ResearchKit](CONTRIBUTING.md)
* [Website](http://researchkit.org) and [Blog](http://researchkit.org/blog.html)
* [ResearchKit BSD License](#license)
* [Installing](#installation)
* [ORKCatalog App](#orkcatalog-app)
* [Surveys](#surveys)
* [Consent](#consent)
* [Active Tasks](#active-tasks)
* [Getting Help](#getting-help)
* [License](#license)
Getting More Information
========================
# Requirements <a name="requirements"></a>
* Join the [*ResearchKit* Forum](https://forums.developer.apple.com/community/researchkit) for discussing uses of the *ResearchKit framework and* related projects.
The *ResearchKit framework* codebase supports iOS and requires Xcode 12.0 or newer. The *ResearchKit framework* has a Base SDK version of 13.0.
Use Cases
===========
# Documentation <a name="documentation"></a>
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.
<img width="1000" alt="ebedded-framework" src="https://github.com/ResearchKit/ResearchKit/assets/29615893/19d6edd3-3d95-4416-9ac4-24ccb35e09c2">
Surveys
-------
View the *ResearchKit framework* documentation by setting ResearchKit as your target in Xcode and selecting 'Build Documentation' in the Product menu dropdown.
# Getting Started <a name="gettingstarted"></a>
* [Website](https://www.researchandcare.org)
* [WWDC: ResearchKit and CareKit Reimagined](https://developer.apple.com/videos/play/wwdc2019/217/)
### Install as an embedded framework <a name="installation"></a>
Download the project source code and drag in ResearchKit.xcodeproj. Then, embed *ResearchKit* framework in your app by adding it to the "Frameworks, Libraries, and Embedded Content" section for your target as shown in the figure below.
<img width="1000" alt="ebedded-framework" src="https://github.com/ResearchKit/ResearchKit/assets/29615893/7479f313-ecc7-4d94-8c64-c58ae7362a4d">
### ORKCatalog App <a name="orkcatalog-app"></a>
The included catalog app demonstrates the different modules that are available in *ResearchKit*. Find the
project in ResearchKit's [`samples`](samples) directory.
| | |
|---|---|
| ![catalog-home](https://github.com/ResearchKit/ResearchKit/assets/29615893/45357cf8-17bf-4f38-aebc-bdf1c3395eb5) | ![catalog-survey](https://github.com/ResearchKit/ResearchKit/assets/29615893/a850f20b-7a05-4d14-bc2d-2d6dab7af30d) |
# Surveys <a name="surveys"></a>
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.
modally on an *iPhone* or *iPad*. The example below shows the process to present a height question for a participant to answer.
```swift
import ResearchKit
import ResearchKitUI
let sectionHeaderFormItem = ORKFormItem(sectionTitle: "Your question here.")
Consent
----------------
let heightQuestionFormItem = ORKFormItem(identifier: "heightQuestionFormItem1", text: nil, answerFormat: ORKAnswerFormat.heightAnswerFormat())
heightQuestionFormItem.placeholder = "Tap here"
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.
let formStep = ORKFormStep(identifier: "HeightQuestionIdentifier", title: "Height", text: "Local system")
formStep.formItems = [sectionHeaderFormItem, heightQuestionFormItem]
return formStep
```
Active Tasks
------------
The height question is presented in the figure below.
| | |
|---|---|
| ![height-question](https://github.com/ResearchKit/ResearchKit/assets/29615893/4f425329-83b7-45c3-84f9-58cdbcaf2529) | ![height-question-2](https://github.com/ResearchKit/ResearchKit/assets/29615893/2cc0dc2c-5c2a-4b50-a4be-834363fb64b5) |
# Consent <a name="consent"></a>
The *ResearchKit framework* provides classes that you can customize to explain the
details of your research study and obtain a signature if needed. Use *ResearchKit's* provided classes to quickly welcome, and inform your participants of what the study entails.
```swift
import ResearchKit
import ResearchKitUI
// Welcome page.
let welcomeStep = ORKInstructionStep(identifier: String(describing: Identifier.consentWelcomeInstructionStep))
welcomeStep.iconImage = UIImage(systemName: "hand.wave")
welcomeStep.title = "Welcome!"
welcomeStep.detailText = "Thank you for joining our study. Tap Next to learn more before signing up."
// Before You Join page.
let beforeYouJoinStep = ORKInstructionStep(identifier: String(describing: Identifier.informedConsentInstructionStep))
beforeYouJoinStep.iconImage = UIImage(systemName: "doc.text.magnifyingglass")
beforeYouJoinStep.title = "Before You Join"
let sharingHealthDataBodyItem = ORKBodyItem(text: "The study will ask you to share some of your Health data.",
detailText: nil,
image: UIImage(systemName: "heart.fill"),
learnMoreItem: nil,
bodyItemStyle: .image)
let completingTasksBodyItem = ORKBodyItem(text: "You will be asked to complete various tasks over the duration of the study.",
detailText: nil,
image: UIImage(systemName: "checkmark.circle.fill"),
learnMoreItem: nil,
bodyItemStyle: .image)
let signatureBodyItem = ORKBodyItem(text: "Before joining, we will ask you to sign an informed consent document.",
detailText: nil,
image: UIImage(systemName: "signature"),
learnMoreItem: nil,
bodyItemStyle: .image)
let secureDataBodyItem = ORKBodyItem(text: "Your data is kept private and secure.",
detailText: nil,
image: UIImage(systemName: "lock.fill"),
learnMoreItem: nil,
bodyItemStyle: .image)
beforeYouJoinStep.bodyItems = [
sharingHealthDataBodyItem,
completingTasksBodyItem,
signatureBodyItem,
secureDataBodyItem
]
```
The consent steps are presented in the figure below.
| | |
|---|---|
| ![consent-welcome-page](https://github.com/ResearchKit/ResearchKit/assets/29615893/e6cbbe07-47ed-4bb4-a84a-f3bf612e9122) | ![consent-before-you-join](https://github.com/ResearchKit/ResearchKit/assets/29615893/687fe345-14d9-4356-9c37-c6a2714875ae) |
Vist the `Obtaining Consent`article in ResearchKit's Documentation for
more examples that include signature collection and PDF file storage.
# Active Tasks <a name="active-tasks"></a>
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.
while *iPhone* sensors actively collect data.
ResearchKit active tasks are not diagnostic tools nor medical devices of any kind and output from those active tasks may not be used for diagnosis. Developers and researchers are responsible for complying with all applicable laws and regulations with respect to further development and use of the active tasks.
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>
===============
Requirements
------------
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
```
git clone -b stable https://github.com/ResearchKit/ResearchKit.git
```
Or, for the latest changes, use the `master` branch:
```
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.
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.
### 1. Add the ResearchKit framework to Your Project
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"/>
</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.
<center>
<figure>
<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*.
### 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.
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*
```objc
ORKInstructionStep *myStep =
[[ORKInstructionStep alloc] initWithIdentifier:@"intro"];
myStep.title = @"Welcome to ResearchKit";
```
*Swift*
Use predefined tasks provided by *ResearchKit* to guide your participants through specific actions.
```swift
let myStep = ORKInstructionStep(identifier: "intro")
myStep.title = "Welcome to ResearchKit"
```
import ResearchKit
import ResearchKitUI
import ResearchKitActiveTask
### 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`.
*Objective-C*
```objc
ORKOrderedTask *task =
[[ORKOrderedTask alloc] initWithIdentifier:@"task" steps:@[myStep]];
```
*Swift*
```swift
let task = ORKOrderedTask(identifier: "task", steps: [myStep])
```
### 4. Present the Task
Create a task view controller (`ORKTaskViewController`) and initialize it with your `task`. A task
view controller manages a task and collects the results of each step. In this case, your task view
controller simply displays your instruction step.
*Objective-C*
```objc
ORKTaskViewController *taskViewController =
[[ORKTaskViewController alloc] initWithTask:task taskRunUUID:nil];
taskViewController.delegate = self;
[self presentViewController:taskViewController animated:YES completion:nil];
```
*Swift*
```swift
let taskViewController = ORKTaskViewController(task: task, taskRunUUID: nil)
let orderedTask = ORKOrderedTask.dBHLToneAudiometryTask(withIdentifier: "dBHLToneAudiometryTaskIdentifier",
intendedUseDescription: nil, options: [])
let taskViewController = ORKTaskViewController(task: orderedTask, taskRun: nil)
taskViewController.delegate = self
presentViewController(taskViewController, animated: true, completion: nil)
present(taskViewController, animated: true)
```
The dBHL Tone Audiometry task is presented in the figure below.
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:
| | |
|---|---|
| ![noise-check](https://github.com/ResearchKit/ResearchKit/assets/29615893/d8fb669c-bb60-482d-9a2d-e5b6b6696aa5) | ![dbhl-tone-test](https://github.com/ResearchKit/ResearchKit/assets/29615893/04df862b-46bc-4749-8c3e-02d2e54dbcbf) |
*Objective-C*
# Getting Help <a name="getting-help"></a>
```objc
- (void)taskViewController:(ORKTaskViewController *)taskViewController
didFinishWithReason:(ORKTaskViewControllerFinishReason)reason
error:(NSError *)error {
GitHub is our primary forum for ResearchKit. Feel free to open up issues about questions, problems, or ideas.
ORKTaskResult *taskResult = [taskViewController result];
// You could do something with the result here.
# License <a name="license"></a>
// Then, dismiss the task view controller.
[self dismissViewControllerAnimated:YES completion:nil];
}
```
*Swift*
```swift
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.
dismiss(true, completion: nil)
}
```
If you now run your app, you should see your first *ResearchKit framework* instruction step:
<center>
<figure>
<img src="../../wiki/HelloWorld.png" width="50%" alt="HelloWorld example screenshot" align="middle"/>
</figure>
</center>
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 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:
```
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:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
This project is made available under the terms of a BSD license. See the [LICENSE](LICENSE) file.
-346
View File
@@ -1,346 +0,0 @@
# 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
*ResearchKit 1.3* supports *iOS* and requires *Xcode 7.2* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stability and performance improvements, *ResearchKit 1.3* includes the following new features and enhancements.
- **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 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* (`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 module includes the following steps:
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 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).*
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 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
*ResearchKit 1.2* supports *iOS* and requires *Xcode 7.0* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stability and performance improvements, *ResearchKit 1.2* includes the following new features and enhancements.
- **New Active Tasks**
- **Tower of Hanoi Task**
*Contributed by [coxy1989](https://github.com/coxy1989).*
The *[Tower of Hanoi](https://en.wikipedia.org/wiki/Tower_of_Hanoi#Applications) task* is frequently used in psychological research on problem solving.
It is a mathematical puzzle consisting of three rods and a number of disks of different sizes which can slide onto any rod. The puzzle starts with the disks in a stack in ascending order of size on one rod (the smallest at the top).
The objective of the puzzle is to move the entire stack to another rod, obeying the following rules:
1. Only one disk can be moved at a time.
2. Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack.
3. No disk may be placed on top of a smaller disk.
- **Paced Serial Addition Test Task**
*Contributed by [Julien Therier](https://github.com/julientherier).*
The *Paced Serial Addition Test task* provides adaptations of both the *Paced Auditory Serial Addition Test (PASAT)* and the *Paced Visual Serial Addition Test (PVSAT)*.
The *[PASAT](https://en.wikipedia.org/wiki/Paced_Auditory_Serial_Addition_Test)* is a neuropsychological test used to assess capacity and rate of information processing and sustained and divided attention.
Both tests are documented in the scientific literature ([Fos et al., 2000](http://www.ncbi.nlm.nih.gov/pubmed/11125707); [Nagels et al., 2005](http://www.ncbi.nlm.nih.gov/pubmed/15823678)) as a measure of the [*Multiple Sclerosis Functional Score*](http://www.nationalmssociety.org/For-Professionals/Researchers/Resources-for-Researchers/Clinical-Study-Measures/Multiple-Sclerosis-Functional-Composite-%28MSFC%29).
This task generates a series of single digits (for example, 60 of them), at the specific frequency (for example, one new digit every 2 or 3 seconds). The user must add the newly presented digit to the one prior to it.
- **Timed Walk Task**
*Contributed by [Julien Therier](https://github.com/julientherier).*
The *Timed Walk task* measures gait speed and is an adaptation of the [*Timed 25-Foot Walk*](http://www.nationalmssociety.org/For-Professionals/Researchers/Resources-for-Researchers/Clinical-Study-Measures/Timed-25-Foot-Walk-%28T25-FW%29) in the context of *multiple sclerosis*.
Gait speed has been demonstrated to be a useful and reliable functional measure of walking ability. When administering the *Timed Walk Task*, patients are allowed to use assistive devices (canes, crutches, walkers).
- **Charts Module**
*Contributed by [coxy1989](https://github.com/coxy1989) and [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
A *Charts module* has been implemented. 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*. It doesn't automatically connect with any other *ResearchKit* module: the developer has to supply the data to be displayed through the views' `dataSources`, which allows for maximum flexibility.
- **Other Improvements**
- **Scale Answer Format**
*Contributed by [Apple Inc](https://github.com/researchkit).*
*Discrete scales* now support *text choice* labels, and all *scales* support images in place of the minimum and maximum range labels.
- **Result Predicates**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
The predicate-building methods in `ORKResultPredicate` now use the new `ORKResultSelector` class for unequivocally identifying a *question step result* or a *form item result*.
This eliminates ambiguity when matching results with the same inner scope identifier. For example, a *form item result* can have the same identifier as a *question step result* or as another *form item result* in a different *form step*, and you can now match them separately.
## ResearchKit 1.1 Release Notes
*ResearchKit 1.1* supports *iOS* and requires *Xcode 6.3* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stability and performance improvements, *ResearchKit 1.1* includes the following new features and enhancements.
- **Navigable Ordered Task**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
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 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**
- **Reaction Time Task**
*Contributed by [coxy1989](https://github.com/coxy1989).*
The *Reaction Time Task* is an adaptation of the [*Simple Reaction Time test (SRT)*](http://www.cambridgecognition.com/tests/simple-reaction-time-srt). *SRT* measures reaction time through delivery of a known stimulus to a known location to elicit a known response.
This test is deployed in a range of research questions across fields including medicine, sports science and psychology.
Although it classically involves pressing the space bar or clicking a mouse in response to an event on screen, the *ResearchKit* implementation relies on the study participant shaking the device when she sees a blue circle on the screen, which we think is more correlatable to a true stimulus reaction test.
- **Tone Audiometry Task**
*Contributed by [Vincent Tourraine](https://github.com/vtourraine).*
The *Tone Audiometry Task* is an adaptation of the [*Pure Tone Audiometry test (PTA)*](https://en.wikipedia.org/wiki/Pure_tone_audiometry). *PTA* is a key hearing test used to identify hearing threshold levels of an individual, enabling determination of the degree, type and configuration of a hearing loss.
The *ResearchKit* implementation generates a series of pure sinusoid sounds, with different frequencies and on different channels (left or right). The test starts at the minimum volume and is gradually increased until the participant perceives it and taps a button. At that time, the current sound amplitude, frequency and channel are recorded.
- **Scale Answer Format Enhancements**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez) and [Bruce Duncan](https://github.com/brucehappy).*
Support for discrete and continuous *vertical scales* has been added. Some questions, like mood measurement or symptom severity measurement queries may be more naturally presented using a *vertical scale*.
The *Scale Answer Format* has also been improved by making it usable within forms.
- **Image Capture Step**
*Contributed by [Bruce Duncan](https://github.com/brucehappy).*
An *Image Capture Step* has been added. The researcher can ask the participant to take pictures of relevant body parts. The researcher can provide a body part image template to facilitate the scale and orientation of the taken pictures.
- **iPad Support**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez) and [Apple Inc](https://github.com/researchkit).*
*iPad support* for all orientations has been implemented.
- **iPhone Landscape Support**
*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.
-16
View File
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:ResearchKit.xcodeproj">
</FileRef>
<FileRef
location = "group:Testing/ORKTest/ORKTest.xcodeproj">
</FileRef>
<FileRef
location = "group:samples/ORKCatalog/ORKCatalog.xcodeproj">
</FileRef>
<FileRef
location = "group:samples/ORKSample/ORKSample.xcodeproj">
</FileRef>
</Workspace>
-15
View File
@@ -1,15 +0,0 @@
Pod::Spec.new do |s|
s.name = 'ResearchKit'
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/'
s.license = { :type => 'BSD', :file => 'LICENSE' }
s.author = { 'researchkit.org' => 'http://researchkit.org' }
s.source = { :git => 'https://github.com/ResearchKit/ResearchKit.git', :tag => s.version.to_s }
s.public_header_files = `./scripts/find_headers.rb --public --private`.split("\n")
s.source_files = 'ResearchKit/**/*.{h,m,swift}'
s.resources = 'ResearchKit/**/*.{fsh,vsh}', 'ResearchKit/Animations/**/*.m4v', 'ResearchKit/Artwork.xcassets', 'ResearchKit/Localized/*.lproj'
s.platform = :ios, '8.2'
s.requires_arc = true
end
File diff suppressed because it is too large Load Diff
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:ResearchKit.xcodeproj">
</FileRef>
</Workspace>
@@ -1,99 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0900"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B183A4731A8535D100C76870"
BuildableName = "ResearchKit.framework"
BlueprintName = "ResearchKit"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "86CC8E991AC09332001CCD89"
BuildableName = "ResearchKitTests.xctest"
BlueprintName = "ResearchKitTests"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B183A4731A8535D100C76870"
BuildableName = "ResearchKit.framework"
BlueprintName = "ResearchKit"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B183A4731A8535D100C76870"
BuildableName = "ResearchKit.framework"
BlueprintName = "ResearchKit"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B183A4731A8535D100C76870"
BuildableName = "ResearchKit.framework"
BlueprintName = "ResearchKit"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0900"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B18FF3A41A9FE25700C0C3B0"
BuildableName = "docs"
BlueprintName = "docs"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B18FF3A41A9FE25700C0C3B0"
BuildableName = "docs"
BlueprintName = "docs"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B18FF3A41A9FE25700C0C3B0"
BuildableName = "docs"
BlueprintName = "docs"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,35 +0,0 @@
/*
Copyright (c) 2015, 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:
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.
*/
// Shared header for accessibility functionality.
#import "ORKAccessibilityFunctions.h"
#import "ORKLineGraphAccessibilityElement.h"
#import "UIView+ORKAccessibility.h"
@@ -1,58 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKDefines.h"
#import "ORKHelpers_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKScaleSlider;
// Used to properly format values from the ORKScaleSlider.
ORK_EXTERN NSString *ORKAccessibilityFormatScaleSliderValue(CGFloat value, ORKScaleSlider *slider);
ORK_EXTERN NSString *ORKAccessibilityFormatContinuousScaleSliderValue(CGFloat value, ORKScaleSlider *slider);
// Performs a block on the main thread after a delay. If Voice Over is not running, the block is performed immediately.
ORK_EXTERN void ORKAccessibilityPerformBlockAfterDelay(NSTimeInterval delay, void(^block)(void));
// Convenience for posting an accessibility notification after a delay.
ORK_INLINE void ORKAccessibilityPostNotificationAfterDelay(UIAccessibilityNotifications notification, _Nullable id argument, NSTimeInterval delay) {
ORKAccessibilityPerformBlockAfterDelay(delay, ^{
UIAccessibilityPostNotification(notification, argument);
});
}
// 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
@@ -1,93 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
#import "ORKScaleSlider.h"
#import "ORKScaleSliderView.h"
#import "ORKAnswerFormat_Internal.h"
#import "ORKAccessibilityFunctions.h"
#import "UIView+ORKAccessibility.h"
NSString *ORKAccessibilityFormatScaleSliderValue(CGFloat value, ORKScaleSlider *slider) {
ORKScaleSliderView *sliderView = (ORKScaleSliderView *)[slider ork_superviewOfType:[ORKScaleSliderView class]];
if (!slider || !sliderView) {
return nil;
}
NSNumber *normalizedValue = [sliderView.formatProvider normalizedValueForNumber:@(value)];
return [sliderView.formatProvider localizedStringForNumber:normalizedValue];
}
NSString *ORKAccessibilityFormatContinuousScaleSliderValue(CGFloat value, ORKScaleSlider *slider) {
ORKScaleSliderView *sliderView = (ORKScaleSliderView *)[slider ork_superviewOfType:[ORKScaleSliderView class]];
if (!slider || !sliderView) {
return nil;
}
return [sliderView.formatProvider localizedStringForNumber:@(value)];
}
void ORKAccessibilityPerformBlockAfterDelay(NSTimeInterval delay, void(^block)(void)) {
if (block == nil) {
return;
}
if (!UIAccessibilityIsVoiceOverRunning()) {
delay = 0;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
block();
});
}
NSString *_ORKAccessibilityStringForVariables(NSInteger numParameters, NSString *baseString, ...) {
NSMutableArray *variables = [[NSMutableArray alloc] init];
NSInteger paramIndex = 0;
va_list args;
va_start(args, baseString);
for (__unsafe_unretained NSString *variable = baseString;
paramIndex < numParameters;
variable = va_arg(args, __unsafe_unretained NSString *), paramIndex++) {
if ([variable isKindOfClass:[NSString class]] && variable.length > 0) {
[variables addObject:variable];
}
}
va_end(args);
return [variables componentsJoinedByString:@", "];
}
@@ -1,43 +0,0 @@
/*
Copyright (c) 2015, 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:
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 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
@@ -1,66 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "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 {
self = [super initWithAccessibilityContainer:container];
if (self) {
self.index = index;
self.maxIndex = maxIndex;
}
return self;
}
- (CGRect)accessibilityFrame {
if (self.maxIndex == 0) {
return [super accessibilityFrame];
}
CGRect containerFrame = [self.accessibilityContainer frame];
CGFloat height = CGRectGetHeight(containerFrame);
CGFloat width = CGRectGetWidth(containerFrame) / self.maxIndex;
CGFloat x = self.index * width;
return UIAccessibilityConvertFrameToScreenCoordinates(CGRectMake(x, 0, width, height), self.accessibilityContainer);
}
@end
@@ -1,43 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
NS_ASSUME_NONNULL_BEGIN
@interface UIView (ORKAccessibility)
- (nullable UIView *)ork_superviewOfType:(nullable Class)aClass;
@end
NS_ASSUME_NONNULL_END
@@ -1,52 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "UIView+ORKAccessibility.h"
@implementation UIView (ORKAccessibility)
- (UIView *)ork_superviewOfType:(Class)aClass {
if (aClass == nil) {
return nil;
}
id superview = [self superview];
if (superview == nil) {
return nil;
} else if ([superview isKindOfClass:aClass]) {
return superview;
}
return [superview ork_superviewOfType:aClass];
}
@end
@@ -1,43 +0,0 @@
/*
Copyright (c) 2015, 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:
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 CoreLocation;
NS_ASSUME_NONNULL_BEGIN
@interface CLLocation (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary;
@end
NS_ASSUME_NONNULL_END
@@ -1,73 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "CLLocation+ORKJSONDictionary.h"
#import "ORKHelpers_Internal.h"
@implementation CLLocation (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary {
CLLocationCoordinate2D coord = self.coordinate;
CLLocationDistance altitude = self.altitude;
CLLocationAccuracy horizAccuracy = self.horizontalAccuracy;
CLLocationAccuracy vertAccuracy = self.verticalAccuracy;
CLLocationDirection course = self.course;
CLLocationSpeed speed = self.speed;
NSDate *timestamp = self.timestamp;
CLFloor *floor = self.floor;
NSMutableDictionary *dictionary = [@{ @"timestamp": ORKStringFromDateISO8601(timestamp) } mutableCopy];
if (horizAccuracy >= 0) {
dictionary[@"coordinate"] = @{ @"latitude": [NSDecimalNumber numberWithDouble:coord.latitude],
@"longitude": [NSDecimalNumber numberWithDouble:coord.longitude]};
dictionary[@"horizontalAccuracy"] = [NSDecimalNumber numberWithDouble:horizAccuracy];
}
if (vertAccuracy >= 0) {
dictionary[@"altitude"] = [NSDecimalNumber numberWithDouble:altitude];
dictionary[@"verticalAccuracy"] = [NSDecimalNumber numberWithDouble:vertAccuracy];
}
if (course >= 0) {
dictionary[@"course"] = [NSDecimalNumber numberWithDouble:course];
}
if (speed >= 0) {
dictionary[@"speed"] = [NSDecimalNumber numberWithDouble:speed];
}
if (floor) {
dictionary[@"floor"] = @(floor.level);
}
return dictionary;
}
@end
@@ -1,43 +0,0 @@
/*
Copyright (c) 2015, 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:
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 CoreMotion;
NS_ASSUME_NONNULL_BEGIN
@interface CMAccelerometerData (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary;
@end
NS_ASSUME_NONNULL_END
@@ -1,46 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "CMAccelerometerData+ORKJSONDictionary.h"
@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]
};
return dictionary;
}
@end
@@ -1,43 +0,0 @@
/*
Copyright (c) 2015, 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:
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 CoreMotion;
NS_ASSUME_NONNULL_BEGIN
@interface CMDeviceMotion (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary;
@end
NS_ASSUME_NONNULL_END
@@ -1,76 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "CMDeviceMotion+ORKJSONDictionary.h"
@implementation CMDeviceMotion (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary {
CMQuaternion attitude = self.attitude.quaternion;
CMRotationRate rotationRate = self.rotationRate;
CMAcceleration gravity = self.gravity;
CMAcceleration userAccel = self.userAcceleration;
CMCalibratedMagneticField field = self.magneticField;
NSDictionary *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]
}
};
return dictionary;
}
@end
@@ -1,43 +0,0 @@
/*
Copyright (c) 2015, 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:
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 CoreMotion;
NS_ASSUME_NONNULL_BEGIN
@interface CMMotionActivity (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary;
@end
NS_ASSUME_NONNULL_END
@@ -1,84 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "CMMotionActivity+ORKJSONDictionary.h"
#import "ORKHelpers_Internal.h"
static NSString *const ActivityUnknown = @"unknown";
static NSString *const ActivityStationary = @"stationary";
static NSString *const ActivityWalking = @"walking";
static NSString *const ActivityRunning = @"running";
static NSString *const ActivityAutomotive = @"automotive";
static NSString *const StartDateKey = @"startDate";
static NSString *const EndDateKey = @"endDate";
static NSString *stringFromActivityConfidence(CMMotionActivityConfidence confidence) {
NSDictionary *confidences = @{@(CMMotionActivityConfidenceHigh): @"high",
@(CMMotionActivityConfidenceMedium): @"medium",
@(CMMotionActivityConfidenceLow): @"low"};
return confidences[@(confidence)];
}
static NSArray *activityArray(CMMotionActivity *activity) {
NSMutableArray *array = [NSMutableArray array];
if (activity.unknown) {
[array addObject:ActivityUnknown];
}
if (activity.stationary) {
[array addObject:ActivityStationary];
}
if (activity.walking) {
[array addObject:ActivityWalking];
}
if (activity.running) {
[array addObject:ActivityRunning];
}
if (activity.automotive) {
[array addObject:ActivityAutomotive];
}
return array;
}
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)};
}
@end
@@ -1,43 +0,0 @@
/*
Copyright (c) 2015, 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:
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 CoreMotion;
NS_ASSUME_NONNULL_BEGIN
@interface CMPedometerData (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary;
@end
NS_ASSUME_NONNULL_END
@@ -1,49 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "CMPedometerData+ORKJSONDictionary.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" ]) {
[dictionary setValue:[self valueForKey:key] forKey:key];
}
return dictionary;
}
@end
@@ -1,62 +0,0 @@
/*
Copyright (c) 2015, 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:
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 HealthKit;
NS_ASSUME_NONNULL_BEGIN
typedef NS_OPTIONS(NSInteger, ORKSampleJSONOptions) {
ORKSampleIncludeMetadata = 0x1,
ORKSampleIncludeSource = 0x2,
ORKSampleIncludeUUID = 0x4
};
/**
JSON serialization aid for HKSample.
*/
@interface HKSample (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(nullable HKUnit *)unit;
@end
/**
JSON serialization aid for HKCorrelation.
*/
@interface HKCorrelation (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options sampleTypes:(NSArray *)sampleTypes units:(NSArray *)units;
@end
NS_ASSUME_NONNULL_END
@@ -1,169 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "HKSample+ORKJSONDictionary.h"
#import "ORKHelpers_Internal.h"
static NSString *const HKSampleIdentifierKey = @"type"; // For compatibility with Health XML export
static NSString *const HKUUIDKey = @"uuid";
static NSString *const HKSampleStartDateKey = @"startDate";
static NSString *const HKSampleEndDateKey = @"endDate";
static NSString *const HKSampleValue = @"value";
static NSString *const HKMetadataKey = @"metadata";
static NSString *const HKSourceKey = @"source";
static NSString *const HKUnitKey = @"unit";
static NSString *const HKCorrelatedObjectsKey = @"objects";
// static NSString *const HKSourceIdentifierKey = @"sourceBundleIdentifier";
@implementation HKSample (ORKJSONDictionary)
- (NSMutableDictionary *)ork_JSONMutableDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:12];
// Type identification
HKSampleType *sampleType = [self sampleType];
mutableDictionary[HKSampleIdentifierKey] = [sampleType identifier];
// consider adding @"class" : NSStringFromClass(sampleType) ?
// Start and end dates
NSDate *startDate = [self startDate];
if (startDate) {
mutableDictionary[HKSampleStartDateKey] = ORKStringFromDateISO8601(startDate);
}
NSDate *endDate = [self endDate];
if (endDate) {
mutableDictionary[HKSampleEndDateKey] = ORKStringFromDateISO8601(endDate);
}
if (unit) {
mutableDictionary[HKUnitKey] = [unit unitString];
}
if ((options & ORKSampleIncludeUUID)) {
NSUUID *uuid = [self UUID];
if (uuid) {
mutableDictionary[HKUUIDKey] = uuid.UUIDString;
}
}
if ( (options & ORKSampleIncludeMetadata) && self.metadata.count > 0) {
NSMutableDictionary *metadata = [self.metadata mutableCopy];
for (NSString *k in metadata) {
id obj = metadata[k];
if ([obj isKindOfClass:[NSDate class]]) {
metadata[k] = ORKStringFromDateISO8601(obj);
}
}
mutableDictionary[HKMetadataKey] = metadata;
}
if (options & ORKSampleIncludeSource) {
HKSource *source = [[self sourceRevision] source];
if (source.name) {
mutableDictionary[HKSourceKey] = source.name;
}
}
return mutableDictionary;
}
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
return [self ork_JSONMutableDictionaryWithOptions:options unit:unit];
}
@end
@interface HKCategorySample (ORKJSONDictionary)
@end
@implementation HKCategorySample (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
NSMutableDictionary *dictionary = [self ork_JSONMutableDictionaryWithOptions:options unit:unit];
NSInteger value = self.value;
dictionary[HKSampleValue] = @(value);
return dictionary;
}
@end
@interface HKQuantitySample (ORKJSONDictionary)
@end
@implementation HKQuantitySample (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
NSMutableDictionary *dictionary = [self ork_JSONMutableDictionaryWithOptions:options unit:unit];
HKQuantity *quantity = [self quantity];
double value = [quantity doubleValueForUnit:unit];
dictionary[HKSampleValue] = @(value);
return dictionary;
}
@end
@implementation HKCorrelation (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options sampleTypes:(NSArray *)sampleTypes units:(NSArray *)units {
NSMutableDictionary *mutableDictionary = [self ork_JSONMutableDictionaryWithOptions:options unit:nil];
// The correlated objects
NSMutableArray *correlatedObjects = [NSMutableArray arrayWithCapacity:sampleTypes.count];
for (HKSample *sample in self.objects) {
NSUInteger idx = [sampleTypes indexOfObject:sample.sampleType];
if (idx == NSNotFound) {
continue;
}
[correlatedObjects addObject:[sample ork_JSONDictionaryWithOptions:options unit:units[idx]]];
}
mutableDictionary[HKCorrelatedObjectsKey] = correlatedObjects;
return mutableDictionary;
}
@end
@@ -1,69 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKAccelerometerRecorder` class represents a recorder that requests and collects raw accelerometer data from CoreMotion at a fixed frequency.
The accelerometer recorder continues to record when the application enters the
background by using the background task support provided by UIApplication.
*/
ORK_CLASS_AVAILABLE
@interface ORKAccelerometerRecorder : ORKRecorder
/**
The frequency of accelerometer data collected from CoreMotion, in hertz (Hz).
*/
@property (nonatomic, readonly) double frequency;
/**
Returns an initialized accelerometer recorder using the specified frequency.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param frequency The frequency of accelerometer data collected from CoreMotion, in hertz (Hz).
@param step The step that requested this recorder.
@param outputDirectory The directory in which the accelerometer data should be stored.
@return An initialized accelerometer recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier
frequency:(double)frequency
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory;
@end
NS_ASSUME_NONNULL_END
@@ -1,231 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKAccelerometerRecorder.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Internal.h"
#import "ORKHelpers_Internal.h"
#import "CMAccelerometerData+ORKJSONDictionary.h"
@import CoreMotion;
@interface ORKAccelerometerRecorder () {
ORKDataLogger *_logger;
NSError *_recordingError;
}
@property (nonatomic, strong) CMMotionManager *motionManager;
@property (nonatomic) NSTimeInterval uptime;
@end
@implementation ORKAccelerometerRecorder
- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)frequency step:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier step:step outputDirectory:outputDirectory];
if (self) {
self.frequency = frequency;
self.continuesInBackground = YES;
}
return self;
}
- (void)dealloc {
[_logger finishCurrentLog];
}
- (NSString *)recorderType {
return @"accel";
}
- (void)setFrequency:(double)frequency {
if (frequency <= 0) {
_frequency = 1;
} else {
_frequency = frequency;
}
}
- (CMMotionManager *)createMotionManager {
return [[CMMotionManager alloc] init];
}
- (void)start {
[super start];
self.motionManager = [self createMotionManager];
if (!_logger) {
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
if (!_logger) {
[self finishRecordingWithError:error];
return;
}
}
if (!self.motionManager || !self.motionManager.accelerometerAvailable) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder": self}];
[self finishRecordingWithError:error];
return;
}
self.motionManager.accelerometerUpdateInterval = 1.0 / _frequency;
self.uptime = [NSProcessInfo processInfo].systemUptime;
[self.motionManager stopAccelerometerUpdates];
[self.motionManager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init] withHandler:^(CMAccelerometerData *data, NSError *error) {
BOOL success = NO;
if (data) {
success = [_logger append:[data ork_JSONDictionary] error:&error];
}
if (!success) {
dispatch_async(dispatch_get_main_queue(), ^{
_recordingError = error;
[self stop];
});
}
}];
}
- (NSDictionary *)userInfo {
return @{ @"frequency": @(self.frequency) };
}
- (void)stop {
[self doStopRecording];
[_logger finishCurrentLog];
NSError *error = _recordingError;
_recordingError = nil;
__block NSURL *fileUrl = nil;
[_logger enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
fileUrl = logFileUrl;
} error:&error];
[self reportFileResultWithFile:fileUrl error:error];
[super stop];
}
- (void)doStopRecording {
if (self.isRecording) {
[self.motionManager stopAccelerometerUpdates];
self.motionManager = nil;
}
}
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:nil];
}
- (void)reset {
[super reset];
_logger = nil;
}
- (BOOL)isRecording {
return self.motionManager.accelerometerActive;
}
- (NSString *)mimeType {
return @"application/json";
}
@end
@implementation ORKAccelerometerRecorderConfiguration
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
- (instancetype)initWithIdentifier:(NSString *)identifier {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use subclass designated initializer" userInfo:nil];
}
- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)frequency {
self = [super initWithIdentifier:identifier];
if (self) {
_frequency = frequency;
}
return self;
}
#pragma clang diagnostic pop
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKAccelerometerRecorder alloc] initWithIdentifier:self.identifier
frequency:self.frequency
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_DOUBLE(aDecoder, frequency);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_DOUBLE(aCoder, frequency);
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
(self.frequency == castObject.frequency));
}
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionCoreMotionAccelerometer;
}
@end
-219
View File
@@ -1,219 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
@import HealthKit;
#import <ResearchKit/ORKStep.h>
@class ORKRecorderConfiguration;
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKActiveStep` class is the base class for steps in active tasks, which
are steps that collect sensor data in a semi-controlled environment, as opposed
to the purely passive data collection enabled by HealthKit, or the more subjective data
collected when users fill in surveys.
In addition to the behaviors of `ORKStep`, active steps have the concept of
life cycle, which includes a defined start and finish.
The ResearchKit framework provides built-in behaviors that allow active steps to play voice prompts, speak a count down, and have a
defined duration.
To present an active step in your app, it's likely that you will subclass `ORKActiveStep` and
`ORKActiveStepViewController` to present custom UI and custom
prompts. For example subclasses, see `ORKSpatialSpanMemoryStep` or `ORKFitnessStep`.
Active steps may also need `ORKResult` subclasses to record their results
if these don't come purely from recorders.
If you develop a new active step subclass, consider contributing your
code to the ResearchKit project so that it's available for others to use in
their studies.
See also: `ORKActiveStepViewController`
*/
ORK_CLASS_AVAILABLE
@interface ORKActiveStep : ORKStep
/**
The duration of the step in seconds.
If the step duration is greater than zero, a built-in timer starts when the
step starts. If `shouldStartTimerAutomatically` is set, the timer
starts when the step's view appears. When the timer expires, a sound or
vibration may be played. If `shouldContinueOnFinish` is set, the step
automatically navigates forward when the timer expires.
The default value of this property is `0`, which disables the built-in timer.
See also: `ORKActiveStepViewController`
*/
@property (nonatomic) NSTimeInterval stepDuration;
/**
A Boolean value indicating whether to show a view with a default timer.
The default timer UI is not used in any of the current predefined tasks,
but it can be displayed in a simple active task that does not require custom
UI and needs only a count down timer on screen during data collection.
Note that this property is ignored if `stepDuration` is `0`.
The default value of this property is `YES`.
*/
@property (nonatomic) BOOL shouldShowDefaultTimer;
/**
A Boolean value indicating whether to speak the last few seconds 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 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.
Usually the explicit action needs to come from custom UI in an
`ORKActiveStepViewController` subclass.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldStartTimerAutomatically;
/**
A Boolean value indicating whether to play a default sound when the step starts.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldPlaySoundOnStart;
/**
A Boolean value indicating whether to play a default sound when the step finishes.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldPlaySoundOnFinish;
/**
A Boolean value indicating whether to vibrate when the step starts.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldVibrateOnStart;
/**
A Boolean value indicating whether to vibrate when the step finishes.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldVibrateOnFinish;
/**
A Boolean value indicating whether the Next button should double as a skip action before
the step finishes.
When the value of this property is `YES`, the ResearchKit framework hides the skip button and makes the Next button function as a skip button when the step has not yet finished.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldUseNextAsSkipButton;
/**
A Boolean value indicating whether to transition automatically when the step finishes.
When the value of this property is `YES`, the active step view controller automatically performs the
continue action when the `[ORKActiveStepViewController finish]` method
is called.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldContinueOnFinish;
/**
Localized text that represents an instructional voice prompt.
Instructional speech begins when the step starts. If VoiceOver is active,
the instruction is spoken by VoiceOver.
*/
@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.
The image can be stretched to fit the available space. When choosing a size
for this asset, be sure to take into account the variations in device form factors.
*/
@property (nonatomic, strong, nullable) UIImage *image;
/**
An array of recorder configurations that define the parameters for recorders to be
run during a step to collect sensor or other data.
If you want to collect data from sensors while the step is in progress,
add one or more recorder configurations to the array. The active step view
controller instantiates recorders and collates their results as children
of the step result.
The set of recorder configurations is scanned when populating the
`requestedHealthKitTypesForReading` and `requestedPermissions` properties.
See also: `ORKRecorderConfiguration` and `ORKRecorder`.
*/
@property (nonatomic, copy, nullable) NSArray<ORKRecorderConfiguration *> *recorderConfigurations;
@end
NS_ASSUME_NONNULL_END
-191
View File
@@ -1,191 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKActiveStep.h"
#import "ORKActiveStep_Internal.h"
#import "ORKActiveStepViewController.h"
#import "ORKRecorder_Private.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@implementation ORKActiveStep
+ (Class)stepViewControllerClass {
return [ORKActiveStepViewController class];
}
- (BOOL)startsFinished {
return (_stepDuration == 0);
}
- (BOOL)hasCountDown {
return (_stepDuration > 0) && _shouldShowDefaultTimer;
}
- (BOOL)hasTitle {
NSString *title = self.title;
return (title != nil && title.length > 0);
}
- (BOOL)hasText {
NSString *text = self.text;
return (text != nil && text.length > 0);
}
- (BOOL)hasVoice {
BOOL hasSpokenInstruction = (_spokenInstruction != nil && _spokenInstruction.length > 0);
BOOL hasFinishedSpokenInstruction = (_finishedSpokenInstruction != nil && _finishedSpokenInstruction.length > 0);
return (hasSpokenInstruction || hasFinishedSpokenInstruction);
}
- (BOOL)isRestorable {
return NO;
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = YES;
}
return self;
}
- (instancetype)copyWithZone:(NSZone *)zone {
ORKActiveStep *step = [super copyWithZone:zone];
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;
step.shouldVibrateOnStart = self.shouldVibrateOnStart;
step.shouldVibrateOnFinish = self.shouldVibrateOnFinish;
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;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self ) {
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);
ORK_DECODE_BOOL(aDecoder, shouldVibrateOnStart);
ORK_DECODE_BOOL(aDecoder, shouldVibrateOnFinish);
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);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
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);
ORK_ENCODE_BOOL(aCoder, shouldVibrateOnStart);
ORK_ENCODE_BOOL(aCoder, shouldVibrateOnFinish);
ORK_ENCODE_BOOL(aCoder, shouldUseNextAsSkipButton);
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);
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__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) &&
(self.shouldVibrateOnFinish == castObject.shouldVibrateOnFinish) &&
(self.shouldContinueOnFinish == castObject.shouldContinueOnFinish) &&
(self.shouldUseNextAsSkipButton == castObject.shouldUseNextAsSkipButton));
}
- (NSSet<HKObjectType *> *)requestedHealthKitTypesForReading {
NSMutableSet<HKObjectType *> *set = [NSMutableSet set];
for (ORKRecorderConfiguration *config in self.recorderConfigurations) {
NSSet<HKObjectType *> *subset = [config requestedHealthKitTypesForReading];
if (subset) {
[set unionSet:subset];
}
}
return set;
}
- (ORKPermissionMask)requestedPermissions {
ORKPermissionMask mask = [super requestedPermissions];
for (ORKRecorderConfiguration *config in self.recorderConfigurations) {
mask |= [config requestedPermissionMask];
}
return mask;
}
@end
@@ -1,65 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
#import "ORKLabel.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKQuantityLabel : ORKLabel
@end
@interface ORKActiveStepQuantityView : UIView
@property (nonatomic, strong, nullable) NSString *title;
@property (nonatomic, strong, nullable) NSString *value;
@property (nonatomic, strong, nullable) UIImage *image;
@property (nonatomic) BOOL enabled;
@property (nonatomic, strong, readonly, nullable) UILabel *titleLabel;
@property (nonatomic, strong, readonly, nullable) UILabel *valueLabel;
@end
@interface ORKQuantityPairView : UIView
@property (nonatomic, strong, nullable) ORKActiveStepQuantityView *leftView;
@property (nonatomic, strong, nullable) ORKActiveStepQuantityView *rightView;
@property (nonatomic, assign) BOOL keylineHidden;
@end
NS_ASSUME_NONNULL_END
@@ -1,333 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKActiveStepQuantityView.h"
#import "ORKSubheadlineLabel.h"
#import "ORKTintedImageView.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@implementation ORKQuantityLabel
+ (UIFont *)defaultFont {
return ORKTimeFontForSize(35);
}
@end
@implementation ORKActiveStepQuantityView {
ORKSubheadlineLabel *_titleLabel;
ORKQuantityLabel *_valueLabel;
ORKTintedImageView *_imageView;
UIView *_valueHolder;
NSLayoutConstraint *_zeroWidthConstraint;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_titleLabel = [ORKSubheadlineLabel new];
_titleLabel.textAlignment = NSTextAlignmentCenter;
_valueLabel = [ORKQuantityLabel new];
_valueLabel.textAlignment = NSTextAlignmentCenter;
_imageView = [ORKTintedImageView new];
_imageView.shouldApplyTint = YES;
_valueHolder = [UIView new];
_titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
_valueLabel.translatesAutoresizingMaskIntoConstraints = NO;
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
_valueHolder.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_titleLabel];
[_valueHolder addSubview:_valueLabel];
[_valueHolder addSubview:_imageView];
[self addSubview:_valueHolder];
#if LAYOUT_DEBUG
self.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:0.2];
_titleLabel.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.2];
_valueLabel.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.2];
#endif
for (UIView *view in @[_titleLabel, _valueLabel, _imageView]) {
view.isAccessibilityElement = NO;
}
[self setUpConstraints];
}
return self;
}
- (void)setEnabled:(BOOL)enabled {
_enabled = enabled;
self.hidden = !enabled;
[self setNeedsUpdateConstraints];
}
- (void)setTitle:(NSString *)title {
_title = title;
_titleLabel.text = title;
}
- (void)setValue:(NSString *)value {
_value = value;
_valueLabel.text = value;
}
- (void)setImage:(UIImage *)image {
_image = nil;
_imageView.image = image;
}
- (void)setUpConstraints {
const CGFloat TitleBaselineToValueBaseline = 40;
const CGFloat ValueBaselineToBottom = 36;
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_titleLabel, _valueLabel, _imageView);
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_titleLabel]"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_titleLabel]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imageView]-10-[_valueLabel]|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_titleLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1.0
constant:TitleBaselineToValueBaseline]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_valueLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1.0
constant:ValueBaselineToBottom]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:_valueHolder
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:_valueHolder
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0.0]];
for (NSLayoutConstraint *constraint in constraints) {
constraint.priority = UILayoutPriorityRequired - 2;
}
[NSLayoutConstraint activateConstraints:constraints];
_zeroWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
_zeroWidthConstraint.priority = UILayoutPriorityRequired - 1;
[self setNeedsUpdateConstraints];
}
- (void)updateConstraints {
_zeroWidthConstraint.active = !_enabled;
[super updateConstraints];
}
#pragma mark Accessibility
- (BOOL)isAccessibilityElement {
return YES;
}
- (NSString *)accessibilityLabel {
return _titleLabel.accessibilityLabel;
}
- (NSString *)accessibilityValue {
return _valueLabel.accessibilityLabel;
}
- (UIAccessibilityTraits)accessibilityTraits {
return [super accessibilityTraits] | UIAccessibilityTraitUpdatesFrequently;
}
@end
@implementation ORKQuantityPairView {
UIView *_metricKeyline;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_leftView = [ORKActiveStepQuantityView new];
_rightView = [ORKActiveStepQuantityView new];
_leftView.translatesAutoresizingMaskIntoConstraints = NO;
_rightView.translatesAutoresizingMaskIntoConstraints = NO;
_metricKeyline = [UIView new];
_metricKeyline.translatesAutoresizingMaskIntoConstraints = NO;
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setKeylineHidden:NO];
_metricKeyline.backgroundColor = [UIColor ork_midGrayTintColor];
[self addSubview:_leftView];
[self addSubview:_rightView];
[self addSubview:_metricKeyline];
[self setUpConstraints];
}
return self;
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_leftView, _rightView, _metricKeyline);
// Leave space for the keyline between these views, and then constrain it to be 1px wide and go from top to bottom baseline of metric views.
CGFloat scale = [UIScreen mainScreen].scale;
NSArray *vertConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_leftView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views];
[constraints addObjectsFromArray:vertConstraints];
NSArray *horizConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_leftView]-s-[_rightView]-|"
options:NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom|NSLayoutFormatDirectionLeftToRight
metrics:@{ @"s": @(1.0 / scale) }
views:views];
for (NSLayoutConstraint *constraint in horizConstraints) {
constraint.priority = UILayoutPriorityDefaultHigh + 1;
}
[constraints addObjectsFromArray:horizConstraints];
// Ensure baseline alignment of title and value
[constraints addObject:[NSLayoutConstraint constraintWithItem:_leftView.titleLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_rightView.titleLabel
attribute:NSLayoutAttributeFirstBaseline
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_leftView.valueLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_rightView.valueLabel
attribute:NSLayoutAttributeFirstBaseline
multiplier:1.0
constant:0.0]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_leftView][_metricKeyline(==s)]"
options:NSLayoutFormatAlignAllTop|NSLayoutFormatDirectionLeftToRight
metrics:@{ @"s": @(1.0 / scale) }
views:views]];
NSLayoutConstraint *keylineBottom = [NSLayoutConstraint constraintWithItem:_metricKeyline
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_leftView.valueLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1.0
constant:0.0];
[constraints addObject:keylineBottom];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
maxWidthConstraint.priority = UILayoutPriorityRequired - 2;
[constraints addObject:maxWidthConstraint];
// This constraint should be beaten out by the full-width-coverage and zero-width constraints if only one of the views is enabled.
NSLayoutConstraint *equalWidthConstraint = [NSLayoutConstraint constraintWithItem:_leftView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:_rightView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0];
equalWidthConstraint.priority = UILayoutPriorityDefaultLow;
[constraints addObject:equalWidthConstraint];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)setKeylineHidden:(BOOL)keylineHidden {
_keylineHidden = keylineHidden;
_metricKeyline.hidden = keylineHidden;
}
@end
@@ -1,70 +0,0 @@
/*
Copyright (c) 2015, 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:
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 Foundation;
NS_ASSUME_NONNULL_BEGIN
@class ORKActiveStepTimer;
typedef void (^ORKActiveStepTimerHandler)(ORKActiveStepTimer *timer, BOOL finished);
@interface ORKActiveStepTimer : NSObject
- (instancetype)initWithDuration:(NSTimeInterval)duration interval:(NSTimeInterval)interval runtime:(NSTimeInterval)runtime handler:(ORKActiveStepTimerHandler)handler;
@property (nonatomic, assign) NSTimeInterval duration;
@property (nonatomic, readonly) NSTimeInterval interval;
@property (nonatomic, readonly) NSTimeInterval runtime;
/*
Handler callbacks are returned on interval boundaries. The timer automatically
pauses itself when finished=YES.
This handler is retained. Be careful not to create a retain cycle.
*/
@property (nonatomic, copy, readonly) ORKActiveStepTimerHandler handler;
// Pauses the timer.
- (void)pause;
// Resumes the timer where it left off.
- (void)resume;
// Sets runtime to 0. Stops the timer if it is running.
- (void)reset;
@end
NS_ASSUME_NONNULL_END
@@ -1,243 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKActiveStepTimer.h"
#import "ORKHelpers_Internal.h"
@import UIKit;
#include <mach/mach.h>
#include <mach/mach_time.h>
static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
static mach_timebase_info_data_t sTimebaseInfo;
if ( sTimebaseInfo.denom == 0 ) {
(void) mach_timebase_info(&sTimebaseInfo);
}
uint64_t elapsedNano = delta * sTimebaseInfo.numer / sTimebaseInfo.denom;
return elapsedNano * 1.0 / NSEC_PER_SEC;
}
@implementation ORKActiveStepTimer {
uint64_t _startTime;
NSTimeInterval _preExistingRuntime;
dispatch_queue_t _queue;
dispatch_source_t _timer;
UIBackgroundTaskIdentifier _backgroundTaskIdentifier;
uint32_t _isRunning;
}
- (instancetype)initWithDuration:(NSTimeInterval)duration interval:(NSTimeInterval)interval runtime:(NSTimeInterval)runtime handler:(ORKActiveStepTimerHandler)handler {
self = [super init];
if (self) {
if (!handler) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Handler is required" userInfo:nil];
}
_duration = duration;
_interval = interval;
_handler = [handler copy];
_preExistingRuntime = runtime;
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
_queue = dispatch_queue_create("active_step", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)dealloc {
[self queue_pauseAtFinish:NO];
}
- (NSTimeInterval)runtime {
__block NSTimeInterval runtime = 0;
dispatch_sync(_queue, ^{
runtime = [self queue_runtime];
});
return MIN(runtime,_duration);
}
- (void)pause {
dispatch_sync(_queue, ^{
[self queue_pauseAtFinish:NO];
});
}
- (void)resume {
dispatch_sync(_queue, ^{
[self queue_resume];
});
}
- (void)reset {
dispatch_sync(_queue, ^{
[self queue_reset];
});
}
- (NSTimeInterval)queue_runtime {
NSTimeInterval runtime = _preExistingRuntime;
if (_timer != NULL) {
uint64_t now = mach_absolute_time();
runtime += timeIntervalFromMachTime(now - _startTime);
}
return runtime;
}
- (void)setDuration:(NSTimeInterval)duration {
dispatch_sync(_queue, ^{
_duration = duration;
});
}
- (void)hiqueue_event {
dispatch_sync(_queue, ^{
[self queue_event];
});
}
- (void)queue_event {
[self queue_assertBackgroundTask];
NSTimeInterval runtime = [self queue_runtime];
BOOL finished = (runtime >= _duration);
if (finished) {
[self queue_pauseAtFinish:YES];
}
dispatch_async(dispatch_get_main_queue(), ^{
_handler(self, finished);
dispatch_sync(_queue, ^{
// If the timer is still NULL here, we can safely release the background task.
if (_timer == NULL) {
[self queue_releaseBackgroundTask];
}
});
});
}
- (void)queue_clearTimer {
if (_timer != NULL) {
dispatch_source_cancel(_timer);
_timer = NULL;
}
}
- (void)queue_releaseBackgroundTask {
if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
return;
}
UIBackgroundTaskIdentifier identifier = _backgroundTaskIdentifier;
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] endBackgroundTask:identifier];
});
}
- (void)queue_assertBackgroundTask {
if (_backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
return;
}
_backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// This is guaranteed to be called synchronously on the main queue, switch to our queue to invalidate the identifier
dispatch_sync(_queue, ^{
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
});
}];
}
- (void)queue_resume {
if (_timer != NULL) {
// Already resumed
return;
}
if ([self queue_runtime] >= _duration) {
// Already finished. Fire one event to indicate.
[self queue_event];
return;
}
// We want to run in the background if we can, so voice can be played, etc.
assert(_backgroundTaskIdentifier == UIBackgroundTaskInvalid);
[self queue_assertBackgroundTask];
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0, 0, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0));
if (_timer == NULL) {
assert(0);
return;
}
ORKWeakTypeOf(self) weakSelf = self;
dispatch_source_set_event_handler(_timer, ^{
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf hiqueue_event];
});
NSTimeInterval timeUntilNextFire = (floor(_preExistingRuntime / _interval) + 1)*_interval - _preExistingRuntime;
_startTime = mach_absolute_time();
dispatch_source_set_timer(_timer,
dispatch_time(DISPATCH_TIME_NOW, timeUntilNextFire * NSEC_PER_SEC),
_interval * NSEC_PER_SEC,
0.05 * NSEC_PER_SEC);
dispatch_resume(_timer);
}
- (void)queue_pauseAtFinish:(BOOL)atFinish {
if (_timer == NULL) {
// Not running
return;
}
uint64_t now = mach_absolute_time();
[self queue_clearTimer];
_preExistingRuntime += timeIntervalFromMachTime(now - _startTime);
_startTime = 0;
if (!atFinish) {
// If we are atFinish, the task will be released after the handler completes
[self queue_releaseBackgroundTask];
}
}
- (void)queue_reset {
[self queue_clearTimer];
_preExistingRuntime = 0;
[self queue_releaseBackgroundTask];
}
@end
@@ -1,52 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
#import "ORKCustomStepView_Internal.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;
@end
NS_ASSUME_NONNULL_END
@@ -1,234 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKActiveStepTimerView.h"
#import "ORKActiveStepTimer.h"
#import "ORKCountdownLabel.h"
#import "ORKSurveyAnswerCellForText.h"
#import "ORKSurveyAnswerCellForNumber.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;
BOOL _registeredForNotifications;
NSLayoutConstraint *_countDownLabelBottomToStartTimerButtonTopConstraint;
NSLayoutConstraint *_countDownLabelZeroHeightConstraint;
NSLayoutConstraint *_startTimerButtonZeroHeightConstraint;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Count Down
{
_countDownLabel = [ORKCountdownLabel new];
_countDownLabel.textAlignment = NSTextAlignmentCenter;
_countDownLabel.text = @" ";
[self addSubview:_countDownLabel];
}
// Count down start button
{
_startTimerButton = [ORKTextButton new];
[_startTimerButton setTitle:ORKLocalizedString(@"BUTTON_START_TIMER", nil) forState:UIControlStateNormal];
[_startTimerButton addTarget:self action:@selector(startTimerButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
_startTimerButton.exclusiveTouch = YES;
[self addSubview:_startTimerButton];
}
_countDownLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setUpConstraints];
}
return self;
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
ORKActiveStepViewController *viewController = self.activeStepViewController;
if (viewController) {
[self updateDisplay:viewController];
}
}
- (void)setRegisteredForNotifications:(BOOL)registered {
if (registered == _registeredForNotifications) {
return;
}
registered = _registeredForNotifications;
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
if (registered) {
[notificationCenter addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
} else {
[notificationCenter removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}
}
- (void)didMoveToWindow {
[self setRegisteredForNotifications:(self.window != nil)];
}
- (void)setStep:(ORKActiveStep *)step {
_step = step;
_countDownLabel.hidden = !(_step.hasCountDown);
BOOL hasTimerButton = (_step.hasCountDown && _step.shouldStartTimerAutomatically == NO);
_startTimerButton.hidden = !hasTimerButton;
_startTimerButton.alpha = 1;
[_countDownLabel setCountDownValue:(NSInteger)[_step stepDuration]];
[self setNeedsUpdateConstraints];
}
- (void)startTimerButtonTapped:(id)sender {
[self.activeStepViewController start];
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, _countDownLabel);
}
- (void)updateDisplay:(ORKActiveStepViewController *)viewController {
NSInteger countDownValue = (NSInteger)round(viewController.timeRemaining);
[_countDownLabel setCountDownValue:countDownValue];
}
- (void)resetStep:(ORKActiveStepViewController *)viewController {
self.step = (ORKActiveStep *)viewController.step;
}
- (void)startStep:(ORKActiveStepViewController *)viewController {
_startTimerButton.alpha = 0;
}
- (void)suspendStep:(ORKActiveStepViewController *)viewController {
}
- (void)resumeStep:(ORKActiveStepViewController *)viewController {
self.step = (ORKActiveStep *)viewController.step;
if ([viewController timerActive]) {
_startTimerButton.alpha = 0;
[self updateDisplay:viewController];
}
}
- (void)finishStep:(ORKActiveStepViewController *)viewController {
}
static const CGFloat CountDownLabelToButtonMargin = 2.0;
- (void)setUpConstraints {
NSDictionary *views = NSDictionaryOfVariableBindings(_countDownLabel, _startTimerButton);
ORKEnableAutoLayoutForViews(views.allValues);
NSMutableArray *constraints = [NSMutableArray new];
for (UIView *view in views.allValues) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
}
[constraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_countDownLabel
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
_countDownLabelBottomToStartTimerButtonTopConstraint = [NSLayoutConstraint constraintWithItem:_startTimerButton
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_countDownLabel
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:CountDownLabelToButtonMargin];
[constraints addObject:_countDownLabelBottomToStartTimerButtonTopConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_startTimerButton
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
[NSLayoutConstraint activateConstraints:constraints];
_countDownLabelZeroHeightConstraint = [NSLayoutConstraint constraintWithItem:_countDownLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
_startTimerButtonZeroHeightConstraint = [NSLayoutConstraint constraintWithItem:_startTimerButton
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
[self setNeedsUpdateConstraints];
}
- (void)updateConstraints {
_countDownLabelZeroHeightConstraint.active = _countDownLabel.hidden;
_startTimerButtonZeroHeightConstraint.active = (_countDownLabel.hidden || _startTimerButton.hidden);
_countDownLabelBottomToStartTimerButtonTopConstraint.constant =
(_countDownLabel.hidden || _startTimerButton.hidden) ? 0.0 : CountDownLabelToButtonMargin;
[super updateConstraints];
}
@end
@@ -1,259 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
#import <ResearchKit/ORKStepViewController.h>
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKActiveStepViewController` class is the base class for displaying `ORKActiveStep`
subclasses. The predefined active tasks defined in `ORKOrderedTask` all make use
of subclasses of `ORKActiveStep`, paired with `ORKActiveStepViewController`
subclasses.
An active step view controller is typically instantiated by a task view controller
when it encounters an active step in a task. Active steps generally include some form of sensor-driven data collection, or involve some highly interactive content, such as a cognitive task or game.
Examples of active step view controller subclasses include `ORKWalkingTaskStepViewController`,
`ORKCountdownStepViewController`, `ORKSpatialSpanMemoryStepViewController`,
`ORKFitnessStepViewController`, and `ORKAudioStepViewController`.
The primary feature that active step view controllers enable is life cycle. After an active step is presented, it can be started to start a timer. When the timer expires, the
step is considered finished. Some steps may have the concept of suspend and resume, such as when
the app is put in the background, and during which data recording is temporarily paused.
These life cycle methods generally apply to any recorders being used to record
data from the device's sensors, but they should also be applied to any UI
being displayed to clearly indicate when data is being collected
for the task.
When you develop a new active step, you should subclass `ORKActiveStepViewController`
and define your specific UI. When subclassing, pay special attention to the life cycle
methods, `start`, `finish`, `suspend`, and `resume`. Also, be sure to test for
the expected behavior when the user suspends and resumes the app, during task
save and restore, and during UIKit's UI state restoration.
See also: `ORKActiveStep`.
*/
ORK_CLASS_AVAILABLE
@interface ORKActiveStepViewController : ORKStepViewController <ORKRecorderDelegate>
/// @name UI Customization
/**
The custom view for the active step.
Attach a custom view here, and implement `sizeThatFits:` or
use `intrinsicContentSize` or provide constraints that request the size needed for
the custom view within the active step's layout.
Custom views can be used for visual instructions with animation,
or for getting interactive input.
*/
@property (nonatomic, strong, nullable) UIView *customView;
/**
The image view for the active step. (read-only)
The image view is created on demand when this property is accessed, and is a
shortcut to display an image in the custom area of an active task (that is, instead of
using `customView`).
*/
@property (nonatomic, strong, readonly, nullable) UIImageView *imageView;
/// @name Data collection
/**
The array of recorders currently in use by the active step. (read-only)
Recorders are generated when the step starts, based on the recorder
configurations of the step. Each recorder is an instance of `ORKRecorder`, and
is created by the active step view controller using the array of recorder
configurations in the step.
See also: `ORKRecorderConfiguration` and `ORKActiveStep`.
*/
@property (nonatomic, strong, readonly, nullable) NSArray *recorders;
/// @name Active step life cycle
/**
A Boolean value that indicates whether the step has finished. (read-only)
If the step is considered finished, the Continue button is enabled and the Skip
button is hidden. When the step is not finished, the Continue button is disabled and the Skip
button is visible.
In addition, when a step is finished, all recorders are stopped.
*/
@property (nonatomic, assign, readonly, getter=isFinished) BOOL finished;
/**
A Boolean value that indicates whether the step has started. (read-only)
If the step has not yet started, recorders are not yet running, and time
is not counted against the `duration` of the step.
*/
@property (nonatomic, assign, readonly, getter=isStarted) BOOL started;
/**
Tells the view controller that the active step has finished.
This method is an override point for subclasses, called by the base class when
the step has just finished.
The default implementation does nothing except in the case of steps that have countdown
enabled. When countdown is enabled in a step, the view controller attempts to navigate automatically to the next step, if so configured.
*/
- (void)stepDidFinish;
/**
A Boolean value that indicates whether to suspend the step if the app is not
active or the screen is off.
Active steps that require the screen in order to work should suspend
recording when the app goes into the background. Other active steps require
the step to continue while the app is in the background. For example, the fitness check
active step continues to collect data while the screen is off, and continues
to give voice prompts.
*/
@property (nonatomic, assign) BOOL suspendIfInactive;
/**
Starts the active step.
Call this method to start the timer on the active step, if there is one, and
to start any data recording.
When you start the step, recorders are instantiated based on their configurations and then started. All
timers should start, and the UI should show users that the step is in progress.
This method does nothing if the step has already started.
Subclasses should super when overriding this method.
*/
- (void)start;
/**
Suspends the active step.
Call this method to suspend data recording and the step's timer.
This method may called automatically when the app is suspended.
The view controller can be configured not to suspend even if the app
goes into the background (for more information, see `suspendIfInactive`).
Subclasses should call super when overriding this method.
*/
- (void)suspend;
/**
Resumes the active step.
Call this method when the step should be resumed. Calls to this method should
be paired with previous calls to `suspend`.
This method may be called automatically when the app is resumed. The view
controller can be configured not to suspend even if the app
goes into the background (for more information, see `suspendIfInactive`).
When the step is resumed, the UI should resume at the point where the user left off,
or, if that does not make sense for the particular step, to the most recent
suitable point.
Subclasses should call super when overriding this method.
*/
- (void)resume;
/**
Finishes the active step.
Call this method to finish the active step. If the active step is configured with
a timer, this method is called automatically when the timer expires.
Finishing the active step stops all data recording and stops any timers. In steps that have the
`shouldContinueOnFinish` property set, forward navigation to the next step
may ensue.
This method does nothing if the step has already finished.
Subclasses should call super when overriding this method.
*/
- (void)finish;
/// @name Recorder life cycle
/**
Tells the view controller that the set of recorders changed.
This method is usually called by the active step view controller in response
to `start` or `resume`.
Subclasses may override this method.
*/
- (void)recordersDidChange;
/**
Tells the view controller that the recorders are about to start.
This method is called by the active step view controller after instantiating
the recorders, but before starting them.
Subclasses may override this method.
*/
- (void)recordersWillStart;
/**
Tells the view controller that the recorders are about to stop.
This method is called by the active step view controller before
stopping the recorders.
Subclasses may override this method.
*/
- (void)recordersWillStop;
/**
Tells the view controller that the step has been loaded and is about to start.
This method is called by the active step view controller just after the step
has been set. The base implementation instantiates the recorders and timer but
does not start them.
Subclasses may override this method, but must also call super.
*/
- (void)prepareStep;
@end
NS_ASSUME_NONNULL_END
@@ -1,505 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKActiveStepViewController.h"
#import "ORKActiveStepTimer.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 () {
ORKActiveStepView *_activeStepView;
ORKActiveStepTimer *_activeStepTimer;
NSArray *_recorderResults;
SystemSoundID _alertSound;
NSURL *_alertSoundURL;
BOOL _hasSpokenHalfwayCountdown;
}
@property (nonatomic, strong) NSArray *recorders;
@end
@implementation ORKActiveStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
_recorderResults = [NSArray new];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
_timerUpdateInterval = 1;
}
return self;
}
- (void)applicationWillResignActive:(NSNotification *)notification {
if (self.suspendIfInactive) {
[self suspend];
}
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
if (self.suspendIfInactive) {
[self resume];
}
}
- (ORKActiveStep *)activeStep {
NSAssert(self.step == nil || [self.step isKindOfClass:[ORKActiveStep class]], @"Step should be a subclass of an ORKActiveStep");
return (ORKActiveStep *)self.step;
}
- (ORKActiveStepView *)activeStepView {
return _activeStepView;
}
- (void)viewDidLoad {
[super viewDidLoad];
_activeStepView = [[ORKActiveStepView alloc] initWithFrame:self.view.bounds];
_activeStepView.translatesAutoresizingMaskIntoConstraints = NO;
[_activeStepView setCustomView:_customView];
[self updateContinueButtonItem];
_activeStepView.headerView.learnMoreButtonItem = self.learnMoreButtonItem;
_activeStepView.continueSkipContainer.skipButtonItem = self.skipButtonItem;
_activeStepView.continueSkipContainer.continueEnabled = _finished;
[self.view addSubview:_activeStepView];
NSMutableArray *constraints = [NSMutableArray new];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[activeStepView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:@{@"activeStepView": _activeStepView}]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topLayoutGuide][activeStepView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:@{@"activeStepView": _activeStepView,
@"topLayoutGuide": self.topLayoutGuide}]];
[NSLayoutConstraint activateConstraints:constraints];
[self prepareStep];
}
- (void)stepDidChange {
[super stepDidChange];
_activeStepView.activeStep = [self activeStep];
[self updateContinueButtonItem];
[self prepareStep];
}
- (UIView *)customViewContainer {
__unused UIView *view = [self view];
return _activeStepView.customViewContainer;
}
- (ORKTintedImageView *)imageView {
__unused UIView *view = [self view];
return _activeStepView.imageView;
}
- (void)setCustomView:(UIView *)customView {
_customView = customView;
[_activeStepView setStepView:_customView];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
ORK_Log_Debug(@"%@",self);
[self.taskViewController setRegisteredScrollView:_activeStepView];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
ORK_Log_Debug(@"%@",self);
// Wait for animation complete
dispatch_async(dispatch_get_main_queue(), ^{
if(self.started){
// Should call resume instead of start when the task has been started.
[self resume];
} else if ([[self activeStep] shouldStartTimerAutomatically]) {
[self start];
}
});
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
ORK_Log_Debug(@"%@",self);
[self suspend];
}
- (void)updateContinueButtonItem {
_activeStepView.continueSkipContainer.continueButtonItem = self.continueButtonItem;
}
- (void)setContinueButtonItem:(UIBarButtonItem *)continueButtonItem {
[super setContinueButtonItem:continueButtonItem];
[self updateContinueButtonItem];
}
- (void)setLearnMoreButtonItem:(UIBarButtonItem *)learnMoreButtonItem {
[super setLearnMoreButtonItem:learnMoreButtonItem];
_activeStepView.headerView.learnMoreButtonItem = self.learnMoreButtonItem;
}
- (void)setSkipButtonItem:(UIBarButtonItem *)skipButtonItem {
[super setSkipButtonItem:skipButtonItem];
_activeStepView.continueSkipContainer.skipButtonItem = skipButtonItem;
}
- (void)setFinished:(BOOL)finished {
_finished = finished;
_activeStepView.continueSkipContainer.continueEnabled = finished;
}
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
if (_recorderResults) {
sResult.results = [sResult.results arrayByAddingObjectsFromArray:_recorderResults] ? : _recorderResults;
}
return sResult;
}
#pragma mark - transition
- (void)recordersDidChange {
}
- (void)recordersWillStart {
}
- (void)recordersWillStop {
}
- (void)prepareRecorders {
// Stop any existing recorders
[self recordersWillStop];
for (ORKRecorder *recorder in self.recorders) {
recorder.delegate = nil;
[recorder stop];
}
NSMutableArray *recorders = [NSMutableArray array];
for (ORKRecorderConfiguration * provider in self.activeStep.recorderConfigurations) {
// If the outputDirectory is nil, recorders which require one will generate an error.
// We start them anyway, because we don't know which recorders will require an outputDirectory.
ORKRecorder *recorder = [provider recorderForStep:self.step
outputDirectory:self.outputDirectory];
recorder.configuration = provider;
recorder.delegate = self;
[recorders addObject:recorder];
}
self.recorders = recorders;
[self recordersDidChange];
}
- (void)setOutputDirectory:(NSURL *)outputDirectory {
[super setOutputDirectory:outputDirectory];
[self prepareStep];
}
- (void)prepareStep {
if (self.activeStep == nil) {
return;
}
self.finished = [[self activeStep] startsFinished];
ORK_Log_Debug(@"%@", self);
_activeStepView.activeStep = self.activeStep;
if ([self.activeStep hasCountDown]) {
ORKActiveStepTimerView *timerView = [ORKActiveStepTimerView new];
_activeStepView.activeCustomView = timerView;
} else {
_activeStepView.activeCustomView = nil;
}
_activeStepView.activeCustomView.activeStepViewController = self;
[_activeStepView.activeCustomView resetStep:self];
[self resetTimer];
[self prepareRecorders];
}
- (void)startRecorders {
[self recordersWillStart];
// Start recorders
for (ORKRecorder *recorder in self.recorders) {
[recorder viewController:self willStartStepWithView:self.customViewContainer];
[recorder start];
}
}
- (void)stopRecorders {
[self recordersWillStop];
for (ORKRecorder *recorder in self.recorders) {
[recorder stop];
}
}
- (void)playSound {
if (_alertSoundURL == nil) {
_alertSoundURL = [NSURL URLWithString:@"/System/Library/Audio/UISounds/short_low_high.caf"];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)(_alertSoundURL), &_alertSound);
}
AudioServicesPlaySystemSound(_alertSound);
}
- (void)start {
ORK_Log_Debug(@"%@",self);
self.started = YES;
[self startTimer];
[_activeStepView.activeCustomView startStep:self];
[self startRecorders];
if (self.activeStep.shouldVibrateOnStart) {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
}
if (self.activeStep.shouldPlaySoundOnStart) {
[self playSound];
}
// Start speech
if (self.activeStep.hasVoice && self.activeStep.spokenInstruction) {
// Let VO speak "Step x of y" before the instruction.
// If VO is not running, the text is spoken immediately.
ORKAccessibilityPerformBlockAfterDelay(1.5, ^{
[[ORKVoiceEngine sharedVoiceEngine] speakText:self.activeStep.spokenInstruction];
});
}
}
- (void)suspend {
ORK_Log_Debug(@"%@",self);
if (self.finished || !self.started) {
return;
}
[_activeStepTimer pause];
[_activeStepView.activeCustomView suspendStep:self];
[self stopRecorders];
}
- (void)resume {
ORK_Log_Debug(@"%@",self);
if (self.finished || !self.started) {
return;
}
[_activeStepTimer resume];
[self prepareRecorders];
[self startRecorders];
[_activeStepView.activeCustomView resumeStep:self];
}
- (void)finish {
ORK_Log_Debug(@"%@",self);
if (self.finished) {
return;
}
self.finished = YES;
[_activeStepTimer pause];
[_activeStepView.activeCustomView finishStep:self];
[self stopRecorders];
if (self.activeStep.shouldPlaySoundOnFinish) {
[self playSound];
}
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];
}
}
[self stepDidFinish];
}
- (void)dealloc {
AudioServicesDisposeSystemSoundID(_alertSound);
NSNotificationCenter *nfc = [NSNotificationCenter defaultCenter];
[nfc removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
[nfc removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}
#pragma mark - timers
- (void)resetTimer {
[_activeStepTimer reset];
_activeStepTimer = nil;
}
- (void)startTimer {
[self resetTimer];
NSTimeInterval stepDuration = self.activeStep.stepDuration;
if (stepDuration > 0) {
ORKWeakTypeOf(self) weakSelf = self;
_activeStepTimer = [[ORKActiveStepTimer alloc] initWithDuration:stepDuration
interval:_timerUpdateInterval
runtime:0
handler:^(ORKActiveStepTimer *timer, BOOL finished) {
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf countDownTimerFired:timer finished:finished];
}];
[_activeStepTimer resume];
}
}
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished {
if (finished) {
[self finish];
}
NSInteger countDownValue = (NSInteger)round(timer.duration - timer.runtime);
ORKActiveStepCustomView *customView = _activeStepView.activeCustomView;
[customView updateDisplay:self];
ORKVoiceEngine *voice = [ORKVoiceEngine sharedVoiceEngine];
if (!finished && self.activeStep.shouldSpeakCountDown) {
// Speak entire countdown if VO is running.
if (UIAccessibilityIsVoiceOverRunning()) {
[voice speakInt:countDownValue];
return;
}
if (0 < countDownValue && countDownValue <= 3) {
[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 {
return (_activeStepTimer != nil);
}
- (NSTimeInterval)timeRemaining {
if (_activeStepTimer == nil) {
return self.activeStep.stepDuration;
}
return _activeStepTimer.duration - _activeStepTimer.runtime;
}
#pragma mark - action handlers
- (void)stepDidFinish {
}
#pragma mark - ORKRecorderDelegate
- (void)recorder:(ORKRecorder *)recorder didCompleteWithResult:(ORKResult *)result {
_recorderResults = [_recorderResults arrayByAddingObject:result];
[self notifyDelegateOnResultChange];
}
- (void)recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error {
if (error) {
ORKStrongTypeOf(self.delegate) strongDelegate = self.delegate;
if ([strongDelegate respondsToSelector:@selector(stepViewController:recorder:didFailWithError:)]) {
[strongDelegate stepViewController:self recorder:recorder didFailWithError:error];
}
// If the recorder returns an error indicating that file write failed, and the output directory was nil,
// we consider it a fatal error and fail the step. Otherwise, developers might be confused to get
// no output, just because they did not set an output directory.
if ([error.domain isEqualToString:NSCocoaErrorDomain] &&
error.code == NSFileWriteInvalidFileNameError &&
self.outputDirectory == nil) {
[strongDelegate stepViewControllerDidFail:self withError:error];
}
}
}
static NSString *const _ORKFinishedRestoreKey = @"finished";
static NSString *const _ORKRecorderResultsRestoreKey = @"recorderResults";
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
[super encodeRestorableStateWithCoder:coder];
[coder encodeBool:_finished forKey:_ORKFinishedRestoreKey];
[coder encodeObject:_recorderResults forKey:_ORKRecorderResultsRestoreKey];
}
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
[super decodeRestorableStateWithCoder:coder];
self.finished = [coder decodeBoolForKey:_ORKFinishedRestoreKey];
_recorderResults = [coder decodeObjectOfClass:[NSArray class] forKey:_ORKRecorderResultsRestoreKey];
}
@end
@@ -1,66 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKActiveStepViewController.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKActiveStepTimer;
@class ORKActiveStepView;
@interface ORKActiveStepViewController ()
/**
The customViewContainer allows custom view to be its subview.
@note When ORKTouchRecorder is present, its gesture recognizer attaches to customViewContainer.
*/
@property (nonatomic, strong, readonly, nullable) UIView *customViewContainer;
@property (nonatomic, strong, readonly, nullable) ORKActiveStepView *activeStepView;
@property (nonatomic, readonly) NSTimeInterval timeRemaining;
@property (nonatomic, readonly) BOOL timerActive;
@property (nonatomic, assign) NSTimeInterval timerUpdateInterval;
@property (nonatomic, assign, getter=isStarted) BOOL started;
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished; // Let subclass receive timer fires
- (void)applicationWillResignActive:(NSNotification *)notification;
- (void)applicationDidBecomeActive:(NSNotification *)notification;
- (void)stopRecorders;
@end
NS_ASSUME_NONNULL_END
@@ -1,48 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKActiveStep.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKActiveStep ()
// Convenience methods.
- (BOOL)startsFinished;
- (BOOL)hasCountDown;
- (BOOL)hasTitle;
- (BOOL)hasText;
- (BOOL)hasVoice;
@end
NS_ASSUME_NONNULL_END
@@ -1,57 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKAudioContentView : ORKActiveStepCustomView
@property (nonatomic, copy, nullable) UIColor *keyColor;
@property (nonatomic, copy, nullable) UIColor *alertColor;
@property (nonatomic, assign) BOOL failed;
@property (nonatomic, assign, getter=isFinished) BOOL finished;
@property (nonatomic, assign) NSTimeInterval timeLeft;
@property (nonatomic, assign) CGFloat alertThreshold;
@property (nonatomic, copy, nullable) NSArray *samples;
// Samples should be in the range of (0, 1).
- (void)addSample:(NSNumber *)sample;
- (void)removeAllSamples;
@end
NS_ASSUME_NONNULL_END
@@ -1,402 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKAudioContentView.h"
#import "ORKHeadlineLabel.h"
#import "ORKLabel.h"
#import "ORKAccessibility.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
// The central blue region.
static const CGFloat GraphViewBlueZoneHeight = 170;
// The two bands at top and bottom which are "loud" each have this height.
static const CGFloat GraphViewRedZoneHeight = 25;
@interface ORKAudioGraphView : UIView
@property (nonatomic, strong) UIColor *keyColor;
@property (nonatomic, strong) UIColor *alertColor;
@property (nonatomic, copy) NSArray *values;
@property (nonatomic) CGFloat alertThreshold;
@end
static const CGFloat ValueLineWidth = 4.5;
static const CGFloat ValueLineMargin = 1.5;
@implementation ORKAudioGraphView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setUpConstraints];
#if TARGET_IPHONE_SIMULATOR
_values = @[ @(0.2), @(0.6), @(0.55), @(0.1), @(0.75), @(0.7) ];
#endif
}
return self;
}
- (void)setUpConstraints {
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:CGFLOAT_MAX];
heightConstraint.priority = UILayoutPriorityFittingSizeLevel;
[NSLayoutConstraint activateConstraints:@[heightConstraint]];
}
- (void)setValues:(NSArray *)values {
_values = [values copy];
[self setNeedsDisplay];
}
- (void)setKeyColor:(UIColor *)keyColor {
_keyColor = [keyColor copy];
[self setNeedsDisplay];
}
- (void)setAlertColor:(UIColor *)alertColor {
_alertColor = [alertColor copy];
[self setNeedsDisplay];
}
- (void)setAlertThreshold:(CGFloat)alertThreshold {
_alertThreshold = alertThreshold;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGRect bounds = self.bounds;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, bounds);
CGFloat scale = self.window.screen.scale;
CGFloat midY = CGRectGetMidY(bounds);
CGFloat maxX = CGRectGetMaxX(bounds);
CGFloat halfHeight = bounds.size.height / 2;
CGContextSaveGState(context);
{
UIBezierPath *centerLine = [UIBezierPath new];
[centerLine moveToPoint:(CGPoint){.x = 0, .y = midY}];
[centerLine addLineToPoint:(CGPoint){.x = maxX, .y = midY}];
CGContextSetLineWidth(context, 1.0 / scale);
[_keyColor setStroke];
CGFloat lengths[2] = {3, 3};
CGContextSetLineDash(context, 0, lengths, 2);
[centerLine stroke];
}
CGContextRestoreGState(context);
CGFloat lineStep = ValueLineMargin + ValueLineWidth;
CGContextSaveGState(context);
{
CGFloat x = maxX - lineStep / 2;
CGContextSetLineWidth(context, ValueLineWidth);
CGContextSetLineCap(context, kCGLineCapRound);
UIBezierPath *path1 = [UIBezierPath new];
path1.lineCapStyle = kCGLineCapRound;
path1.lineWidth = ValueLineWidth;
UIBezierPath *path2 = [path1 copy];
for (NSNumber *value in [_values reverseObjectEnumerator]) {
CGFloat floatValue = value.doubleValue;
UIBezierPath *path = nil;
if (floatValue > _alertThreshold) {
path = path1;
[_alertColor setStroke];
} else {
path = path2;
[_keyColor setStroke];
}
[path moveToPoint:(CGPoint){.x = x, .y = midY - floatValue*halfHeight}];
[path addLineToPoint:(CGPoint){.x = x, .y = midY + floatValue*halfHeight}];
x -= lineStep;
if (x < 0) {
break;
}
}
[_alertColor setStroke];
[path1 stroke];
[_keyColor setStroke];
[path2 stroke];
}
CGContextRestoreGState(context);
}
@end
@interface ORKAudioTimerLabel : ORKLabel
@end
@implementation ORKAudioTimerLabel
+ (UIFont *)defaultFont {
UIFontDescriptor *descriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline];
UIFontDescriptor *alternativeDescriptor = ORKFontDescriptorForLightStylisticAlternative(descriptor);
return [UIFont fontWithDescriptor:alternativeDescriptor size:[alternativeDescriptor pointSize] + 4];
}
@end
@interface ORKAudioContentView ()
@property (nonatomic, strong) ORKHeadlineLabel *alertLabel;
@property (nonatomic, strong) UILabel *timerLabel;
@property (nonatomic, strong) ORKAudioGraphView *graphView;
@end
@implementation ORKAudioContentView {
NSMutableArray *_samples;
UIColor *_keyColor;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.layoutMargins = ORKStandardFullScreenLayoutMarginsForView(self);
self.alertLabel = [ORKHeadlineLabel new];
_alertLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.timerLabel = [ORKAudioTimerLabel new];
_timerLabel.translatesAutoresizingMaskIntoConstraints = NO;
_timerLabel.textAlignment = NSTextAlignmentRight;
self.graphView = [ORKAudioGraphView new];
_graphView.translatesAutoresizingMaskIntoConstraints = NO;
self.translatesAutoresizingMaskIntoConstraints = NO;
self.alertColor = [UIColor ork_redColor];
[self addSubview:_alertLabel];
[self addSubview:_timerLabel];
[self addSubview:_graphView];
_timerLabel.text = @"06:00";
_alertLabel.text = ORKLocalizedString(@"AUDIO_TOO_LOUD_LABEL", nil);
self.alertThreshold = GraphViewBlueZoneHeight / ((GraphViewRedZoneHeight * 2) + GraphViewBlueZoneHeight);
[self updateGraphSamples];
[self applyKeyColor];
[self setUpConstraints];
}
return self;
}
- (void)tintColorDidChange {
[self applyKeyColor];
}
- (void)setFailed:(BOOL)failed {
_failed = failed;
_alertLabel.text = failed ? ORKLocalizedString(@"AUDIO_GENERIC_ERROR_LABEL", nil) : ORKLocalizedString(@"AUDIO_TOO_LOUD_LABEL", nil);
[self updateAlertLabelHidden];
}
- (void)setFinished:(BOOL)finished {
_finished = finished;
[self updateAlertLabelHidden];
}
- (void)applyKeyColor {
UIColor *keyColor = [self keyColor];
_timerLabel.textColor = keyColor;
_graphView.keyColor = keyColor;
}
- (UIColor *)keyColor {
return _keyColor ? : [self tintColor];
}
- (void)setKeyColor:(UIColor *)keyColor {
_keyColor = keyColor;
[self applyKeyColor];
}
- (void)setAlertColor:(UIColor *)alertColor {
_alertColor = alertColor;
_alertLabel.textColor = alertColor;
_graphView.alertColor = alertColor;
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_timerLabel, _alertLabel, _graphView);
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_graphView]-[_alertLabel]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_alertLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
const CGFloat sideMargin = self.layoutMargins.left + (2 * ORKStandardLeftMarginForTableViewCell(self));
const CGFloat innerMargin = 2;
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-sideMargin-[_graphView]-innerMargin-[_timerLabel]-sideMargin-|"
options:NSLayoutFormatAlignAllCenterY
metrics:@{@"sideMargin": @(sideMargin), @"innerMargin": @(innerMargin)}
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_graphView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:(GraphViewBlueZoneHeight + GraphViewRedZoneHeight * 2)]];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)setAlertThreshold:(CGFloat)alertThreshold {
_alertThreshold = alertThreshold;
_graphView.alertThreshold = alertThreshold;
[self updateGraphSamples];
}
- (void)setTimeLeft:(NSTimeInterval)timeLeft {
_timeLeft = timeLeft;
[self updateTimerLabel];
}
- (void)updateTimerLabel {
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;
});
NSString *string = [formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = string;
_timerLabel.hidden = (string == nil);
}
- (void)updateGraphSamples {
_graphView.values = _samples;
[self updateAlertLabelHidden];
}
- (void)updateAlertLabelHidden {
NSNumber *sample = _samples.lastObject;
BOOL show = (!_finished && (sample.doubleValue > _alertThreshold)) || _failed;
if (_alertLabel.hidden && show) {
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, _alertLabel.text);
}
_alertLabel.hidden = !show;
}
- (void)setSamples:(NSArray *)samples {
_samples = [samples mutableCopy];
[self updateGraphSamples];
}
- (void)addSample:(NSNumber *)sample {
NSAssert(sample != nil, @"Sample should be non-nil");
if (!_samples) {
_samples = [NSMutableArray array];
}
[_samples addObject:sample];
// Try to keep around 250 samples
if (_samples.count > 500) {
_samples = [[_samples subarrayWithRange:(NSRange){250, _samples.count - 250}] mutableCopy];
}
[self updateGraphSamples];
}
- (void)removeAllSamples {
_samples = nil;
[self updateGraphSamples];
}
#pragma mark Accessibility
- (BOOL)isAccessibilityElement {
return YES;
}
- (NSString *)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 {
return [super accessibilityTraits] | UIAccessibilityTraitUpdatesFrequently;
}
@end
-110
View File
@@ -1,110 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
This software is based on the original source by Matt Gallagher.
http://www.cocoawithlove.com/2010/10/ios-tone-generator-introduction-to.html
Copyright (c) 2009-2011 Matt Gallagher. All rights reserved.
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software. Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
@import UIKit;
@import AVFoundation;
#import "ORKTypes.h"
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKAudioGenerator` class represents an audio tone generator.
*/
ORK_CLASS_AVAILABLE
@interface ORKAudioGenerator : NSObject
/**
Plays a tone at a specific frequency in stereo.
The sound is a "pure" sinusoid tone.
@param frequency The audio frequency in hertz.
*/
- (void)playSoundAtFrequency:(double)frequency;
/**
Plays a tone at a specific frequency on a specific channel, with a fade-in effect.
The sound is a "pure" sinusoid tone.
The fade-in effect is applied linearly for the peak amplitude, from a 0 to 1 factor.
@param frequency The audio frequency in hertz.
@param channel The audio channel (left or right).
@param duration The fade-in duration.
*/
- (void)playSoundAtFrequency:(double)frequency
onChannel:(ORKAudioChannel)channel
fadeInDuration:(NSTimeInterval)duration;
/**
Stops the audio being played.
*/
- (void)stop;
/**
Returns the peak audio volume being currently played, in decibels (dB).
@return The current audio volume in decibels.
*/
- (double)volumeInDecibels;
/**
Returns the peak audio volume amplitude being currently played (from 0 to 1).
@return The current audio volume amplitude.
*/
- (double)volumeAmplitude;
@end
NS_ASSUME_NONNULL_END
-283
View File
@@ -1,283 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
This software is based on the original source by Matt Gallagher.
http://www.cocoawithlove.com/2010/10/ios-tone-generator-introduction-to.html
Copyright (c) 2009-2011 Matt Gallagher. All rights reserved.
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software. Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import "ORKAudioGenerator.h"
@import AudioToolbox;
@interface ORKAudioGenerator () {
@public
AudioComponentInstance _toneUnit;
double _frequency;
double _theta;
ORKAudioChannel _activeChannel;
BOOL _playsStereo;
double _fadeInFactor;
NSTimeInterval _fadeInDuration;
}
- (void)setupAudioSession;
- (void)createToneUnit;
- (void)play;
- (void)handleInterruption:(id)sender;
@end
const double ORKSineWaveToneGeneratorAmplitudeDefault = 0.03f;
const double ORKSineWaveToneGeneratorSampleRateDefault = 44100.0f;
OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
// Fixed amplitude is good enough for our purposes
const double amplitude = ORKSineWaveToneGeneratorAmplitudeDefault;
// Get the tone parameters out of the view controller
ORKAudioGenerator *audioGenerator = (__bridge ORKAudioGenerator *)inRefCon;
double theta = audioGenerator->_theta;
double theta_increment = 2.0 * M_PI * audioGenerator->_frequency / ORKSineWaveToneGeneratorSampleRateDefault;
double fadeInFactor = audioGenerator->_fadeInFactor;
// This is a mono tone generator so we only need the first buffer
Float32 *bufferActive = (Float32 *)ioData->mBuffers[audioGenerator->_activeChannel].mData;
Float32 *bufferNonActive = (Float32 *)ioData->mBuffers[1 - audioGenerator->_activeChannel].mData;
// Generate the samples
for (UInt32 frame = 0; frame < inNumberFrames; frame++) {
double bufferValue = sin(theta) * amplitude * pow(10, 2 * fadeInFactor - 2);
bufferActive[frame] = bufferValue;
if (audioGenerator->_playsStereo) {
bufferNonActive[frame] = bufferValue;
} else {
bufferNonActive[frame] = 0;
}
theta += theta_increment;
if (theta > 2.0 * M_PI) {
theta -= 2.0 * M_PI;
}
fadeInFactor += 1.0 / (ORKSineWaveToneGeneratorSampleRateDefault * audioGenerator->_fadeInDuration);
if (fadeInFactor >= 1) {
fadeInFactor = 1;
}
}
// Store the theta back in the view controller
audioGenerator->_theta = theta;
audioGenerator->_fadeInFactor = fadeInFactor;
return noErr;
}
@implementation ORKAudioGenerator
- (instancetype)init {
self = [super init];
if (self) {
[self setupAudioSession];
// Automatically stop and then restart audio playback when the app resigns active.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
}
return self;
}
- (void)dealloc {
[self stop];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
if (_toneUnit) {
__unused OSErr error = AudioOutputUnitStart(_toneUnit);
NSAssert1(error == noErr, @"Error starting unit: %hd", error);
}
}
- (void)applicationWillResignActive:(NSNotification *)notification {
if (_toneUnit) {
__unused OSErr error = AudioOutputUnitStop(_toneUnit);
NSAssert1(error == noErr, @"Error stopping unit: %hd", error);
}
}
- (double)volumeInDecibels {
return 20 * log(self.volumeAmplitude);
}
- (double)volumeAmplitude {
return ORKSineWaveToneGeneratorAmplitudeDefault * pow(10, 2 * _fadeInFactor - 2);
}
- (void)playSoundAtFrequency:(double)playFrequency {
_frequency = playFrequency;
_fadeInFactor = 0;
_fadeInDuration = 0.5;
_playsStereo = YES;
[self play];
}
- (void)playSoundAtFrequency:(double)playFrequency
onChannel:(ORKAudioChannel)playChannel
fadeInDuration:(NSTimeInterval)duration {
_frequency = playFrequency;
_activeChannel = playChannel;
_fadeInFactor = 0;
_fadeInDuration = duration;
_playsStereo = NO;
[self play];
}
- (void)play {
if (!_toneUnit) {
[self createToneUnit];
// Stop changing parameters on the unit
OSErr error = AudioUnitInitialize(_toneUnit);
NSAssert1(error == noErr, @"Error initializing unit: %hd", error);
// Start playback
error = AudioOutputUnitStart(_toneUnit);
NSAssert1(error == noErr, @"Error starting unit: %hd", error);
}
}
- (void)stop {
if (_toneUnit) {
AudioOutputUnitStop(_toneUnit);
AudioUnitUninitialize(_toneUnit);
AudioComponentInstanceDispose(_toneUnit);
_toneUnit = nil;
}
}
- (void)setupAudioSession {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
BOOL ok;
NSError *setCategoryError = nil;
ok = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
NSAssert1(ok, @"Audio error %@", setCategoryError);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleInterruption:)
name:AVAudioSessionInterruptionNotification
object:audioSession];
}
- (void)createToneUnit {
// Configure the search parameters to find the default playback output unit
// (called the kAudioUnitSubType_RemoteIO on iOS but
// kAudioUnitSubType_DefaultOutput on Mac OS X)
AudioComponentDescription defaultOutputDescription;
defaultOutputDescription.componentType = kAudioUnitType_Output;
defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
defaultOutputDescription.componentFlags = 0;
defaultOutputDescription.componentFlagsMask = 0;
// Get the default playback output unit
AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription);
NSAssert(defaultOutput, @"Can't find default output");
// Create a new unit based on this that we'll use for output
OSErr 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);
error = AudioUnitSetProperty(_toneUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input));
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;
const int eight_bits_per_byte = 8;
AudioStreamBasicDescription streamFormat;
streamFormat.mSampleRate = ORKSineWaveToneGeneratorSampleRateDefault;
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
streamFormat.mBytesPerPacket = four_bytes_per_float;
streamFormat.mFramesPerPacket = 1;
streamFormat.mBytesPerFrame = four_bytes_per_float;
streamFormat.mChannelsPerFrame = 2;
streamFormat.mBitsPerChannel = four_bytes_per_float * eight_bits_per_byte;
error = AudioUnitSetProperty (_toneUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&streamFormat,
sizeof(AudioStreamBasicDescription));
NSAssert1(error == noErr, @"Error setting stream format: %hd", error);
}
- (void)handleInterruption:(id)sender {
[self stop];
}
@end
@@ -1,77 +0,0 @@
/*
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
@@ -1,217 +0,0 @@
/*
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
@@ -1,90 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
@import AVFoundation;
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
/**
The ORKAudioRecorder class represents a recorder that uses the app's
`AVAudioSession` object to record audio.
To ensure audio recording continues when a task enters the background,
add the `audio` tag to `UIBackgroundModes` in your app's `Info.plist` file.
*/
ORK_CLASS_AVAILABLE
@interface ORKAudioRecorder : ORKRecorder
/**
The default audio format settings.
If no settings are specified, the audio configuration is
MPEG4 AAC, 2 channels, 16 bit, 44.1 kHz, AVAudioQualityMin.
*/
+ (NSDictionary *)defaultRecorderSettings;
/**
Audio format settings
Settings for the recording session.
Passed to AVAudioRecorder`'s `-initWithURL:settings:error:`
For information on the settings available for an audio recorder, see "AV Foundation Audio Settings Constants".
*/
@property (nonatomic, copy, readonly) NSDictionary *recorderSettings;
/**
Returns an initialized audio recorder using the specified settings, step, and output directory.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param recorderSettings The settings for the recording session.
@param step The step that requested this recorder.
@param outputDirectory The directory in which the audio output should be stored.
@return An initialized audio recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier
recorderSettings:(nullable NSDictionary *)recorderSettings
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
/**
Reference to the audio recorder being used.
The value of this property is used in the audio task in order to display recorded volume in real time during the task.
*/
@property (nonatomic, strong, readonly, nullable) AVAudioRecorder *audioRecorder;
@end
NS_ASSUME_NONNULL_END
-341
View File
@@ -1,341 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKAudioRecorder.h"
#import "ORKRecorder_Internal.h"
#import "ORKHelpers_Internal.h"
@interface ORKAudioRecorder ()
@property (nonatomic, strong) AVAudioRecorder *audioRecorder;
@property (nonatomic, copy) NSDictionary *recorderSettings;
@property (nonatomic, copy) NSString *savedSessionCategory;
@end
@implementation ORKAudioRecorder
- (void)dealloc {
ORK_Log_Debug(@"Remove audiorecorder %p", self);
[_audioRecorder stop];
_audioRecorder = nil;
}
+ (NSDictionary *)defaultRecorderSettings {
return @{AVFormatIDKey : @(kAudioFormatMPEG4AAC),
AVEncoderAudioQualityKey : @(AVAudioQualityMin),
AVNumberOfChannelsKey : @(2),
AVSampleRateKey : @(44100.0)};
}
- (instancetype)initWithIdentifier:(NSString *)identifier
recorderSettings:(NSDictionary *)recorderSettings
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier step:step outputDirectory:outputDirectory];
if (self) {
self.continuesInBackground = YES;
if (!recorderSettings) {
recorderSettings = [[self class] defaultRecorderSettings];
}
if (![recorderSettings isKindOfClass:[NSDictionary class]]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"recorderSettings should be a dictionary" userInfo:recorderSettings];
}
self.recorderSettings = recorderSettings;
}
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];
}
// Only create the file when we should actually start recording.
if (!_audioRecorder) {
NSError *error = nil;
NSURL *soundFileURL = [self recordingFileURL];
if (![self recreateFileWithError:&error]) {
[self finishRecordingWithError:error];
return;
}
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
_savedSessionCategory = audioSession.category;
if (![audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]) {
[self finishRecordingWithError:error];
return;
}
ORK_Log_Debug(@"Create audioRecorder %p", self);
_audioRecorder = [[AVAudioRecorder alloc]
initWithURL:soundFileURL
settings:self.recorderSettings
error:&error];
if (!_audioRecorder) {
[self finishRecordingWithError:error];
return;
}
#if !TARGET_IPHONE_SIMULATOR
if (!_audioRecorder.recording) {
[_audioRecorder prepareToRecord];
}
#endif
}
#if !TARGET_IPHONE_SIMULATOR
if (!_audioRecorder.recording) {
[_audioRecorder prepareToRecord];
[_audioRecorder record];
}
#endif
[super start];
}
- (void)stop {
if (!_audioRecorder) {
// Error has already been returned.
return;
}
[self doStopRecording];
NSURL *fileUrl = [self recordingFileURL];
if (![[NSFileManager defaultManager] fileExistsAtPath:[[self recordingFileURL] path]]) {
fileUrl = nil;
}
[self reportFileResultWithFile:fileUrl error:nil];
[super stop];
}
- (BOOL)isRecording {
return _audioRecorder.recording;
}
- (NSString *)mimeType {
NSDictionary *recorderSettings = [self recorderSettings];
unsigned int recorderFormat = ((NSNumber *)recorderSettings[AVFormatIDKey]).unsignedIntValue;
NSString *contentType = @"audio";
switch (recorderFormat) {
case kAudioFormatLinearPCM: {
int numBits = ((NSNumber *)recorderSettings[AVLinearPCMBitDepthKey]).intValue ? : 16;
contentType = [NSString stringWithFormat:@"audio/L%d", numBits];
break;
}
case kAudioFormatAC3: {
contentType = @"audio/ac3";
break;
}
case kAudioFormatMPEG4AAC:
case kAudioFormatMPEG4CELP:
case kAudioFormatMPEG4HVXC:
case kAudioFormatMPEG4TwinVQ:
case kAudioFormatAppleLossless: {
contentType = @"audio/m4a";
break;
}
case kAudioFormatULaw: {
contentType = @"audio/basic";
break;
}
}
return contentType;
}
- (NSString *)recorderType {
return @"audio";
}
- (void)doStopRecording {
if (self.isRecording) {
#if !TARGET_IPHONE_SIMULATOR
[_audioRecorder stop];
[self applyFileProtection:ORKFileProtectionComplete toFileAtURL:[self recordingFileURL]];
#endif
[self restoreSavedAudioSessionCategory];
}
}
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
- (NSString *)extension {
NSDictionary *recorderSettings = [self recorderSettings];
unsigned int recorderFormat = ((NSNumber *)recorderSettings[AVFormatIDKey]).unsignedIntValue;
NSString *extension = @"au";
switch (recorderFormat) {
case kAudioFormatLinearPCM:
{
extension = @"pcm";
break;
}
case kAudioFormatAC3: {
extension = @"ac3";
break;
}
case kAudioFormatMPEG4AAC:
case kAudioFormatMPEG4CELP:
case kAudioFormatMPEG4HVXC:
case kAudioFormatMPEG4TwinVQ:
case kAudioFormatAppleLossless: {
extension = @"m4a";
break;
}
}
return extension;
}
- (NSURL *)recordingFileURL {
return [[self recordingDirectoryURL] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", [self logName], [self extension]]];
}
- (BOOL)recreateFileWithError:(NSError **)error {
NSURL *url = [self recordingFileURL];
if (!url) {
if (error) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteInvalidFileNameError userInfo:@{NSLocalizedDescriptionKey:ORKLocalizedString(@"ERROR_RECORDER_NO_OUTPUT_DIRECTORY", nil)}];
}
return NO;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:error]) {
return NO;
}
if ([fileManager fileExistsAtPath:[url path]]) {
if (![fileManager removeItemAtPath:[url path] error:error]) {
return NO;
}
}
[fileManager createFileAtPath:[url path] contents:nil attributes:nil];
[fileManager setAttributes:@{NSFileProtectionKey: ORKFileProtectionFromMode(ORKFileProtectionCompleteUnlessOpen)} ofItemAtPath:[url path] error:error];
return YES;
}
- (void)reset {
[_audioRecorder stop];
_audioRecorder = nil;
[super reset];
}
@end
@implementation ORKAudioRecorderConfiguration
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
- (instancetype)initWithIdentifier:(NSString *)identifier {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use subclass designated initializer" userInfo:nil];
}
- (instancetype)initWithIdentifier:(NSString *)identifier
recorderSettings:(NSDictionary *)recorderSettings {
self = [super initWithIdentifier:identifier];
if (self) {
if (recorderSettings && ![recorderSettings isKindOfClass:[NSDictionary class]]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"recorderSettings should be a dictionary" userInfo:recorderSettings];
}
_recorderSettings = recorderSettings;
}
return self;
}
#pragma clang diagnostic pop
- (ORKRecorder *)recorderForStep:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory {
return [[ORKAudioRecorder alloc] initWithIdentifier:self.identifier
recorderSettings:self.recorderSettings
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_OBJ_CLASS(aDecoder, recorderSettings, NSDictionary);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_OBJ(aCoder, recorderSettings);
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
ORKEqualObjects(self.recorderSettings, castObject.recorderSettings));
}
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionAudioRecording;
}
@end
-43
View File
@@ -1,43 +0,0 @@
/*
Copyright (c) 2015, 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:
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 Foundation;
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKAudioStep : ORKActiveStep
@end
NS_ASSUME_NONNULL_END
-70
View File
@@ -1,70 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKAudioStep.h"
#import "ORKAudioStepViewController.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@implementation ORKAudioStep
+ (Class)stepViewControllerClass {
return [ORKAudioStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
self.shouldStartTimerAutomatically = YES;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
NSTimeInterval const ORKAudioTaskMinimumDuration = 5.0;
if ( self.stepDuration < ORKAudioTaskMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKAudioTaskMinimumDuration)] userInfo:nil];
}
}
- (BOOL)startsFinished {
return NO;
}
@end
@@ -1,46 +0,0 @@
/*
Copyright (c) 2015, 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:
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 Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKAudioStepViewController : ORKActiveStepViewController
@property (nonatomic, assign) CGFloat alertThreshold;
@end
NS_ASSUME_NONNULL_END
@@ -1,191 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKAudioStepViewController.h"
#import "ORKActiveStepTimer.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 ()
@property (nonatomic, strong) AVAudioRecorder *avAudioRecorder;
@end
@implementation ORKAudioStepViewController {
ORKAudioContentView *_audioContentView;
ORKAudioRecorder *_audioRecorder;
ORKActiveStepTimer *_timer;
NSError *_audioRecorderError;
}
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
// Continue audio recording in the background
self.suspendIfInactive = NO;
}
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;
if (self.alertThreshold > 0) {
_audioContentView.alertThreshold = self.alertThreshold;
}
self.activeStepView.activeCustomView = _audioContentView;
}
- (void)audioRecorderDidChange {
_audioRecorder.audioRecorder.meteringEnabled = YES;
[self setAvAudioRecorder:_audioRecorder.audioRecorder];
}
- (void)recordersDidChange {
ORKAudioRecorder *audioRecorder = nil;
for (ORKRecorder *recorder in self.recorders) {
if ([recorder isKindOfClass:[ORKAudioRecorder class]]) {
audioRecorder = (ORKAudioRecorder *)recorder;
break;
}
}
_audioRecorder = audioRecorder;
[self audioRecorderDidChange];
}
- (ORKAudioStep *)audioStep {
return (ORKAudioStep *)self.step;
}
- (void)doSample {
if (_audioRecorderError) {
return;
}
[_avAudioRecorder updateMeters];
float value = [_avAudioRecorder averagePowerForChannel:0];
// Assume value is in range roughly -60dB to 0dB
float clampedValue = MAX(value / 60.0, -1) + 1;
[_audioContentView addSample:@(clampedValue)];
_audioContentView.timeLeft = [_timer duration] - [_timer runtime];
}
- (void)startNewTimerIfNeeded {
if (!_timer) {
NSTimeInterval duration = self.audioStep.stepDuration;
ORKWeakTypeOf(self) weakSelf = self;
_timer = [[ORKActiveStepTimer alloc] initWithDuration:duration interval:duration / 100 runtime:0 handler:^(ORKActiveStepTimer *timer, BOOL finished) {
ORKStrongTypeOf(self) strongSelf = weakSelf;
[strongSelf doSample];
if (finished) {
[strongSelf finish];
}
}];
[_timer resume];
}
_audioContentView.finished = NO;
}
- (void)start {
[super start];
[self audioRecorderDidChange];
[_timer reset];
_timer = nil;
[self startNewTimerIfNeeded];
}
- (void)suspend {
[super suspend];
[_timer pause];
if (_avAudioRecorder) {
[_audioContentView addSample:@(0)];
}
}
- (void)resume {
[super resume];
[self audioRecorderDidChange];
[self startNewTimerIfNeeded];
[_timer resume];
}
- (void)finish {
if (_audioRecorderError) {
return;
}
[super finish];
[_timer reset];
_timer = nil;
}
- (void)stepDidFinish {
_audioContentView.finished = YES;
}
- (void)setAvAudioRecorder:(AVAudioRecorder *)recorder {
_avAudioRecorder = nil;
_avAudioRecorder = recorder;
}
- (void)recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error {
[super recorder:recorder didFailWithError:error];
_audioRecorderError = error;
_audioContentView.failed = YES;
}
@end
@@ -1,53 +0,0 @@
/*
Copyright (c) 2015, 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:
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 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.
To use the countdown step, set the `duration` property, incorporate it into a
task, and present the task with a task view controller.
The countdown step is used in most of ResearchKit's predefined active tasks.
*/
ORK_CLASS_AVAILABLE
@interface ORKCountdownStep : ORKActiveStep
@end
NS_ASSUME_NONNULL_END
@@ -1,66 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKCountdownStep.h"
#import "ORKCountdownStepViewController.h"
@implementation ORKCountdownStep
+ (Class)stepViewControllerClass {
return [ORKCountdownStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldStartTimerAutomatically = YES;
self.shouldShowDefaultTimer = NO;
self.shouldContinueOnFinish = YES;
self.stepDuration = 5.0;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
NSTimeInterval const ORKCountdownStepMinimumDuration = 3.0;
if ( self.stepDuration < ORKCountdownStepMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKCountdownStepMinimumDuration)] userInfo:nil];
}
}
@end
@@ -1,51 +0,0 @@
/*
Copyright (c) 2015, 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:
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 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`.
It is not usually necessary to instantiate this view controller directly.
Instead, add a countdown step to a task, and present the task in a task
view controller.
*/
ORK_CLASS_AVAILABLE
@interface ORKCountdownStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -1,275 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKCountdownStepViewController.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepView.h"
#import "ORKCustomStepView_Internal.h"
#import "ORKLabel.h"
#import "ORKSubheadlineLabel.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStep.h"
#import "ORKResult.h"
#import "ORKAccessibility.h"
#import "ORKHelpers_Internal.h"
@interface ORKCountDownViewLabel : ORKLabel
@end
@implementation ORKCountDownViewLabel
+ (UIFont *)defaultFont {
return ORKThinFontWithSize(56);
}
@end
@interface ORKCountdownView : ORKActiveStepCustomView
@property (nonatomic, strong) ORKSubheadlineLabel *textLabel;
@property (nonatomic, strong) ORKCountDownViewLabel *timeLabel;
@property (nonatomic, strong) UIView *progressView;
- (void)startAnimateWithDuration:(NSTimeInterval)duration;
@end
@implementation ORKCountdownView {
CAShapeLayer *_circleLayer;
}
static const CGFloat ProgressIndicatorDiameter = 104.0;
static const CGFloat ProgressIndicatorOuterMargin = 1.0;
- (instancetype)init {
self = [super init];
if (self) {
_textLabel = [ORKSubheadlineLabel new];
_textLabel.textAlignment = NSTextAlignmentCenter;
_textLabel.translatesAutoresizingMaskIntoConstraints = NO;
_textLabel.text = ORKLocalizedString(@"COUNTDOWN_LABEL", nil);
[self addSubview:_textLabel];
_timeLabel = [ORKCountDownViewLabel new];
_timeLabel.translatesAutoresizingMaskIntoConstraints = NO;
_timeLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:_timeLabel];
_progressView = [UIView new];
_progressView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_progressView];
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setUpConstraints];
_circleLayer = [CAShapeLayer layer];
static const CGFloat ProgressIndicatorRadius = ProgressIndicatorDiameter / 2;
_circleLayer.path = [[UIBezierPath bezierPathWithArcCenter:CGPointMake(ProgressIndicatorRadius + ProgressIndicatorOuterMargin, ProgressIndicatorRadius + ProgressIndicatorOuterMargin)
radius:ProgressIndicatorRadius
startAngle:M_PI + M_PI_2
endAngle:-M_PI_2
clockwise:NO] CGPath];
_circleLayer.fillColor = [UIColor clearColor].CGColor;
_circleLayer.strokeColor = self.tintColor.CGColor;
_circleLayer.lineWidth = 1;
[_progressView.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
[_progressView.layer addSublayer:_circleLayer];
_textLabel.isAccessibilityElement = NO;
_timeLabel.isAccessibilityElement = NO;
}
return self;
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray new];
NSDictionary *metrics = @{@"d": @(ProgressIndicatorDiameter + 2 * ProgressIndicatorOuterMargin)};
NSDictionary *views = NSDictionaryOfVariableBindings(_textLabel, _timeLabel, _progressView);
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_textLabel]-(>=0)-[_progressView(==d)]|"
options:NSLayoutFormatDirectionLeadingToTrailing | NSLayoutFormatAlignAllCenterX
metrics:metrics
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_textLabel]-(>=0)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_progressView(==d)]-(>=0)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timeLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_progressView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
// Constant required in order to give appearance of vertical centering (compensating for leading on font)
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timeLabel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:_progressView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:-3.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_textLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1.0
constant:16.0 - ProgressIndicatorOuterMargin]];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)tintColorDidChange {
_circleLayer.strokeColor = self.tintColor.CGColor;
}
- (void)startAnimateWithDuration:(NSTimeInterval)duration {
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.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[_circleLayer addAnimation:animation forKey:@"drawCircleAnimation"];
}
#pragma mark Accessibility
- (BOOL)isAccessibilityElement {
return YES;
}
- (NSString *)accessibilityLabel {
return ORKAccessibilityStringForVariables(_textLabel.accessibilityLabel, _timeLabel.accessibilityLabel);
}
- (UIAccessibilityTraits)accessibilityTraits {
return [super accessibilityTraits] | UIAccessibilityTraitUpdatesFrequently;
}
@end
@interface ORKCountdownStepViewController ()
@property (nonatomic, strong) ORKCountdownView *countdownView;
@end
@implementation ORKCountdownStepViewController {
NSInteger _countDown;
}
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = NO;
}
return self;
}
- (void)setStep:(ORKStep *)step {
[super setStep:step];
_countDown = round([(ORKActiveStep *)step stepDuration]);
}
- (void)viewDidLoad {
[super viewDidLoad];
self.learnMoreButtonItem = nil;
_countdownView = [[ORKCountdownView alloc] init];
_countdownView.translatesAutoresizingMaskIntoConstraints = NO;
self.activeStepView.activeCustomView = _countdownView;
[self updateCountdownLabel];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @(_countDown).stringValue);
[_countdownView startAnimateWithDuration:[(ORKActiveStep *)self.step stepDuration]];
}
- (void)updateCountdownLabel {
_countdownView.timeLabel.text = ORKLocalizedStringFromNumber(@(_countDown));
}
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished {
_countDown = MAX((_countDown - 1), 0);
[self updateCountdownLabel];
if (UIAccessibilityIsVoiceOverRunning()) {
if (finished) {
[[NSNotificationCenter defaultCenter] addObserverForName:UIAccessibilityAnnouncementDidFinishNotification
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIAccessibilityAnnouncementDidFinishNotification object:nil];
[super countDownTimerFired:timer finished:finished];
}];
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, ORKLocalizedString(@"AX_ANNOUNCE_BEGIN_TASK", nil));
} else {
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @(_countDown).stringValue);
[super countDownTimerFired:timer finished:finished];
}
} else {
[super countDownTimerFired:timer finished:finished];
}
}
@end
-582
View File
@@ -1,582 +0,0 @@
/*
Copyright (c) 2015, 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:
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 Foundation;
#import <ResearchKit/ORKTypes.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKDataLogger;
@class HKUnit;
/**
The `ORKDataLoggerDelegate` protocol defines methods that the delegate of an `ORKDataLogger` object uses to handle data being logged to disk.
*/
@protocol ORKDataLoggerDelegate <NSObject>
/**
Tells the delegate when a log file rollover occurs.
@param dataLogger The data logger providing the notification.
@param fileUrl The URL of the newly renamed log file.
*/
- (void)dataLogger:(ORKDataLogger *)dataLogger finishedLogFile:(NSURL *)fileUrl;
@optional
/**
Tells the delegate if the number of bytes in completed logs changes.
When files are removed or added, or marked as uploaded or unmarked, this delegate method is called a short time later. Multiple directory changes
are rolled up into a single delegate callback.
@param dataLogger The data logger providing the notification.
*/
- (void)dataLoggerByteCountsDidChange:(ORKDataLogger *)dataLogger;
@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;
/**
The `ORKDataLogger` class is an internal component used by some `ORKRecorder`
subclasses for writing data to disk during tasks. An `ORKDataLogger` object manages one log as a set of files in a directory.
The current log file is at `directory/logName`.
Historic log files are at `directory/logName-(timestamp)-(count)`
where timestamp is of the form `YYYYMMddHHmmss` (Zulu) and indicates the time
the log finished (that is, was rolled over). If more than one rollover occurs within
one second, additional log files may be created with increasing `count`.
The user is responsible for managing the historic log files, but the `ORKDataLogger` class
provides tools for enumerating them (in sorted order).
The data logger contains a concept of whether a file has been uploaded, which
is tracked using file attributes. This feature can facilitate a workflow in which
log files are archived and queued for upload before actually sending them to
a server. When archived and ready for upload, the files could be marked uploaded
by the `ORKDataLogger`. When the upload is complete and the data has been handed
off downstream, the files can then be deleted. If the upload fails, the uploaded
files can have that flag cleared, to indicate that they should be included
in the next archiving attempt.
*/
ORK_CLASS_AVAILABLE
@interface ORKDataLogger : NSObject
/**
Returns a data logger with an `ORKJSONLogFormatter`.
@param url The URL of the directory in which to place log files.
@param logName The prefix on the log file name in an ASCII string. Note that the string must not contain the hyphen character ("-"), because a hyphen is used as a separator in the log naming scheme.
@param delegate The initial delegate. May be `nil`.
*/
+ (ORKDataLogger *)JSONDataLoggerWithDirectory:(NSURL *)url logName:(NSString *)logName delegate:(nullable id<ORKDataLoggerDelegate>)delegate;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/**
Returns an initialized data logger using the specified URL, log name, formatter, and delegate.
@param url The URL of the directory in which to place log files
@param logName The prefix on the log file name in an ASCII string. Note that
the string must not contain the hyphen character ("-"), because a hyphen is used as a separator in the log naming scheme.
@param formatter The type of formatter to use for the log, such as `ORKJSONLogFormatter`.
@param delegate The initial delegate. May be `nil`.
@return An initialized data logger.
*/
- (instancetype)initWithDirectory:(NSURL *)url logName:(NSString *)logName formatter:(ORKLogFormatter *)formatter delegate:(nullable id<ORKDataLoggerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
/// The delegate to be notified when file sizes change or the log rolls over.
@property (weak, nullable) id<ORKDataLoggerDelegate> delegate;
/// The log formatter being used.
@property (strong, readonly) ORKLogFormatter *logFormatter;
/**
The maximum current log file size.
When the current log reaches this size, it is automatically rolled over.
*/
@property size_t maximumCurrentLogFileSize;
/**
The maximum current log file lifetime.
When the current log file has been active this long, it is rolled over.
*/
@property NSTimeInterval maximumCurrentLogFileLifetime;
/// The number of bytes of log data that are not marked uploaded, excluding the current file. This value is lazily updated.
@property unsigned long long pendingBytes;
/// The number of bytes of log data that are marked uploaded. This value is lazily updated.
@property unsigned long long uploadedBytes;
/// The file protection mode to use for newly created files.
@property (assign) ORKFileProtectionMode fileProtectionMode;
/// The prefix on the log file names.
@property (copy, readonly) NSString *logName;
/// Forces a roll-over now.
- (void)finishCurrentLog;
/// The current log file's location.
- (NSURL *)currentLogFileURL;
/**
Enumerates the URLs of completed log files, sorted to put the oldest first.
Takes a snapshot of the current directory's relevant files, sorts them,
and enumerates them. Errors can occur if changes are being made to the filesystem other
than through this object.
@param block The block to call during enumeration.
@param error Any error detected during the enumeration.
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
/**
Enumerates the URLs of completed log files not yet marked uploaded,
sorted to put the oldest first.
This method takes a snapshot of the current directory's completed nonuploaded log files, sorts them,
and then enumerates them. Errors can occur if changes are being made to the filesystem other
than through this object.
@param block The block to call during enumeration.
@param error Any error detected during the enumeration.
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
/**
Enumerates the URLs of completed log files not already marked uploaded,
sorted to put the oldest first.
Takes a snapshot of the current directory's completed uploaded log files, sorts them,
and then enumerates them. Errors can occur if changes are being made to the filesystem other
than through this object.
@param block The block to call during enumeration.
@param error Any error detected during the enumeration.
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
/**
Appends an object to the log file, which is formatted with `logFormatter`.
The default log formatter expects NSData; call canAcceptLogObjectOfClass: on `logFormatter` to determine if it will accept this object.
Note that the current log file is created and opened lazily when a request to
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.
@return `YES` if appending succeeds; otherwise, `NO`.
*/
- (BOOL)append:(id)object error:(NSError * _Nullable *)error;
/**
Appends multiple objects to the log file.
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.
@return `YES` if appending succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * _Nullable *)error;
/**
Checks whether a file has been marked as uploaded.
@param url The URL to check.
@return `YES` if the uploaded attribute has been set on the file and the file exists; otherwise,
`NO`.
*/
- (BOOL)isFileUploadedAtURL:(NSURL *)url;
/**
Marks or unmarks a file as uploaded.
This method uses an extended attribute on the filesystem to mark a file as uploaded.
This is intended for book-keeping use only and to track which files have already
been attached to a pending upload. When the upload is sufficiently complete,
the file should be removed.
@param uploaded A Boolean value that indicates whether to mark the file uploaded or not uploaded.
@param url The URL to mark.
@param error The error that occurred, if the operation fails.
@return `YES` if adding or removing the attribute succeeded; otherwise, `NO`.
*/
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * _Nullable *)error;
/**
Removes files if they are marked uploaded.
If a file is in the list, but is no longer marked uploaded, this method does not remove the file. This workflow lets you unmark files selectively if they could not be added
to the archive, and later call `removeUploadedFiles:withError:` to remove only
the files that are still marked uploaded.
@param fileURLs The array of files that should be removed.
@param error The error that occurred, if the operation fails.
@return `YES` if removing the files succeeded; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * _Nullable *)error;
/**
Removes all files managed by this logger (files that have the `logName` prefix).
@param error The error that occurred, if operation fails.
@return `YES` if removing the files succeeded.; otherwise, `NO`.
*/
- (BOOL)removeAllFilesWithError:(NSError * _Nullable *)error;
@end
/**
The `ORKLogFormatter` class represents the base (default) log formatter, which appends data
blindly to a log file.
A log formatter is used by a data logger to format objects
for output to the log, and to begin a new log file and end an existing log file.
`ORKLogFormatter` accepts NSData and has neither a header nor a footer.
A log formatter should ensure that the log is always in a valid state, so that
even if the app is killed, the log is still readable.
*/
@interface ORKLogFormatter : NSObject
/**
Returns a Boolean value that indicates whether the log formatter can serialize the specified type of object.
@param c The class of object to serialize.
@return `YES` if the log formatter can serialize this object class; otherwise, `NO`.
*/
- (BOOL)canAcceptLogObjectOfClass:(Class)c;
/**
Returns a Boolean value that indicates whether the log formatter can serialize the specified type of object.
@param object The object to serialize.
@return `YES` if the log formatter can serialize `object`; otherwise, `NO`
*/
- (BOOL)canAcceptLogObject:(id)object;
/**
Begins a new log file on the specified file handle.
For example, may write a header or opening stanza of a new log file.
@param fileHandle The file handle to which to write.
@param error The error output, on failure.
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
/**
Appends the specified object to the log file.
@param object The object to write.
@param fileHandle The file handle to which to write.
@param error The error output, on failure.
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
/**
Appends the specified objects to the log file.
@param objects The objects to write.
@param fileHandle The file handle to which to write.
@param error The error output, on failure.
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
@end
/**
The `ORKJSONLogFormatter` class represents a log formatter for producing JSON output.
The JSON log formatter accepts `NSDictionary` objects for serialization.
The JSON output is a dictionary that contains one key, `items`,
which contains the array of logged items. The log itself does not contain
any timestamp information, so the items should include such fields,
if desired.
*/
ORK_CLASS_AVAILABLE
@interface ORKJSONLogFormatter : ORKLogFormatter
@end
@class ORKJSONDataLogger;
@class ORKDataLoggerManager;
/**
The `ORKDataLoggerManagerDelegate` protocol defines methods a delegate can implement to receive notifications
when the data loggers managed by a `ORKDataLoggerManager` reach a certain file size threshold.
*/
ORK_CLASS_AVAILABLE
@protocol ORKDataLoggerManagerDelegate <NSObject>
/**
Called by the data logger manager when the total size of files
that are not marked uploaded has reached a threshold.
@param dataLoggerManager The manager that produced the notification.
@param pendingUploadBytes The number of bytes managed by all the loggers, which
have not yet been marked uploaded.
*/
- (void)dataLoggerManager:(ORKDataLoggerManager *)dataLoggerManager pendingUploadBytesReachedThreshold:(unsigned long long)pendingUploadBytes;
/**
Called by the data logger manager when the total size of files
managed by any of the loggers has reached a threshold.
@param dataLoggerManager The manager that produced the notification.
@param totalBytes The total number of bytes of all files managed.
*/
- (void)dataLoggerManager:(ORKDataLoggerManager *)dataLoggerManager totalBytesReachedThreshold:(unsigned long long)totalBytes;
@end
/**
The `ORKDataLoggerManager` class represents a manager for multiple `ORKDataLogger` instances,
which tracks the total size of log files produced and can notify its delegate
when file sizes reach configurable thresholds.
The `ORKDataLoggerManager` class is an internal component used by some `ORKRecorder`
subclasses for writing data to disk during tasks.
This manager can be used to organize the `ORKDataLogger` logs in a directory,
and keep track of the total number of bytes stored on disk by each logger. The
delegate can be informed if either the number of bytes pending upload, or the total
number of bytes, exceeds configurable thresholds.
The configuration of the loggers and their thresholds is persisted in a
configuration file in the log directory.
If the number of bytes pending upload exceeds the threshold, the natural action is to
upload them. A block-based enumeration is provided for enumerating all the logs
pending upload. Use `enumerateLogsNeedingUpload:error:`, and when a log has been
processed for upload, use the logger to mark it uploaded.
When the upload succeeds (or at least is successfully queued), the uploaded files
can be removed across all the loggers by calling `removeUploadedFiles:error:`
If the total number of bytes exceeds the threshold, the natural action is to remove log
files that have been marked uploaded, and then remove old log files until the
threshold is no longer exceeded. You can do this by calling `removeOldAndUploadedLogsToThreshold:error:`
*/
ORK_CLASS_AVAILABLE
@interface ORKDataLoggerManager : NSObject <ORKDataLoggerDelegate>
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/**
Returns an initialized data logger manager using the specified directory and delegate.
Designated initializer.
@param directory The file URL of the directory where the data loggers should coexist.
@param delegate The delegate to receive notifications.
@return An initialized data logger manager.
*/
- (instancetype)initWithDirectory:(NSURL *)directory delegate:(nullable id<ORKDataLoggerManagerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
/// The delegate of the data logger manager.
@property (weak, nullable) id<ORKDataLoggerManagerDelegate> delegate;
/// The threshold for delegate callback for total bytes not marked uploaded.
@property unsigned long long pendingUploadBytesThreshold;
/// The threshold for delegate callback for total bytes of completed logs.
@property unsigned long long totalBytesThreshold;
/// The total number of bytes of files not marked as pending upload.
@property unsigned long long pendingUploadBytes;
/// The total number of bytes for all the loggers.
@property unsigned long long totalBytes;
/**
Adds a data logger with a JSON log format to the directory.
This method throws an exception if a logger already exists with the specified log name.
@param logName The log name prefix for the data logger.
@return The `ORKDataLogger` object that was added.
*/
- (ORKDataLogger *)addJSONDataLoggerForLogName:(NSString *)logName;
/**
Adds a data logger with a particular formatter to the directory.
@param logName The log name prefix for the data logger.
@param formatter The log formatter instance to use for this logger.
@return The `ORKDataLogger` object that was added, or the existing one if one already existed for
that log name.
*/
- (ORKDataLogger *)addDataLoggerForLogName:(NSString *)logName formatter:(ORKLogFormatter *)formatter;
/**
Retrieves the already existing data logger for a log name.
@param logName The log name prefix for the data logger.
@return The `ORKDataLogger` object that was retrieved, or `nil` if one already existed for that log name.
*/
- (nullable ORKDataLogger *)dataLoggerForLogName:(NSString *)logName;
/**
Removes a data logger.
@param logger The logger to remove.
*/
- (void)removeDataLogger:(ORKDataLogger *)logger;
/// Returns the set of log names of the data loggers managed by this object.
- (NSArray<NSString *> *)logNames;
/**
Enumerates all the logs that need upload across all data loggers, sorted from oldest to first.
Before sorting the logs, this method fetches all the data loggers' logs that need upload.
@param block The block to call during enumeration.
@param error The error, on failure.
@return `YES` if the enumeration succeeds; otherwise, `NO`.
*/
- (BOOL)enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
/**
Unmarks the set of uploaded files.
Use this method to indicate that the specified files should no longer be marked uploaded (for example, because
the upload did not succeed).
@param fileURLs The array of file URLs that should no longer be marked uploaded.
@param error The error, on failure.
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable *)error;
/**
Removes a set of uploaded files.
This method is analogous to a similar method in `ORKDataLogger`, but it accepts an array of files
that may relate to any of the data loggers. It is an error to pass a URL which would not
belong to one of the loggers managed by this manager.
@param fileURLs The array of file URLs that should be removed.
@param error The error, on failure.
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable *)error;
/**
Removes old and uploaded logs to bring total bytes down to a threshold.
This method removes uploaded logs first, followed by the oldest log files across
all of the data loggers, until the total usage falls below a threshold.
@param bytes The threshold down to which to remove old log files. File removal stops when the total bytes managed by all the data loggers reaches this threshold.
@param error The error, on failure.
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (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
NS_ASSUME_NONNULL_END
File diff suppressed because it is too large Load Diff
@@ -1,79 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class CMDeviceMotion;
@protocol ORKDeviceMotionRecorderDelegate <ORKRecorderDelegate>
@optional
- (void)deviceMotionRecorderDidUpdateWithMotion:(CMDeviceMotion *)motion;
@end
/**
The `ORKDeviceMotionRecorder` class represents a recorder that requests and collects device motion data from CoreMotion at a fixed frequency.
To ensure that the motion recorder continues to record when the app enters the
background, use the background task support provided by `UIApplication`.
*/
ORK_CLASS_AVAILABLE
@interface ORKDeviceMotionRecorder : ORKRecorder
/**
The frequency of motion data collection from CoreMotion in hertz (Hz).
*/
@property (nonatomic, readonly) double frequency;
/**
Returns an initialized device motion recorder using the specified frequency.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param frequency The frequency of motion data collection from CoreMotion in hertz (Hz).
@param step The step that requested this recorder.
@param outputDirectory The directory in which the device motion data should be stored.
@return An initialized motion data recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier
frequency:(double)frequency
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END
@@ -1,224 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKDeviceMotionRecorder.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Internal.h"
#import "ORKHelpers_Internal.h"
#import "CMDeviceMotion+ORKJSONDictionary.h"
@import CoreMotion;
@interface ORKDeviceMotionRecorder () {
ORKDataLogger *_logger;
}
@property (nonatomic, strong) CMMotionManager *motionManager;
@property (nonatomic) NSTimeInterval uptime;
@end
@implementation ORKDeviceMotionRecorder
- (instancetype)initWithIdentifier:(NSString *)identifier
frequency:(double)frequency
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier
step:step
outputDirectory:outputDirectory];
if (self) {
self.frequency = frequency;
self.continuesInBackground = YES;
}
return self;
}
- (void)dealloc {
[_logger finishCurrentLog];
}
- (void)setFrequency:(double)frequency {
if (frequency <= 0) {
_frequency = 1;
} else {
_frequency = frequency;
}
}
- (CMMotionManager *)createMotionManager {
return [[CMMotionManager alloc] init];
}
- (void)start {
[super start];
if (!_logger) {
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
if (!_logger) {
[self finishRecordingWithError:error];
return;
}
}
self.motionManager = [self createMotionManager];
self.motionManager.deviceMotionUpdateInterval = 1.0 / _frequency;
self.uptime = [NSProcessInfo processInfo].systemUptime;
[self.motionManager stopDeviceMotionUpdates];
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *data, NSError *error) {
BOOL success = NO;
if (data) {
success = [_logger append:[data ork_JSONDictionary] error:&error];
id delegate = self.delegate;
if ([delegate respondsToSelector:@selector(deviceMotionRecorderDidUpdateWithMotion:)]) {
[delegate deviceMotionRecorderDidUpdateWithMotion:data];
}
}
if (!success) {
dispatch_async(dispatch_get_main_queue(), ^{
[self finishRecordingWithError:error];
});
}
}];
}
- (NSString *)recorderType {
return @"deviceMotion";
}
- (void)stop {
[self doStopRecording];
[_logger finishCurrentLog];
NSError *error = nil;
__block NSURL *fileUrl = nil;
[_logger enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
fileUrl = logFileUrl;
} error:&error];
[self reportFileResultWithFile:fileUrl error:error];
[super stop];
}
- (void)doStopRecording {
if (self.isRecording) {
[self.motionManager stopDeviceMotionUpdates];
self.motionManager = nil;
}
}
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
- (BOOL)isRecording {
return self.motionManager.deviceMotionActive;
}
- (NSString *)mimeType {
return @"application/json";
}
- (void)reset {
[super reset];
_logger = nil;
}
@end
@implementation ORKDeviceMotionRecorderConfiguration
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
- (instancetype)initWithIdentifier:(NSString *)identifier {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use subclass designated initializer" userInfo:nil];
}
- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)freq {
self = [super initWithIdentifier:identifier];
if (self) {
_frequency = freq;
}
return self;
}
#pragma clang diagnostic pop
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKDeviceMotionRecorder alloc] initWithIdentifier:self.identifier
frequency:self.frequency
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_DOUBLE(aDecoder, frequency);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_DOUBLE(aCoder, frequency);
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
(self.frequency == castObject.frequency));
}
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionCoreMotionAccelerometer;
}
@end
@@ -1,53 +0,0 @@
/*
Copyright (c) 2015, 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:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKFitnessContentView : ORKActiveStepCustomView
@property (nonatomic, assign, getter=isFinished) BOOL finished;
@property (nonatomic) BOOL hasHeartRate;
@property (nonatomic) BOOL hasDistance;
@property (nonatomic, copy, nullable) NSString *heartRate;
@property (nonatomic) double distanceInMeters;
@property (nonatomic, strong, nullable) UIImage *image;
@property (nonatomic, assign) NSTimeInterval timeLeft;
@end
NS_ASSUME_NONNULL_END
@@ -1,346 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKFitnessContentView.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
@interface ORKFitnessContentView () {
ORKQuantityLabel *_timerLabel;
ORKQuantityPairView *_quantityPairView;
UIView *_imageSpacer1;
UIView *_imageSpacer2;
ORKTintedImageView *_imageView;
NSLengthFormatter *_lengthFormatter;
NSLayoutConstraint *_imageRatioConstraint;
NSLayoutConstraint *_topConstraint;
}
@end
@implementation ORKFitnessContentView
- (ORKActiveStepQuantityView *)distanceView {
return _quantityPairView.leftView;
}
- (ORKActiveStepQuantityView *)heartRateView {
return _quantityPairView.rightView;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_timerLabel = [ORKQuantityLabel new];
_quantityPairView = [ORKQuantityPairView new];
_imageSpacer1 = [UIView new];
_imageSpacer1.translatesAutoresizingMaskIntoConstraints = NO;
_imageSpacer2 = [UIView new];
_imageSpacer2.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_imageSpacer1];
[self addSubview:_imageSpacer2];
[self heartRateView].image = [UIImage imageNamed:@"heart-fitness" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
[self updateLengthFormatter];
_imageView = [ORKTintedImageView new];
_imageView.contentMode = UIViewContentModeScaleAspectFit;
_imageView.shouldApplyTint = YES;
_timerLabel.translatesAutoresizingMaskIntoConstraints = NO;
_quantityPairView.translatesAutoresizingMaskIntoConstraints = NO;
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
self.translatesAutoresizingMaskIntoConstraints = NO;
[self updateKeylineVisible];
_timerLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
_imageView.isAccessibilityElement = NO;
self.hasHeartRate = _hasHeartRate;
self.hasDistance = _hasDistance;
#if LAYOUT_TEST
self.timeLeft = 60 * 5;
self.hasHeartRate = YES;
self.hasDistance = YES;
self.distanceInMeters = 100;
self.heartRate = @"22";
#endif
#if LAYOUT_DEBUG
self.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.2];
_quantityPairView.backgroundColor = [[UIColor orangeColor] colorWithAlphaComponent:0.2];
#endif
[self setDistanceInMeters:0];
[self heartRateView].title = ORKLocalizedString(@"FITNESS_HEARTRATE_TITLE", nil);
[self addSubview:_quantityPairView];
[self addSubview:_imageView];
[self addSubview:_timerLabel];
[self setUpConstraints];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localeDidChange:) name:NSCurrentLocaleDidChangeNotification object:nil];
[self tintColorDidChange];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)updateLengthFormatter {
_lengthFormatter = [NSLengthFormatter new];
_lengthFormatter.numberFormatter.maximumFractionDigits = 1;
_lengthFormatter.numberFormatter.maximumSignificantDigits = 3;
}
- (void)localeDidChange:(NSNotification *)notification {
[self updateLengthFormatter];
[self setDistanceInMeters:_distanceInMeters];
}
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
[self updateConstraintConstantsForWindow:newWindow];
}
- (void)updateConstraintConstantsForWindow:(UIWindow *)window {
const CGFloat CaptionBaselineToTimerTop = ORKGetMetricForWindow(ORKScreenMetricCaptionBaselineToFitnessTimerTop, window);
const CGFloat CaptionBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window);
_topConstraint.constant = (CaptionBaselineToTimerTop - CaptionBaselineToStepViewTop);
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_timerLabel, _imageView, _quantityPairView, _imageSpacer1, _imageSpacer2);
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_timerLabel][_imageSpacer1(>=0)][_imageView]"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
_topConstraint = [NSLayoutConstraint constraintWithItem:_timerLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];
[constraints addObject:_topConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timerLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timerLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_imageView][_imageSpacer2(>=0)][_quantityPairView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_imageSpacer2
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0.0]];
NSLayoutConstraint *imageSpacerHeightConstraint = [NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
imageSpacerHeightConstraint.priority = UILayoutPriorityDefaultLow - 1;
[constraints addObject:imageSpacerHeightConstraint];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_quantityPairView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
maxWidthConstraint.priority = UILayoutPriorityRequired - 1;
[constraints addObject:maxWidthConstraint];
[NSLayoutConstraint activateConstraints:constraints];
[self updateConstraintConstantsForWindow:self.window];
}
- (void)setImage:(UIImage *)image {
_image = image;
_imageView.image = image;
_imageRatioConstraint.active = NO;
CGSize size = image.size;
if (size.width > 0 && size.height > 0) {
_imageRatioConstraint = [NSLayoutConstraint constraintWithItem:_imageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_imageView
attribute:NSLayoutAttributeWidth
multiplier:size.height / size.width
constant:0.0];
_imageRatioConstraint.active = YES;
}
}
- (void)setHasDistance:(BOOL)hasDistance {
_hasDistance = hasDistance;
[self distanceView].enabled = _hasDistance;
[self updateKeylineVisible];
}
- (void)setHasHeartRate:(BOOL)hasHeartRate {
_hasHeartRate = hasHeartRate;
[self heartRateView].enabled = _hasHeartRate;
[self updateKeylineVisible];
}
- (void)setHeartRate:(NSString *)heartRate {
_heartRate = heartRate;
[self heartRateView].value = heartRate;
}
- (void)updateKeylineVisible {
[_quantityPairView setKeylineHidden:!(_hasDistance && _hasHeartRate)];
}
- (void)setDistanceInMeters:(double)distanceInMeters {
_distanceInMeters = distanceInMeters;
double displayDistance = _distanceInMeters;
NSString *distanceString = nil;
NSLengthFormatterUnit unit;
NSString *unitString = [_lengthFormatter unitStringFromMeters:displayDistance usedUnit:&unit];
switch (unit) {
case NSLengthFormatterUnitCentimeter:
case NSLengthFormatterUnitMillimeter:
unit = NSLengthFormatterUnitMeter;
// Force showing 0 meters if the distance is sufficiently short to be displayed in cm or mm
unitString = [_lengthFormatter unitStringFromValue:0 unit:NSLengthFormatterUnitMeter];
displayDistance = 0;
break;
default:
break;
}
// Use HealthKit to convert the unit, so we can use the number formatter directly.
HKUnit *hkUnit = [HKUnit unitFromLengthFormatterUnit:unit];
double conversionFactor = 1.0;
if ([hkUnit isNull] && (unit == NSLengthFormatterUnitYard)) {
hkUnit = [HKUnit footUnit];
conversionFactor = 1.0 / 3.0;
}
HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit meterUnit] doubleValue:displayDistance];
distanceString = [_lengthFormatter.numberFormatter stringFromNumber:@([quantity doubleValueForUnit:hkUnit]*conversionFactor)];
[self distanceView].title = [NSString localizedStringWithFormat:ORKLocalizedString(@"FITNESS_DISTANCE_TITLE_FORMAT", nil), unitString];
[self distanceView].value = distanceString;
}
- (void)setTimeLeft:(NSTimeInterval)timeLeft {
_timeLeft = timeLeft;
[self updateTimerLabel];
}
- (void)updateTimerLabel {
static NSDateComponentsFormatter *formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateComponentsFormatter new];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
});
NSString *labelString = [formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = labelString;
_timerLabel.hidden = (labelString == nil);
}
@end
-52
View File
@@ -1,52 +0,0 @@
/*
Copyright (c) 2015, 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:
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 Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
/**
Fitness step.
Displays usual header, a counting-up timer, read outs for distance and/or
heart rate if corresponding recorders are attached.
Also displays an image during the task.
*/
ORK_CLASS_AVAILABLE
@interface ORKFitnessStep : ORKActiveStep
@end
NS_ASSUME_NONNULL_END
-70
View File
@@ -1,70 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKFitnessStep.h"
#import "ORKFitnessStepViewController.h"
@implementation ORKFitnessStep
+ (Class)stepViewControllerClass {
return [ORKFitnessStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
NSTimeInterval const ORKFitnessStepMinimumDuration = 5.0;
if (self.stepDuration < ORKFitnessStepMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"rest duration cannot be shorter than %@ seconds.", @(ORKFitnessStepMinimumDuration)] userInfo:nil];
}
}
- (instancetype)copyWithZone:(NSZone *)zone {
ORKFitnessStep *step = [super copyWithZone:zone];
return step;
}
- (BOOL)startsFinished {
return NO;
}
@end
@@ -1,50 +0,0 @@
/*
Copyright (c) 2015, 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:
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 Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
/**
Step view controller corresponding to `ORKFitnessStep`.
Observes countdown timer, heart rate, and distance, and relays these to the
screen during the task.
*/
ORK_CLASS_AVAILABLE
@interface ORKFitnessStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -1,153 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKFitnessStepViewController.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepView.h"
#import "ORKFitnessContentView.h"
#import "ORKVerticalContainerView.h"
#import "ORKStepViewController_Internal.h"
#import "ORKHealthQuantityTypeRecorder.h"
#import "ORKPedometerRecorder.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKFitnessStep.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@interface ORKFitnessStepViewController () <ORKHealthQuantityTypeRecorderDelegate, ORKPedometerRecorderDelegate> {
NSInteger _intendedSteps;
ORKFitnessContentView *_contentView;
NSNumberFormatter *_hrFormatter;
}
@end
@implementation ORKFitnessStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = NO;
}
return self;
}
- (ORKFitnessStep *)fitnessStep {
return (ORKFitnessStep *)self.step;
}
- (void)stepDidChange {
[super stepDidChange];
_hrFormatter = [[NSNumberFormatter alloc] init];
_hrFormatter.numberStyle = kCFNumberFormatterNoStyle;
_contentView.timeLeft = self.fitnessStep.stepDuration;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_contentView = [ORKFitnessContentView new];
_contentView.image = self.fitnessStep.image;
_contentView.timeLeft = self.fitnessStep.stepDuration;
self.activeStepView.activeCustomView = _contentView;
self.activeStepView.stepViewFillsAvailableSpace = YES;
}
- (void)updateHeartRateWithQuantity:(HKQuantitySample *)quantity unit:(HKUnit *)unit {
if (quantity != nil) {
_contentView.hasHeartRate = YES;
}
if (quantity) {
_contentView.heartRate = [_hrFormatter stringFromNumber:@([quantity.quantity doubleValueForUnit:unit])];
} else {
_contentView.heartRate = @"--";
}
}
- (void)updateDistance:(double)distanceInMeters {
_contentView.hasDistance = YES;
_contentView.distanceInMeters = distanceInMeters;
}
- (void)recordersDidChange {
[super recordersDidChange];
ORKPedometerRecorder *pedometerRecorder = nil;
ORKHealthQuantityTypeRecorder *heartRateRecorder = nil;
for (ORKRecorder *recorder in self.recorders) {
if ([recorder isKindOfClass:[ORKPedometerRecorder class]]) {
pedometerRecorder = (ORKPedometerRecorder *)recorder;
} else if ([recorder isKindOfClass:[ORKHealthQuantityTypeRecorder class]]) {
ORKHealthQuantityTypeRecorder *rec1 = (ORKHealthQuantityTypeRecorder *)recorder;
if ([[[rec1 quantityType] identifier] isEqualToString:HKQuantityTypeIdentifierHeartRate]) {
heartRateRecorder = (ORKHealthQuantityTypeRecorder *)recorder;
}
}
}
if (heartRateRecorder == nil) {
_contentView.hasHeartRate = NO;
}
_contentView.heartRate = @"--";
_contentView.hasDistance = (pedometerRecorder != nil);
_contentView.distanceInMeters = 0;
}
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished {
_contentView.timeLeft = finished ? 0 : (timer.duration - timer.runtime);
[super countDownTimerFired:timer finished:finished];
}
#pragma mark - ORKHealthQuantityTypeRecorderDelegate
- (void)healthQuantityTypeRecorderDidUpdate:(ORKHealthQuantityTypeRecorder *)healthQuantityTypeRecorder {
if ([[healthQuantityTypeRecorder.quantityType identifier] isEqualToString:HKQuantityTypeIdentifierHeartRate]) {
[self updateHeartRateWithQuantity:healthQuantityTypeRecorder.lastSample unit:healthQuantityTypeRecorder.unit];
}
}
#pragma mark - ORKPedometerRecorderDelegate
- (void)pedometerRecorderDidUpdate:(ORKPedometerRecorder *)pedometerRecorder {
double distanceInMeters = pedometerRecorder.totalDistance;
[self updateDistance:distanceInMeters];
}
@end
@@ -1,80 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class ORKHealthQuantityTypeRecorder;
@protocol ORKHealthQuantityTypeRecorderDelegate <ORKRecorderDelegate>
@optional
- (void)healthQuantityTypeRecorderDidUpdate:(ORKHealthQuantityTypeRecorder *)healthQuantityTypeRecorder;
@end
/**
The `ORKHealthQuantityTypeRecorder` class represents a recorder for collecting real time sample data from HealthKit, such as heart rate, during
an active task.
*/
ORK_CLASS_AVAILABLE
@interface ORKHealthQuantityTypeRecorder : ORKRecorder
@property (nonatomic, copy, readonly) HKQuantityType *quantityType;
@property (nonatomic, copy, readonly) HKUnit *unit;
@property (nonatomic, copy, readonly, nullable) HKQuantitySample *lastSample;
/**
Returns an initialized health quantity type recorder using the specified quantity type and unit.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param quantityType The quantity type that should be collected during the active task.
@param unit The unit for the data that should be collected and serialized.
@param step The step that requested this recorder.
@param outputDirectory The directory in which the HealthKit data should be stored.
@return An initialized health quantity type recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier
healthQuantityType:(HKQuantityType *)quantityType
unit:(HKUnit *)unit
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END
@@ -1,370 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKHealthQuantityTypeRecorder.h"
#import "ORKHelpers_Internal.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Private.h"
#import "ORKRecorder_Internal.h"
#import "HKSample+ORKJSONDictionary.h"
@interface ORKHealthQuantityTypeRecorder () {
ORKDataLogger *_logger;
BOOL _isRecording;
HKHealthStore *_healthStore;
NSPredicate *_samplePredicate;
HKObserverQuery *_observerQuery;
/// 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
- (instancetype)initWithIdentifier:(NSString *)identifier
healthQuantityType:(HKQuantityType *)quantityType
unit:(HKUnit *)unit
step:(ORKStep *)step
outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier
step:step
outputDirectory:outputDirectory];
if (self) {
NSParameterAssert(quantityType != nil);
NSParameterAssert(unit != nil);
// Quantity type and unit are immutable, so should be equivalent to -copy
_quantityType = quantityType;
_unit = unit;
self.continuesInBackground = YES;
_anchorValue = HKAnchoredObjectQueryNoAnchor;
_anchor = [HKQueryAnchor anchorFromValue:_anchorValue];
}
return self;
}
- (void)dealloc {
[_logger finishCurrentLog];
}
- (void)updateMostRecentSample:(HKQuantitySample *)sample {
[self willChangeValueForKey:@"lastSample"];
_lastSample = sample;
[self didChangeValueForKey:@"lastSample"];
id<ORKHealthQuantityTypeRecorderDelegate> delegate = (id<ORKHealthQuantityTypeRecorderDelegate>)self.delegate;
if (delegate && [delegate respondsToSelector:@selector(healthQuantityTypeRecorderDidUpdate:)]) {
[delegate healthQuantityTypeRecorderDidUpdate:self];
}
}
static const NSInteger _HealthAnchoredQueryLimit = 100;
- (void)query_logResults:(NSArray *)results withAnchor:(HKQueryAnchor*)newAnchor anchorValue:(NSUInteger)anchorValue {
NSUInteger resultCount = results.count;
if (resultCount == 0) {
return;
}
// Do conversion to dictionary on whatever queue we happen to be on.
NSMutableArray *dictionaries = [NSMutableArray arrayWithCapacity:resultCount];
[results enumerateObjectsUsingBlock:^(HKQuantitySample *sample, NSUInteger idx, BOOL *stop) {
[dictionaries addObject:[sample ork_JSONDictionaryWithOptions:ORKSampleIncludeSource|ORKSampleIncludeMetadata unit:_unit]];
}];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateMostRecentSample:results.lastObject];
NSError *error = nil;
if (![_logger appendObjects:dictionaries error:&error]) {
// Logger writes are unrecoverable
[self finishRecordingWithError:error];
return;
}
_anchor = newAnchor;
_anchorValue = anchorValue;
if (resultCount == _HealthAnchoredQueryLimit) {
// Do another fetch immediately rather than wait for an observation
[self doFetchNewData];
}
});
}
- (void)doFetchNewData {
if (!_healthStore || !_isRecording) {
return;
}
NSAssert(_samplePredicate != nil, @"Sample predicate should be non-nil if recording");
__weak typeof(self) weakSelf = self;
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];
}
- (void)start {
[super start];
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (!_logger) {
[self finishRecordingWithError:err];
return;
}
}
if (![HKHealthStore isHealthDataAvailable]) {
[self finishRecordingWithError:[NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}]];
return;
}
if (!_healthStore) {
// Get a new obsever query
_healthStore = [HKHealthStore new];
} else {
// Reset
if (_observerQuery) {
[_healthStore stopQuery:_observerQuery];
_observerQuery = nil;
}
}
_lastSample = nil;
_samplePredicate = [HKQuery predicateForSamplesWithStartDate:[NSDate date] endDate:nil options:HKQueryOptionStrictStartDate];
NSAssert(!_observerQuery, @"observer query should not exist if not recording");
__weak __typeof(self) weakSelf = self;
_observerQuery = [[HKObserverQuery alloc]
initWithSampleType:_quantityType
predicate:_samplePredicate
updateHandler:^(HKObserverQuery *query, HKObserverQueryCompletionHandler completionHandler, NSError *error) {
__typeof(self) strongSelf = weakSelf;
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
[strongSelf finishRecordingWithError:error];
} else {
[strongSelf doFetchNewData];
}
});
// Immediately signal receipt. We've fired off to either finish or do a new fetch.
completionHandler();
}];
_isRecording = YES;
[_healthStore executeQuery:_observerQuery];
}
- (NSString *)recorderType {
return _quantityType.identifier;
}
- (void)stop {
if (!_isRecording) {
return;
}
[self doStopRecording];
[_logger finishCurrentLog];
NSError *error = nil;
__block NSURL *fileUrl = nil;
[_logger enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
fileUrl = logFileUrl;
} error:&error];
[self reportFileResultWithFile:fileUrl error:error];
[super stop];
}
- (void)doStopRecording {
if (_isRecording) {
NSAssert(_observerQuery != nil, @"Observer query should be non-nil when recording");
[_healthStore stopQuery:_observerQuery];
_observerQuery = nil;
_samplePredicate = nil;
_isRecording = NO;
[self updateMostRecentSample:nil];
}
}
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
- (BOOL)isRecording {
return _isRecording;
}
- (NSString *)mimeType {
return @"application/json";
}
- (void)reset {
[super reset];
_logger = nil;
}
@end
@implementation ORKHealthQuantityTypeRecorderConfiguration
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
- (instancetype)initWithIdentifier:(NSString *)identifier {
@throw [NSException exceptionWithName:NSGenericException reason:@"Use subclass designated initializer" userInfo:nil];
}
- (instancetype)initWithIdentifier:(NSString *)identifier healthQuantityType:(HKQuantityType *)quantityType unit:(HKUnit *)unit {
self = [super initWithIdentifier:identifier];
if (self) {
NSParameterAssert(quantityType != nil);
NSParameterAssert(unit != nil);
// Quantity type and unit are immutable, so should be equivalent to -copy
_quantityType = quantityType;
_unit = unit;
}
return self;
}
#pragma clang diagnostic pop
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKHealthQuantityTypeRecorder alloc] initWithIdentifier:self.identifier
healthQuantityType:_quantityType
unit:_unit
step:step
outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_OBJ_CLASS(aDecoder, quantityType, HKQuantityType);
ORK_DECODE_OBJ_CLASS(aDecoder, unit, HKUnit);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
ORK_ENCODE_OBJ(aCoder, quantityType);
ORK_ENCODE_OBJ(aCoder, unit);
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame &&
ORKEqualObjects(self.quantityType, castObject.quantityType)&&
ORKEqualObjects(self.unit, castObject.unit));
}
- (NSSet *)requestedHealthKitTypesForReading {
return [NSSet setWithObject:_quantityType];
}
@end
@@ -1,66 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import "ORKTypes.h"
NS_ASSUME_NONNULL_BEGIN
@protocol ORKHolePegTestPlaceContentViewDelegate;
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceContentView : ORKActiveStepCustomView
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE;
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
- (instancetype)initWithMovingDirection:(ORKBodySagittal)movingDirection rotated:(BOOL)rotated NS_DESIGNATED_INITIALIZER;
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign) double threshold;
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@property (nonatomic, weak) id<ORKHolePegTestPlaceContentViewDelegate> delegate;
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated;
@end
@protocol ORKHolePegTestPlaceContentViewDelegate <NSObject>
- (void)holePegTestPlaceDidProgress:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView;
- (void)holePegTestPlaceDidSucceed:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView withDistance:(CGFloat)distance;
- (void)holePegTestPlaceDidFail:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView;
@end
NS_ASSUME_NONNULL_END
@@ -1,399 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKDirectionView.h"
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKHolePegTestPlacePegView.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
static const CGFloat ORKOrientationThreshold = 12.0f;
static const CGFloat ORKHolePegViewDiameter = 88.0f;
#define degreesToRadians(degrees) ((degrees) / 180.0 * M_PI)
@interface ORKHolePegTestPlaceContentView () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) ORKHolePegTestPlacePegView *pegView;
@property (nonatomic, strong) ORKHolePegTestPlaceHoleView *holeView;
@property (nonatomic, strong) ORKDirectionView *directionView;
@property (nonatomic, copy) NSArray *constraints;
@property (nonatomic, strong) UIPinchGestureRecognizer *pinchRecognizer;
@property (nonatomic, strong) UIPanGestureRecognizer *panRecognizer;
@property (nonatomic, strong) UIRotationGestureRecognizer *rotationRecognizer;
@property (nonatomic, assign, getter = isMovable) BOOL movable;
@property (nonatomic, assign, getter = hasMoveEnded) BOOL moveEnded;
@property (nonatomic, assign) CGFloat rotation;
@property (nonatomic, assign) CGFloat rotationOffset;
@property (nonatomic, assign) CGPoint translation;
@property (nonatomic, assign) CGPoint translationOffset;
@property (nonatomic, assign) CGPoint startPoint;
@end
@implementation ORKHolePegTestPlaceContentView
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithFrame:(CGRect)frame {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithMovingDirection:(ORKBodySagittal)movingDirection rotated:(BOOL)rotated {
self = [super initWithFrame:CGRectZero];
if (self) {
self.movingDirection = movingDirection;
self.rotated = rotated;
self.progressView = [UIProgressView new];
self.progressView.progressTintColor = self.tintColor;
[self.progressView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.progressView setAlpha:0];
[self addSubview:self.progressView];
self.holeView = [[ORKHolePegTestPlaceHoleView alloc] initWithFrame:CGRectMake(0, 0, ORKHolePegViewDiameter, ORKHolePegViewDiameter)];
self.holeView.rotated = self.isRotated;
[self.holeView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.holeView];
self.pegView = [[ORKHolePegTestPlacePegView alloc] initWithFrame:CGRectMake(0, 0, ORKHolePegViewDiameter, ORKHolePegViewDiameter)];
self.pegView.rotated = self.isRotated;
[self.pegView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.pegView];
self.directionView = [[ORKDirectionView alloc] initWithOrientation:(self.movingDirection == ORKBodySagittalLeft) ? ORKBodySagittalRight : ORKBodySagittalLeft];
[self.directionView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.directionView];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
[self setNeedsUpdateConstraints];
self.movable = NO;
self.moveEnded = NO;
self.startPoint = CGPointZero;
self.pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePinch:)];
self.pinchRecognizer.delegate = self;
[self addGestureRecognizer:self.pinchRecognizer];
self.panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePan:)];
self.panRecognizer.delegate = self;
[self addGestureRecognizer:self.panRecognizer];
if (rotated) {
self.rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self
action:@selector(handleRotate:)];
self.rotationRecognizer.delegate = self;
[self addGestureRecognizer:self.rotationRecognizer];
}
}
return self;
}
- (void)tintColorDidChange {
[super tintColorDidChange];
self.progressView.progressTintColor = self.tintColor;
}
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated {
[self.progressView setProgress:progress animated:animated];
[UIView animateWithDuration:animated ? 0.2 : 0 animations:^{
[self.progressView setAlpha:(progress == 0) ? 0 : 1];
}];
}
- (void)updateLayoutMargins {
CGFloat margin = ORKStandardHorizontalMarginForView(self);
self.layoutMargins = (UIEdgeInsets){.left = margin * 2, .right = margin * 2};
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self updateLayoutMargins];
}
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
[self updateLayoutMargins];
}
- (void)updateConstraints {
if ([self.constraints count]) {
[NSLayoutConstraint deactivateConstraints:self.constraints];
self.constraints = nil;
}
NSMutableArray *constraintsArray = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _pegView, _holeView, _directionView);
NSDictionary *metrics = @{@"diameter": @(ORKHolePegViewDiameter)};
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:(self.movingDirection == ORKBodySagittalLeft) ? @"H:|-[_pegView]->=0-[_holeView]-|" : @"H:|-[_holeView]->=0-[_pegView]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_progressView]"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|->=0-[_pegView(diameter)]->=0-|"
options:(NSLayoutFormatOptions)0
metrics:metrics views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|->=0-[_holeView]->=0-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.pegView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.directionView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.directionView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0]];
self.constraints = constraintsArray;
[self addConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:self.constraints];
[super updateConstraints];
}
#pragma mark - gesture recognizer methods
- (void)pickupPegWithGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
CGPoint touch = [gestureRecognizer locationInView:self];
CGPoint touch1 = [gestureRecognizer locationOfTouch:0 inView:self];
CGPoint touch2 = [gestureRecognizer locationOfTouch:1 inView:self];
double distance = hypot(touch1.x - touch2.x, touch1.y - touch2.y);
if (distance < 3 * CGRectGetWidth(self.pegView.frame) &&
CGRectContainsPoint(self.pegView.frame, touch)) {
self.movable = YES;
} else {
self.movable = NO;
}
}
- (void)handlePinch:(UIPinchGestureRecognizer *)pinchGestureRecognizer {
if ([pinchGestureRecognizer numberOfTouches] == 2) {
[self pickupPegWithGestureRecognizer:pinchGestureRecognizer];
}
}
- (void)handlePan:(UIPanGestureRecognizer *)panGestureRecognizer {
if ([panGestureRecognizer numberOfTouches] != 2 ||
panGestureRecognizer.state == UIGestureRecognizerStateEnded ||
panGestureRecognizer.state == UIGestureRecognizerStateCancelled ||
panGestureRecognizer.state == UIGestureRecognizerStateFailed) {
[self resetTransformAtPoint:[panGestureRecognizer locationInView:self]];
} else {
if (self.isMovable) {
self.translation = CGPointMake([panGestureRecognizer translationInView:self].x - self.translationOffset.x,
[panGestureRecognizer translationInView:self].y - self.translationOffset.y);
[self updateTransformAtPoint:[panGestureRecognizer locationInView:self]];
} else {
self.translationOffset = CGPointMake([panGestureRecognizer translationInView:self].x - self.translation.x,
[panGestureRecognizer translationInView:self].y - self.translation.y);
if (CGPointEqualToPoint(self.startPoint, CGPointZero)) {
[self pickupPegWithGestureRecognizer:panGestureRecognizer];
}
}
}
}
- (void)handleRotate:(UIRotationGestureRecognizer *)rotationGestureRecognizer {
if ([rotationGestureRecognizer numberOfTouches] != 2 ||
rotationGestureRecognizer.state == UIGestureRecognizerStateEnded ||
rotationGestureRecognizer.state == UIGestureRecognizerStateCancelled ||
rotationGestureRecognizer.state == UIGestureRecognizerStateFailed) {
[self resetTransformAtPoint:[rotationGestureRecognizer locationInView:self]];
} else {
if (self.isMovable) {
self.rotation = rotationGestureRecognizer.rotation - self.rotationOffset;
[self updateTransformAtPoint:[rotationGestureRecognizer locationInView:self]];
} else {
self.rotationOffset = rotationGestureRecognizer.rotation - self.rotation;
}
}
}
- (void)updateTransformAtPoint:(CGPoint)point {
self.pegView.transform = CGAffineTransformMakeTranslation(self.translation.x, self.translation.y);
self.pegView.transform = CGAffineTransformRotate(self.pegView.transform, self.rotation);
[self pegViewDidMoveAtPoint:point];
}
- (void)resetTransformAtPoint:(CGPoint)point {
if (!self.hasMoveEnded) {
self.movable = NO;
self.moveEnded = YES;
self.pinchRecognizer.enabled = NO;
self.panRecognizer.enabled = NO;
self.rotationRecognizer.enabled = NO;
BOOL animated = ![self pegViewMoveDidEndAtPoint:point];
self.pegView.hidden = !animated;
[UIView animateWithDuration:animated ? 0.15f : 0.0f
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^(){
self.pegView.transform = CGAffineTransformIdentity;
self.pegView.alpha = 1.0f;
}
completion:^(BOOL finished){
self.rotation = 0.0f;
self.rotationOffset = 0.0f;
self.translation = CGPointZero;
self.translationOffset = CGPointZero;
self.pinchRecognizer.enabled = YES;
self.panRecognizer.enabled = YES;
self.rotationRecognizer.enabled = YES;
self.moveEnded = NO;
self.pegView.hidden = NO;
}];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
#pragma mark - peg view delegate
- (void)pegViewDidMoveAtPoint:(CGPoint)point {
self.directionView.hidden = YES;
if (CGPointEqualToPoint(self.startPoint, CGPointZero)) {
self.startPoint = point;
}
if ([self.delegate respondsToSelector:@selector(holePegTestPlaceDidProgress:)]) {
[self.delegate holePegTestPlaceDidProgress:self];
}
if (self.holeView.isSuccess) {
self.holeView.success = NO;
}
if ([self holeViewContainsPegView]) {
self.pegView.alpha = 1.0f;
} else {
self.pegView.alpha = 0.2f;
}
}
- (BOOL)pegViewMoveDidEndAtPoint:(CGPoint)point {
self.directionView.hidden = NO;
BOOL succeeded = NO;
if ([self holeViewContainsPegView]) {
if ([self.delegate respondsToSelector:@selector(holePegTestPlaceDidSucceed:withDistance:)]) {
CGFloat distance = hypotf(point.x - self.startPoint.x, point.y - self.startPoint.y);
[self.delegate holePegTestPlaceDidSucceed:self withDistance:distance];
}
self.holeView.success = YES;
succeeded = YES;
} else {
if ([self.delegate respondsToSelector:@selector(holePegTestPlaceDidFail:)]) {
[self.delegate holePegTestPlaceDidFail:self];
}
self.holeView.success = NO;
}
self.startPoint = CGPointZero;
return succeeded;
}
- (BOOL)holeViewContainsPegView {
CGRect detectionFrame = CGRectMake(CGRectGetMidX(self.holeView.frame) - (self.threshold * CGRectGetWidth(self.holeView.frame) / 2),
CGRectGetMidY(self.holeView.frame) - (self.threshold * CGRectGetHeight(self.holeView.frame) / 2),
self.threshold * CGRectGetWidth(self.holeView.frame),
self.threshold * CGRectGetHeight(self.holeView.frame));
CGPoint pegCenter = CGPointMake(CGRectGetMaxX(self.pegView.frame) - CGRectGetWidth(self.pegView.frame) / 2,
CGRectGetMaxY(self.pegView.frame) - CGRectGetHeight(self.pegView.frame) / 2);
if (CGRectContainsPoint(detectionFrame, pegCenter)) {
if (self.isRotated) {
double rotation = atan2(self.pegView.transform.b, self.pegView.transform.a);
double angle = fmod(fabs(rotation), M_PI_2);
if (angle > M_PI_4 - degreesToRadians(ORKOrientationThreshold) &&
angle < M_PI_4 + degreesToRadians(ORKOrientationThreshold)) {
return YES;
}
} else {
return YES;
}
}
return NO;
}
@end
@@ -1,46 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceHoleView : UIView <CAAnimationDelegate>
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@property (nonatomic, assign, getter = isSuccess) BOOL success;
@end
NS_ASSUME_NONNULL_END
@@ -1,173 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKHelpers_Internal.h"
static const CGFloat ORKPlaceHoleViewRotation = 45.0f;
@interface ORKHolePegTestPlaceHoleView ()
@property (nonatomic, strong) CAShapeLayer *checkLayer;
@property (nonatomic, strong) CAShapeLayer *crossLayer;
@end
@implementation ORKHolePegTestPlaceHoleView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(27.7f, 46.9f)];
[path addLineToPoint:CGPointMake(36.1f, 56.3f)];
[path addLineToPoint:CGPointMake(62.8f, 30.3f)];
path.lineCapStyle = kCGLineCapRound;
path.lineWidth = 3.6f;
CAShapeLayer *checkLayer = [CAShapeLayer new];
checkLayer.path = path.CGPath;
checkLayer.lineWidth = 3.6f;
checkLayer.lineCap = kCALineCapRound;
checkLayer.lineJoin = kCALineJoinRound;
checkLayer.frame = self.layer.bounds;
checkLayer.strokeColor = self.tintColor.CGColor;
checkLayer.backgroundColor = [UIColor clearColor].CGColor;
checkLayer.fillColor = nil;
self.checkLayer = checkLayer;
self.opaque = NO;
self.success = NO;
}
return self;
}
- (CGSize)intrinsicContentSize {
return CGSizeMake(self.frame.size.width, self.frame.size.height);
}
#pragma mark - drawing method
- (void)tintColorDidChange {
[super tintColorDidChange];
self.checkLayer.strokeColor = self.tintColor.CGColor;
[self setNeedsDisplay];
}
- (void)setSuccess:(BOOL)success
{
_success = success;
[self.checkLayer removeFromSuperlayer];
[self.crossLayer removeFromSuperlayer];
[self setNeedsDisplay];
}
- (void)setRotated:(BOOL)rotated
{
_rotated = rotated;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGRect bounds = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(bounds, 1.0f, 1.0f)];
path.lineWidth = 2.0f;
[self.tintColor setStroke];
[path stroke];
if (self.isSuccess) {
[self.layer addSublayer:self.checkLayer];
CAMediaTimingFunction *timing = [[CAMediaTimingFunction alloc] initWithControlPoints:0.180739998817444
:0
:0.577960014343262
:0.918200016021729];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[animation setTimingFunction:timing];
[animation setFillMode:kCAFillModeBoth];
animation.fromValue = @(0);
animation.toValue = @(1);
animation.duration = 0.3f;
animation.delegate = self;
[self.checkLayer addAnimation:animation forKey:@"strokeEnd"];
} else if (self.isRotated) {
UIBezierPath *crossPath = [[UIBezierPath alloc] init];
[crossPath moveToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 1/4)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 7/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 1/4, CGRectGetHeight(bounds) * 7/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 1/4, CGRectGetHeight(bounds) * 9/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 9/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 3/4)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 3/4)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 9/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 3/4, CGRectGetHeight(bounds) * 9/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 3/4, CGRectGetHeight(bounds) * 7/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 7/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 1/4)];
[crossPath closePath];
CAShapeLayer *crossLayer = [[CAShapeLayer alloc] init];
crossLayer.path = crossPath.CGPath;
crossLayer.bounds = CGPathGetBoundingBox(crossLayer.path);
crossLayer.anchorPoint = CGPointMake(0.5, 0.5);
crossLayer.fillColor = self.tintColor.CGColor;
CATransform3D transform = CATransform3DMakeTranslation(CGRectGetMidX(bounds), CGRectGetMidY(bounds), 1);
transform = CATransform3DRotate(transform, ORKPlaceHoleViewRotation * (M_PI / 180), 0, 0, 1);
crossLayer.transform = transform;
self.crossLayer = crossLayer;
[self.layer addSublayer:self.crossLayer];
}
CGContextRestoreGState(context);
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
ORKWeakTypeOf(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
ORKStrongTypeOf(self) strongSelf = weakSelf;
strongSelf.success = NO;
});
}
@end
@@ -1,45 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlacePegView : UIView
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@end
NS_ASSUME_NONNULL_END
@@ -1,93 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlacePegView.h"
@implementation ORKHolePegTestPlacePegView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.opaque = NO;
}
return self;
}
- (CGSize)intrinsicContentSize {
return CGSizeMake(self.frame.size.width, self.frame.size.height);
}
#pragma mark - drawing method
- (void)tintColorDidChange {
[super tintColorDidChange];
[self setNeedsDisplay];
}
- (void)setRotated:(BOOL)rotated
{
_rotated = rotated;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGRect bounds = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:bounds];
if (self.isRotated) {
[path moveToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 1/4)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 7/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 1/4, CGRectGetHeight(bounds) * 7/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 1/4, CGRectGetHeight(bounds) * 9/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 9/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 3/4)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 3/4)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 9/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 3/4, CGRectGetHeight(bounds) * 9/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 3/4, CGRectGetHeight(bounds) * 7/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 7/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 1/4)];
[path closePath];
}
[self.tintColor setFill];
[path fill];
CGContextRestoreGState(context);
}
@end
@@ -1,50 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceStep : ORKActiveStep
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign, getter = isDominantHandTested) BOOL dominantHandTested;
@property (nonatomic, assign) NSInteger numberOfPegs;
@property (nonatomic, assign) double threshold;
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@end
NS_ASSUME_NONNULL_END
@@ -1,136 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlaceStep.h"
#import "ORKHolePegTestPlaceStepViewController.h"
#import "ORKHelpers_Internal.h"
@implementation ORKHolePegTestPlaceStep
+ (Class)stepViewControllerClass {
return [ORKHolePegTestPlaceStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
self.shouldContinueOnFinish = YES;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
int const ORKHolePegTestMinimumNumberOfPegs = 1;
double const ORKHolePegTestMinimumThreshold = 0.0f;
double const ORKHolePegTestMaximumThreshold = 1.0f;
NSTimeInterval const ORKHolePegTestMinimumDuration = 1.0f;
if (self.movingDirection != ORKBodySagittalLeft &&
self.movingDirection != ORKBodySagittalRight) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"moving direction should be left or right."] userInfo:nil];
}
if (self.numberOfPegs < ORKHolePegTestMinimumNumberOfPegs) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"number of pegs must be greater than or equal to %@.", @(ORKHolePegTestMinimumNumberOfPegs)] userInfo:nil];
}
if (self.threshold < ORKHolePegTestMinimumThreshold ||
self.threshold > ORKHolePegTestMaximumThreshold) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"threshold must be greater than or equal to %@ and lower or equal to %@.", @(ORKHolePegTestMinimumThreshold), @(ORKHolePegTestMaximumThreshold)] userInfo:nil];
}
if (self.stepDuration < ORKHolePegTestMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
}
}
- (BOOL)allowsBackNavigation {
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
@@ -1,44 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -1,181 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlaceStepViewController.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>
@property (nonatomic, strong) NSMutableArray *samples;
@property (nonatomic, strong) ORKHolePegTestPlaceContentView *holePegTestPlaceContentView;
@property (nonatomic, assign) NSTimeInterval sampleStart;
@property (nonatomic, assign) NSUInteger successes;
@property (nonatomic, assign) NSUInteger failures;
@end
@implementation ORKHolePegTestPlaceStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = YES;
}
return self;
}
- (ORKHolePegTestPlaceStep *)holePegTestPlaceStep {
return (ORKHolePegTestPlaceStep *)self.step;
}
- (void)initializeInternalButtonItems {
[super initializeInternalButtonItems];
// Don't show next button
self.internalContinueButtonItem = nil;
self.internalDoneButtonItem = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.holePegTestPlaceContentView = [[ORKHolePegTestPlaceContentView alloc] initWithMovingDirection:[self holePegTestPlaceStep].movingDirection
rotated:[self holePegTestPlaceStep].rotated];
self.holePegTestPlaceContentView.threshold = [self holePegTestPlaceStep].threshold;
self.holePegTestPlaceContentView.delegate = self;
self.activeStepView.activeCustomView = self.holePegTestPlaceContentView;
self.activeStepView.stepViewFillsAvailableSpace = YES;
}
#pragma mark - step life cycle methods
- (void)start {
self.successes = 0;
self.failures = 0;
self.samples = [NSMutableArray array];
[self.holePegTestPlaceContentView setProgress:0.001f animated:NO];
[super start];
}
#pragma mark - result methods
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKHolePegTestResult *holePegTestResult = [[ORKHolePegTestResult alloc] initWithIdentifier:self.step.identifier];
holePegTestResult.movingDirection = [self holePegTestPlaceStep].movingDirection;
holePegTestResult.dominantHandTested = [self holePegTestPlaceStep].isDominantHandTested;
holePegTestResult.numberOfPegs = [self holePegTestPlaceStep].numberOfPegs;
holePegTestResult.threshold = [self holePegTestPlaceStep].threshold;
holePegTestResult.rotated = [self holePegTestPlaceStep].isRotated;
holePegTestResult.totalSuccesses = self.successes;
holePegTestResult.totalFailures = self.failures;
holePegTestResult.totalTime = [self holePegTestPlaceStep].stepDuration - self.timeRemaining;
double totalDistance = 0.0;
for (ORKHolePegTestSample *sample in self.samples) {
totalDistance += sample.distance;
}
holePegTestResult.totalDistance = totalDistance;
holePegTestResult.samples = self.samples;
[results addObject:holePegTestResult];
sResult.results = [results copy];
return sResult;
}
- (void)saveSampleWithDistance:(CGFloat)distance {
ORKHolePegTestSample *sample = [[ORKHolePegTestSample alloc] init];
sample.time = CACurrentMediaTime() - self.sampleStart;
sample.distance = distance;
self.sampleStart = CACurrentMediaTime();
[self.samples addObject:sample];
}
#pragma mark - hole peg test content view delegate
- (NSString *)stepTitle {
NSString *title = ([self holePegTestPlaceStep].movingDirection == ORKBodySagittalLeft) ? ORKLocalizedString(@"HOLE_PEG_TEST_PLACE_INSTRUCTION_LEFT_HAND", nil) : ORKLocalizedString(@"HOLE_PEG_TEST_PLACE_INSTRUCTION_RIGHT_HAND", nil);
return title;
}
- (void)holePegTestPlaceDidProgress:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView {
if (!self.isStarted) {
self.sampleStart = CACurrentMediaTime();
[self start];
}
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT_2", nil)];
}
- (void)holePegTestPlaceDidSucceed:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView withDistance:(CGFloat)distance {
self.successes++;
[self saveSampleWithDistance:distance];
[holePegTestPlaceContentView setProgress:((CGFloat)self.successes / [self holePegTestPlaceStep].numberOfPegs) animated:YES];
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)];
if (self.successes >= [self holePegTestPlaceStep].numberOfPegs) {
[((ORKNavigableOrderedTask *)self.taskViewController.task) removeNavigationRuleForTriggerStepIdentifier:[self holePegTestPlaceStep].identifier];
[self finish];
}
}
- (void)holePegTestPlaceDidFail:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView {
self.failures++;
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)];
}
@end
@@ -1,65 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import "ORKTypes.h"
NS_ASSUME_NONNULL_BEGIN
@protocol ORKHolePegTestRemoveContentViewDelegate;
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemoveContentView : ORKActiveStepCustomView
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE;
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
- (instancetype)initWithMovingDirection:(ORKBodySagittal)movingDirection NS_DESIGNATED_INITIALIZER;
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign) double threshold;
@property (nonatomic, weak) id<ORKHolePegTestRemoveContentViewDelegate> delegate;
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated;
@end
@protocol ORKHolePegTestRemoveContentViewDelegate <NSObject>
- (void)holePegTestRemoveDidProgress:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView;
- (void)holePegTestRemoveDidSucceed:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView withDistance:(CGFloat)distance;
- (void)holePegTestRemoveDidFail:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView;
@end
NS_ASSUME_NONNULL_END
@@ -1,358 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKDirectionView.h"
#import "ORKHolePegTestRemovePegView.h"
#import "ORKSeparatorView.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
static const CGFloat PegViewDiameter = 88.0f;
static const CGFloat PegViewSeparatorWidth = 2.0f;
@interface ORKHolePegTestRemoveContentView () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) ORKHolePegTestRemovePegView *pegView;
@property (nonatomic, strong) ORKSeparatorView *separatorView;
@property (nonatomic, strong) ORKDirectionView *directionView;
@property (nonatomic, strong) UIView *container;
@property (nonatomic, copy) NSArray *constraints;
@property (nonatomic, strong) UIPinchGestureRecognizer *pinchRecognizer;
@property (nonatomic, strong) UIPanGestureRecognizer *panRecognizer;
@property (nonatomic, assign, getter = isMovable) BOOL movable;
@property (nonatomic, assign, getter = hasMoveEnded) BOOL moveEnded;
@property (nonatomic, assign) CGPoint translation;
@property (nonatomic, assign) CGPoint translationOffset;
@property (nonatomic, assign) CGPoint startPoint;
@end
@implementation ORKHolePegTestRemoveContentView
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithFrame:(CGRect)frame {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithMovingDirection:(ORKBodySagittal)movingDirection {
self = [super initWithFrame:CGRectZero];
if (self) {
self.movingDirection = movingDirection;
self.opaque = NO;
self.container = [UIView new];
self.container.translatesAutoresizingMaskIntoConstraints = NO;
self.progressView = [UIProgressView new];
self.progressView.progressTintColor = self.tintColor;
[self.progressView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.progressView setAlpha:0];
[self addSubview:self.progressView];
self.pegView = [[ORKHolePegTestRemovePegView alloc] initWithFrame:CGRectMake(0, 0, PegViewDiameter, PegViewDiameter)];
[self.pegView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.container addSubview:self.pegView];
self.separatorView = [[ORKSeparatorView alloc] init];
[self.separatorView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.container addSubview:self.separatorView];
self.directionView = [[ORKDirectionView alloc] initWithOrientation:(self.movingDirection == ORKBodySagittalLeft) ? ORKBodySagittalRight : ORKBodySagittalLeft];
[self.directionView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.directionView];
[self addSubview:self.container];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
[self setNeedsUpdateConstraints];
self.movable = NO;
self.moveEnded = NO;
self.startPoint = CGPointZero;
self.pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePinch:)];
self.pinchRecognizer.delegate = self;
[self addGestureRecognizer:self.pinchRecognizer];
self.panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePan:)];
self.panRecognizer.delegate = self;
[self addGestureRecognizer:self.panRecognizer];
}
return self;
}
- (void)tintColorDidChange {
[super tintColorDidChange];
self.progressView.progressTintColor = self.tintColor;
}
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated {
[self.progressView setProgress:progress animated:animated];
[UIView animateWithDuration:animated ? 0.2 : 0 animations:^{
[self.progressView setAlpha:(progress == 0) ? 0 : 1];
}];
}
- (void)updateLayoutMargins {
CGFloat margin = ORKStandardHorizontalMarginForView(self);
self.layoutMargins = (UIEdgeInsets){.left = margin * 2, .right = margin * 2};
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self updateLayoutMargins];
}
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
[self updateLayoutMargins];
}
- (void)updateConstraints {
if ([self.constraints count]) {
[NSLayoutConstraint deactivateConstraints:self.constraints];
self.constraints = nil;
}
NSMutableArray *constraintsArray = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _container, _pegView, _separatorView, _directionView);
NSDictionary *metrics = @{@"diameter": @(PegViewDiameter), @"separator": @(PegViewSeparatorWidth), @"margin": @((1 + self.threshold) * PegViewDiameter)};
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:(self.movingDirection == ORKBodySagittalLeft) ? @"H:|-[_pegView(diameter)]->=0-[_separatorView(separator)]-(margin)-|" : @"H:|-(margin)-[_separatorView(separator)]->=0-[_pegView(diameter)]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:metrics views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_container]|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=0)-[_pegView(diameter)]-(>=0)-|"
options:(NSLayoutFormatOptions)0
metrics:metrics views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_separatorView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_progressView][_container]|"
options:(NSLayoutFormatOptions)0
metrics:metrics views:views]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.directionView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.directionView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0]];
self.constraints = constraintsArray;
[self addConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:self.constraints];
[super updateConstraints];
}
#pragma mark - gesture recognizer methods
- (void)pickupPegWithGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
CGPoint touch = [gestureRecognizer locationInView:self];
CGPoint touch1 = [gestureRecognizer locationOfTouch:0 inView:self];
CGPoint touch2 = [gestureRecognizer locationOfTouch:1 inView:self];
double distance = hypot(touch1.x - touch2.x, touch1.y - touch2.y);
if (distance < 3 * CGRectGetWidth(self.pegView.frame) &&
CGRectContainsPoint(self.pegView.frame, touch)) {
self.movable = YES;
} else {
self.movable = NO;
}
}
- (void)handlePinch:(UIPinchGestureRecognizer *)pinchGestureRecognizer {
if ([pinchGestureRecognizer numberOfTouches] == 2) {
[self pickupPegWithGestureRecognizer:pinchGestureRecognizer];
}
}
- (void)handlePan:(UIPanGestureRecognizer *)panGestureRecognizer {
if ([panGestureRecognizer numberOfTouches] != 2 ||
panGestureRecognizer.state == UIGestureRecognizerStateEnded ||
panGestureRecognizer.state == UIGestureRecognizerStateCancelled ||
panGestureRecognizer.state == UIGestureRecognizerStateFailed) {
[self resetTransformAtPoint:[panGestureRecognizer locationInView:self]];
} else {
if (self.isMovable) {
self.translation = CGPointMake([panGestureRecognizer translationInView:self].x - self.translationOffset.x,
[panGestureRecognizer translationInView:self].y - self.translationOffset.y);
[self updateTransformAtPoint:[panGestureRecognizer locationInView:self]];
} else {
self.translationOffset = CGPointMake([panGestureRecognizer translationInView:self].x - self.translation.x,
[panGestureRecognizer translationInView:self].y - self.translation.y);
if (CGPointEqualToPoint(self.startPoint, CGPointZero)) {
[self pickupPegWithGestureRecognizer:panGestureRecognizer];
}
}
}
}
- (void)updateTransformAtPoint:(CGPoint)point {
self.pegView.transform = CGAffineTransformMakeTranslation(self.translation.x, self.translation.y);
[self pegViewDidMoveAtPoint:point];
}
- (void)resetTransformAtPoint:(CGPoint)point {
if (!self.hasMoveEnded) {
self.movable = NO;
self.moveEnded = YES;
self.pinchRecognizer.enabled = NO;
self.panRecognizer.enabled = NO;
BOOL animated = ![self pegViewMoveDidEndAtPoint:point];
[UIView animateWithDuration:animated ? 0.15f : 0.0f
delay:animated ? 0.0f : 0.30f
options:UIViewAnimationOptionCurveEaseOut
animations:^(){
self.pegView.transform = CGAffineTransformIdentity;
self.pegView.alpha = 1.0f;
}
completion:^(BOOL finished){
self.translation = CGPointZero;
self.translationOffset = CGPointZero;
self.pinchRecognizer.enabled = YES;
self.panRecognizer.enabled = YES;
self.moveEnded = NO;
self.pegView.hidden = NO;
}];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
#pragma mark - peg view delegate
- (void)pegViewDidMoveAtPoint:(CGPoint)point {
self.directionView.hidden = YES;
if (CGPointEqualToPoint(self.startPoint, CGPointZero)) {
self.startPoint = point;
}
if ([self.delegate respondsToSelector:@selector(holePegTestRemoveDidProgress:)]) {
[self.delegate holePegTestRemoveDidProgress:self];
}
if (self.pegView.isSuccess) {
self.pegView.success = NO;
}
if ([self pegViewBehindLine]) {
self.pegView.alpha = 1.0f;
} else {
self.pegView.alpha = 0.2f;
}
}
- (BOOL)pegViewMoveDidEndAtPoint:(CGPoint)point {
self.directionView.hidden = NO;
BOOL succeeded = NO;
if ([self pegViewBehindLine]) {
if ([self.delegate respondsToSelector:@selector(holePegTestRemoveDidSucceed:withDistance:)]) {
CGFloat distance = hypotf(point.x - self.startPoint.x, point.y - self.startPoint.y);
[self.delegate holePegTestRemoveDidSucceed:self withDistance:distance];
}
self.pegView.success = YES;
succeeded = YES;
} else {
if ([self.delegate respondsToSelector:@selector(holePegTestRemoveDidFail:)]) {
[self.delegate holePegTestRemoveDidFail:self];
}
self.pegView.success = NO;
}
self.startPoint = CGPointZero;
return succeeded;
}
- (BOOL)pegViewBehindLine {
if (self.movingDirection == ORKBodySagittalLeft) {
if (CGRectGetMinX(self.pegView.frame) > CGRectGetMaxX(self.separatorView.frame)) {
return YES;
} else {
return NO;
}
} else {
if (CGRectGetMaxX(self.pegView.frame) < CGRectGetMinX(self.separatorView.frame)) {
return YES;
} else {
return NO;
}
}
}
@end
@@ -1,45 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemovePegView : UIView <CAAnimationDelegate>
@property (nonatomic, assign, getter = isSuccess) BOOL success;
@end
NS_ASSUME_NONNULL_END
@@ -1,122 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestRemovePegView.h"
@interface ORKHolePegTestRemovePegView ()
@property (nonatomic, strong) CAShapeLayer *checkLayer;
@end
@implementation ORKHolePegTestRemovePegView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(27.7f, 46.9f)];
[path addLineToPoint:CGPointMake(36.1f, 56.3f)];
[path addLineToPoint:CGPointMake(62.8f, 30.3f)];
path.lineCapStyle = kCGLineCapRound;
path.lineWidth = 3.6f;
CAShapeLayer *checkLayer = [CAShapeLayer new];
checkLayer.path = path.CGPath;
checkLayer.lineWidth = 3.6f;
checkLayer.lineCap = kCALineCapRound;
checkLayer.lineJoin = kCALineJoinRound;
checkLayer.frame = self.layer.bounds;
checkLayer.strokeColor = [UIColor whiteColor].CGColor;
checkLayer.backgroundColor = [UIColor clearColor].CGColor;
checkLayer.fillColor = nil;
self.checkLayer = checkLayer;
self.opaque = NO;
self.success = NO;
}
return self;
}
- (void)tintColorDidChange {
[super tintColorDidChange];
[self setNeedsDisplay];
}
#pragma mark - drawing method
- (void)setSuccess:(BOOL)success
{
_success = success;
[self.checkLayer removeFromSuperlayer];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGRect bounds = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:bounds];
path.lineWidth = 2.0f;
[self.tintColor setFill];
[path fill];
if (self.isSuccess) {
[self.layer addSublayer:self.checkLayer];
CAMediaTimingFunction *timing = [[CAMediaTimingFunction alloc] initWithControlPoints:0.180739998817444
:0
:0.577960014343262
:0.918200016021729];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[animation setTimingFunction:timing];
[animation setFillMode:kCAFillModeBoth];
animation.fromValue = @(0);
animation.toValue = @(1);
animation.duration = 0.25f;
animation.delegate = self;
[self.checkLayer addAnimation:animation forKey:@"strokeEnd"];
}
CGContextRestoreGState(context);
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
self.success = NO;
}
@end
@@ -1,49 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemoveStep : ORKActiveStep
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign, getter = isDominantHandTested) BOOL dominantHandTested;
@property (nonatomic, assign) NSInteger numberOfPegs;
@property (nonatomic, assign) double threshold;
@end
NS_ASSUME_NONNULL_END
@@ -1,134 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestRemoveStep.h"
#import "ORKHolePegTestRemoveStepViewController.h"
#import "ORKHelpers_Internal.h"
@implementation ORKHolePegTestRemoveStep
+ (Class)stepViewControllerClass {
return [ORKHolePegTestRemoveStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
self.shouldContinueOnFinish = YES;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
int const ORKHolePegTestMinimumNumberOfPegs = 1;
double const ORKHolePegTestMinimumThreshold = 0.0f;
double const ORKHolePegTestMaximumThreshold = 1.0f;
NSTimeInterval const ORKHolePegTestMinimumDuration = 1.0f;
if (self.movingDirection != ORKBodySagittalLeft &&
self.movingDirection != ORKBodySagittalRight) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"moving direction should be left or right."] userInfo:nil];
}
if (self.numberOfPegs < ORKHolePegTestMinimumNumberOfPegs) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"number of pegs must be greater than or equal to %@.", @(ORKHolePegTestMinimumNumberOfPegs)] userInfo:nil];
}
if (self.threshold < ORKHolePegTestMinimumThreshold ||
self.threshold > ORKHolePegTestMaximumThreshold) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"threshold must be greater than or equal to %@ and lower or equal to %@.", @(ORKHolePegTestMinimumThreshold), @(ORKHolePegTestMaximumThreshold)] userInfo:nil];
}
if (self.stepDuration < ORKHolePegTestMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
}
}
- (BOOL)allowsBackNavigation {
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
@@ -1,44 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemoveStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -1,180 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestRemoveStepViewController.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>
@property (nonatomic, strong) NSMutableArray *samples;
@property (nonatomic, strong) ORKHolePegTestRemoveContentView *holePegTestRemoveContentView;
@property (nonatomic, assign) NSTimeInterval sampleStart;
@property (nonatomic, assign) NSUInteger successes;
@property (nonatomic, assign) NSUInteger failures;
@end
@implementation ORKHolePegTestRemoveStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = YES;
}
return self;
}
- (ORKHolePegTestRemoveStep *)holePegTestRemoveStep {
return (ORKHolePegTestRemoveStep *)self.step;
}
- (void)initializeInternalButtonItems {
[super initializeInternalButtonItems];
// Don't show next button
self.internalContinueButtonItem = nil;
self.internalDoneButtonItem = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.holePegTestRemoveContentView = [[ORKHolePegTestRemoveContentView alloc] initWithMovingDirection:[self holePegTestRemoveStep].movingDirection];
self.holePegTestRemoveContentView.threshold = [self holePegTestRemoveStep].threshold;
self.holePegTestRemoveContentView.delegate = self;
self.activeStepView.activeCustomView = self.holePegTestRemoveContentView;
self.activeStepView.stepViewFillsAvailableSpace = YES;
NSString *identifier = [[self holePegTestRemoveStep].identifier stringByReplacingOccurrencesOfString:@"remove" withString:@"place"];
NSTimeInterval placeStepDuration = ((ORKHolePegTestResult *)[[self.taskViewController.result stepResultForStepIdentifier:identifier].results firstObject]).totalTime;
[self holePegTestRemoveStep].stepDuration -= placeStepDuration;
[self start];
}
#pragma mark - step life cycle methods
- (void)start {
self.sampleStart = CACurrentMediaTime();
self.successes = 0;
self.failures = 0;
self.samples = [NSMutableArray array];
[self.holePegTestRemoveContentView setProgress:0.001f animated:NO];
[super start];
}
#pragma mark - result methods
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKHolePegTestResult *holePegTestResult = [[ORKHolePegTestResult alloc] initWithIdentifier:self.step.identifier];
holePegTestResult.movingDirection = [self holePegTestRemoveStep].movingDirection;
holePegTestResult.dominantHandTested = [self holePegTestRemoveStep].isDominantHandTested;
holePegTestResult.numberOfPegs = [self holePegTestRemoveStep].numberOfPegs;
holePegTestResult.threshold = [self holePegTestRemoveStep].threshold;
holePegTestResult.rotated = NO;
holePegTestResult.totalSuccesses = self.successes;
holePegTestResult.totalFailures = self.failures;
holePegTestResult.totalTime = [self holePegTestRemoveStep].stepDuration - self.timeRemaining;
double totalDistance = 0.0;
for (ORKHolePegTestSample *sample in self.samples) {
totalDistance += sample.distance;
}
holePegTestResult.totalDistance = totalDistance;
holePegTestResult.samples = self.samples;
[results addObject:holePegTestResult];
sResult.results = [results copy];
return sResult;
}
- (void)saveSampleWithDistance:(CGFloat)distance {
ORKHolePegTestSample *sample = [[ORKHolePegTestSample alloc] init];
sample.time = CACurrentMediaTime() - self.sampleStart;
sample.distance = distance;
self.sampleStart = CACurrentMediaTime();
[self.samples addObject:sample];
}
#pragma mark - hole peg test content view delegate
- (NSString *)stepTitle {
NSString *title = ([self holePegTestRemoveStep].movingDirection == ORKBodySagittalLeft) ? ORKLocalizedString(@"HOLE_PEG_TEST_REMOVE_INSTRUCTION_RIGHT_HAND", nil) : ORKLocalizedString(@"HOLE_PEG_TEST_REMOVE_INSTRUCTION_LEFT_HAND", nil);
return title;
}
- (void)holePegTestRemoveDidProgress:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView {
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT_2", nil)];
}
- (void)holePegTestRemoveDidSucceed:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView withDistance:(CGFloat)distance {
self.successes++;
[self saveSampleWithDistance:distance];
[holePegTestRemoveContentView setProgress:((CGFloat)self.successes / [self holePegTestRemoveStep].numberOfPegs) animated:YES];
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)];
if (self.successes >= [self holePegTestRemoveStep].numberOfPegs) {
[self finish];
}
}
- (void)holePegTestRemoveDidFail:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView {
self.failures++;
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)];
}
@end
@@ -1,71 +0,0 @@
/*
Copyright (c) 2015, 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:
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 UIKit;
@import CoreLocation;
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKLocationRecorder` class represents a recorder for collecting location data from CoreLocation.
Because location data is sensitive information, you need to take special care in handling it, including removoing or otherwise preparing it for a
anonymous data set.
The accuracy of location data may be limited indoors.
*/
ORK_CLASS_AVAILABLE
@interface ORKLocationRecorder : ORKRecorder
/**
Returns an initialized location recorder.
@param identifier The unique identifier of the recorder (assigned by the recorder configuration).
@param step The step that requested this recorder.
@param outputDirectory The directory in which the location data should be stored.
@return An initialized location recorder.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier
step:(nullable ORKStep *)step
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
/**
The location manager, if any, being used by this recorder.
*/
@property (nonatomic, strong, nullable, readonly) CLLocationManager *locationManager;
@end
NS_ASSUME_NONNULL_END
@@ -1,204 +0,0 @@
/*
Copyright (c) 2015, 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:
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 "ORKLocationRecorder.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Internal.h"
#import "CLLocation+ORKJSONDictionary.h"
#import <CoreLocation/CoreLocation.h>
@interface ORKLocationRecorder () <CLLocationManagerDelegate> {
ORKDataLogger *_logger;
NSError *_recordingError;
BOOL _started;
}
@property (nonatomic, strong, nullable) CLLocationManager *locationManager;
@property (nonatomic) NSTimeInterval uptime;
@end
@implementation ORKLocationRecorder
- (instancetype)initWithIdentifier:(NSString *)identifier step:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
self = [super initWithIdentifier:identifier step:step outputDirectory:outputDirectory];
if (self) {
self.continuesInBackground = YES;
}
return self;
}
- (void)dealloc {
[_logger finishCurrentLog];
}
- (NSString *)recorderType {
return @"location";
}
- (CLLocationManager *)createLocationManager {
return [[CLLocationManager alloc] init];
}
- (void)start {
[super start];
if (!_logger) {
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
if (!_logger) {
[self finishRecordingWithError:error];
return;
}
}
self.locationManager = [self createLocationManager];
if ([CLLocationManager authorizationStatus] <= kCLAuthorizationStatusDenied) {
[self.locationManager requestWhenInUseAuthorization];
}
self.locationManager.pausesLocationUpdatesAutomatically = NO;
self.locationManager.delegate = self;
if (!self.locationManager) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder": self}];
[self finishRecordingWithError:error];
return;
}
self.uptime = [NSProcessInfo processInfo].systemUptime;
[self.locationManager startUpdatingLocation];
}
- (void)doStopRecording {
[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
self.locationManager = nil;
}
- (void)stop {
[self doStopRecording];
[_logger finishCurrentLog];
NSError *error = _recordingError;
_recordingError = nil;
__block NSURL *fileUrl = nil;
[_logger enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
fileUrl = logFileUrl;
} error:&error];
[self reportFileResultWithFile:fileUrl error:error];
[super stop];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
BOOL success = YES;
NSParameterAssert(locations.count >= 0);
NSError *error = nil;
if (locations) {
NSMutableArray *dictionaries = [NSMutableArray arrayWithCapacity:locations.count];
[locations enumerateObjectsUsingBlock:^(CLLocation *obj, NSUInteger idx, BOOL *stop) {
NSDictionary *d = [obj ork_JSONDictionary];
[dictionaries addObject:d];
}];
success = [_logger appendObjects:dictionaries error:&error];
}
if (!success) {
dispatch_async(dispatch_get_main_queue(), ^{
_recordingError = error;
[self stop];
});
}
}
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:nil];
}
- (BOOL)isRecording {
return [CLLocationManager locationServicesEnabled] && (self.locationManager != nil) && ([CLLocationManager authorizationStatus] > kCLAuthorizationStatusDenied);
}
- (void)reset {
[super reset];
_logger = nil;
}
- (NSString *)mimeType {
return @"application/json";
}
@end
@implementation ORKLocationRecorderConfiguration
- (instancetype)initWithIdentifier:(NSString *)identifier {
return [super initWithIdentifier:identifier];
}
- (ORKRecorder *)recorderForStep:(ORKStep *)step outputDirectory:(NSURL *)outputDirectory {
return [[ORKLocationRecorder alloc] initWithIdentifier:self.identifier step:step outputDirectory:outputDirectory];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
return self;
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
return isParentSame;
}
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionCoreLocation;
}
@end
@@ -1,53 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import "ORKTypes.h"
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKPSATKeyboardView;
@interface ORKPSATContentView : ORKActiveStepCustomView
@property (nonatomic, strong) ORKPSATKeyboardView *keyboardView;
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
- (instancetype)initWithPresentationMode:(ORKPSATPresentationMode)presentationMode NS_DESIGNATED_INITIALIZER;
- (void)setEnabled:(BOOL)enabled;
- (void)setAddition:(NSUInteger)additionIndex forTotal:(NSUInteger)totalAddition withDigit:(NSNumber *)digit;
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated;
@end
NS_ASSUME_NONNULL_END
@@ -1,164 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKPSATContentView.h"
#import "ORKBorderedButton.h"
#import "ORKPSATKeyboardView.h"
#import "ORKTapCountLabel.h"
#import "ORKVoiceEngine.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@interface ORKPSATContentView ()
@property (nonatomic, assign, getter = isAuditory) BOOL auditory;
@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) ORKTapCountLabel *digitLabel;
@end
@implementation ORKPSATContentView
- (instancetype)initWithFrame:(CGRect)frame {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [self initWithPresentationMode:ORKPSATPresentationModeAuditory];
return self;
}
- (instancetype)initWithPresentationMode:(ORKPSATPresentationMode)presentationMode {
self = [super initWithFrame:CGRectZero];
if (self) {
_digitLabel = [ORKTapCountLabel new];
_digitLabel.textAlignment = NSTextAlignmentCenter;
_digitLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_digitLabel];
_auditory = (presentationMode & ORKPSATPresentationModeAuditory) ? YES : NO;
if (!(presentationMode & ORKPSATPresentationModeVisual)) {
_digitLabel.hidden = YES;
}
_progressView = [UIProgressView new];
_progressView.translatesAutoresizingMaskIntoConstraints = NO;
_progressView.progressTintColor = [self tintColor];
[_progressView setAlpha:0];
[self addSubview:_progressView];
_keyboardView = [ORKPSATKeyboardView new];
_keyboardView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_keyboardView];
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setNeedsUpdateConstraints];
}
return self;
}
- (void)setEnabled:(BOOL)enabled {
self.keyboardView.enabled = enabled;
}
- (void)setAddition:(NSUInteger)additionIndex forTotal:(NSUInteger)totalAddition withDigit:(NSNumber *)digit {
if (digit.integerValue == -1) {
self.digitLabel.textColor = [[UIColor blackColor] colorWithAlphaComponent:0.3f];
self.digitLabel.text = ORKLocalizedString(@"PSAT_NO_DIGIT", nil);
} else {
[self.keyboardView.selectedAnswerButton setSelected:NO];
self.digitLabel.textColor = nil;
self.digitLabel.text = [NSNumberFormatter localizedStringFromNumber:digit
numberStyle:NSNumberFormatterNoStyle];
if (self.isAuditory) {
[[ORKVoiceEngine sharedVoiceEngine] speakInt:digit.integerValue];
}
}
}
- (void)tintColorDidChange {
[super tintColorDidChange];
self.progressView.progressTintColor = self.tintColor;
}
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated {
[self.progressView setProgress:progress animated:animated];
[UIView animateWithDuration:animated ? 0.2 : 0 animations:^{
[self.progressView setAlpha:(progress == 0) ? 0 : 1];
}];
}
- (void)updateConstraints {
[NSLayoutConstraint deactivateConstraints:self.constraints];
const CGFloat ORKPSATKeyboardWidth = ORKGetMetricForWindow(ORKScreenMetricPSATKeyboardViewWidth, self.window);
const CGFloat ORKPSATKeyboardHeight = ORKGetMetricForWindow(ORKScreenMetricPSATKeyboardViewHeight, self.window);
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _digitLabel, _keyboardView);
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_keyboardView(==keyboardWidth)]-|"
options:(NSLayoutFormatOptions)0
metrics:@{ @"keyboardWidth": @(ORKPSATKeyboardWidth) }
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_keyboardView(==keyboardHeight)]"
options:(NSLayoutFormatOptions)0
metrics:@{ @"keyboardHeight": @(ORKPSATKeyboardHeight) }
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_progressView]-[_digitLabel]-(>=10)-[_keyboardView]-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
[NSLayoutConstraint activateConstraints:constraints];
[super updateConstraints];
}
@end
@@ -1,56 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKBorderedButton;
@protocol ORKPSATKeyboardViewDelegate;
@interface ORKPSATKeyboardView : UIView
@property (nonatomic, weak) id<ORKPSATKeyboardViewDelegate> delegate;
@property (nonatomic, weak) ORKBorderedButton *selectedAnswerButton;
- (void)setEnabled:(BOOL)enabled;
@end
@protocol ORKPSATKeyboardViewDelegate <NSObject>
- (void)keyboardView:(ORKPSATKeyboardView *)keyboardView didSelectAnswer:(NSInteger)answer;
@end
NS_ASSUME_NONNULL_END
@@ -1,153 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKPSATKeyboardView.h"
#import "ORKBorderedButton.h"
NSUInteger const ORKPSATMinimumAnswer = 3;
NSUInteger const ORKPSATMaximumAnswer = 17;
@interface ORKPSATKeyboardView ()
@property (nonatomic, strong, readonly) NSArray *answerButtons;
@property (nonatomic, strong) NSArray *constraints;
@end
@implementation ORKPSATKeyboardView
- (instancetype)init {
self = [super init];
if (self) {
NSMutableArray *buttonsArray = [[NSMutableArray alloc] initWithCapacity:(ORKPSATMaximumAnswer - ORKPSATMinimumAnswer) + 1];
ORKBorderedButton *answerButton = nil;
for (int i = ORKPSATMinimumAnswer; i <= ORKPSATMaximumAnswer; i++) {
answerButton = [self answerButtonWithTitle:[NSNumberFormatter localizedStringFromNumber:@(i)
numberStyle:NSNumberFormatterNoStyle]];
[buttonsArray addObject:answerButton];
[self addSubview:answerButton];
}
_answerButtons = [NSArray arrayWithArray:buttonsArray];
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setNeedsUpdateConstraints];
}
return self;
}
- (ORKBorderedButton *)answerButtonWithTitle:(NSString *)title {
ORKBorderedButton *answerButton = [ORKBorderedButton new];
answerButton.translatesAutoresizingMaskIntoConstraints = NO;
[answerButton setTitle:title forState:UIControlStateNormal];
[answerButton addTarget:self action:@selector(buttonPressed:forEvent:) forControlEvents:UIControlEventTouchUpInside];
answerButton.accessibilityTraits |= UIAccessibilityTraitKeyboardKey;
return answerButton;
}
- (void)setEnabled:(BOOL)enabled {
for (ORKBorderedButton *answerButton in self.answerButtons) {
[answerButton setEnabled:enabled];
}
}
- (void)updateConstraints {
[NSLayoutConstraint deactivateConstraints:self.constraints];
NSMutableArray *constraints = [NSMutableArray array];
ORKBorderedButton *answer3Button = self.answerButtons[0];
ORKBorderedButton *answer4Button = self.answerButtons[1];
ORKBorderedButton *answer5Button = self.answerButtons[2];
ORKBorderedButton *answer6Button = self.answerButtons[3];
ORKBorderedButton *answer7Button = self.answerButtons[4];
ORKBorderedButton *answer8Button = self.answerButtons[5];
ORKBorderedButton *answer9Button = self.answerButtons[6];
ORKBorderedButton *answer10Button = self.answerButtons[7];
ORKBorderedButton *answer11Button = self.answerButtons[8];
ORKBorderedButton *answer12Button = self.answerButtons[9];
ORKBorderedButton *answer13Button = self.answerButtons[10];
ORKBorderedButton *answer14Button = self.answerButtons[11];
ORKBorderedButton *answer15Button = self.answerButtons[12];
ORKBorderedButton *answer16Button = self.answerButtons[13];
ORKBorderedButton *answer17Button = self.answerButtons[14];
NSDictionary *views = NSDictionaryOfVariableBindings(answer3Button, answer4Button, answer5Button, answer6Button, answer7Button, answer8Button, answer9Button, answer10Button, answer11Button, answer12Button, answer13Button, answer14Button, answer15Button, answer16Button, answer17Button);
// First line of answer buttons
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[answer3Button]-[answer4Button(==answer3Button)]-[answer5Button(==answer3Button)]-[answer6Button(==answer3Button)]-[answer7Button(==answer3Button)]-|"
options:NSLayoutFormatAlignAllCenterY|NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom
metrics:nil views:views]];
// Second line of answer buttons
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[answer8Button]-[answer9Button(==answer8Button)]-[answer10Button(==answer8Button)]-[answer11Button(==answer8Button)]-[answer12Button(==answer8Button)]-|"
options:NSLayoutFormatAlignAllCenterY|NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom
metrics:nil views:views]];
// Third line of answer buttons
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[answer13Button]-[answer14Button(==answer13Button)]-[answer15Button(==answer13Button)]-[answer16Button(==answer13Button)]-[answer17Button(==answer13Button)]-|"
options:NSLayoutFormatAlignAllCenterY|NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom
metrics:nil views:views]];
// Align vertically
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[answer3Button]-[answer8Button(==answer3Button)]-[answer13Button(==answer3Button)]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[NSLayoutConstraint activateConstraints:constraints];
[super updateConstraints];
}
#pragma mark buttonAction
- (IBAction)buttonPressed:(id)button forEvent:(UIEvent *)event {
ORKBorderedButton *tappedAnswerButton = (ORKBorderedButton *)button;
[self.selectedAnswerButton setSelected:NO];
self.selectedAnswerButton = tappedAnswerButton;
[self.selectedAnswerButton setSelected:YES];
if ([self.delegate respondsToSelector:@selector(keyboardView:didSelectAnswer:)]) {
NSInteger answerValue = [self.answerButtons indexOfObject:tappedAnswerButton] + ORKPSATMinimumAnswer;
[self.delegate keyboardView:self didSelectAnswer:answerValue];
}
}
@end
-49
View File
@@ -1,49 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKPSATStep : ORKActiveStep
@property (nonatomic, assign) ORKPSATPresentationMode presentationMode;
@property (nonatomic, assign) NSTimeInterval interStimulusInterval;
@property (nonatomic, assign) NSTimeInterval stimulusDuration;
@property (nonatomic, assign) NSInteger seriesLength;
@end
NS_ASSUME_NONNULL_END
-143
View File
@@ -1,143 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKPSATStep.h"
#import "ORKPSATStepViewController.h"
#import "ORKHelpers_Internal.h"
@implementation ORKPSATStep
+ (Class)stepViewControllerClass {
return [ORKPSATStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldStartTimerAutomatically = YES;
self.shouldShowDefaultTimer = NO;
self.shouldContinueOnFinish = YES;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
NSTimeInterval const ORKPSATInterStimulusMinimumInterval = 1.0;
NSTimeInterval const ORKPSATInterStimulusMaximumInterval = 5.0;
NSTimeInterval const ORKPSATStimulusMinimumDuration = 0.2;
NSInteger const ORKPSATSerieMinimumLength = 10;
NSInteger const ORKPSATSerieMaximumLength = 120;
NSTimeInterval totalDuration = (self.seriesLength + 1) * self.interStimulusInterval;
if (self.stepDuration != totalDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"step duration must be equal to %@ seconds.", @(totalDuration)] userInfo:nil];
}
if (!(self.presentationMode & ORKPSATPresentationModeAuditory) &&
!(self.presentationMode & ORKPSATPresentationModeVisual)) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"step presentation mode must be auditory and/or visual." userInfo:nil];
}
if (self.interStimulusInterval < ORKPSATInterStimulusMinimumInterval ||
self.interStimulusInterval > ORKPSATInterStimulusMaximumInterval) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"inter stimulus interval must be greater than or equal to %@ seconds and less than or equal to %@ seconds.", @(ORKPSATInterStimulusMinimumInterval), @(ORKPSATInterStimulusMaximumInterval)] userInfo:nil];
}
if ((self.presentationMode & ORKPSATPresentationModeVisual) &&
(self.stimulusDuration < ORKPSATStimulusMinimumDuration || self.stimulusDuration > self.interStimulusInterval)) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"stimulus duration must be greater than or equal to %@ seconds and less than or equal to %@ seconds.", @(ORKPSATStimulusMinimumDuration), @(self.interStimulusInterval)] userInfo:nil];
}
if (self.seriesLength < ORKPSATSerieMinimumLength ||
self.seriesLength > ORKPSATSerieMaximumLength) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"serie length must be greater than or equal to %@ additions and less than or equal to %@ additions.", @(ORKPSATSerieMinimumLength), @(ORKPSATSerieMaximumLength)] userInfo:nil];
}
}
- (BOOL)allowsBackNavigation {
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
@@ -1,44 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKPSATStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END

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