Compare commits

...

420 Commits

Author SHA1 Message Date
Pariece McKinney c71d1a56dd Public release 3.0.1 2024-05-08 14:56:11 -04:00
Corey 6c24a7e922 ci: Add code integration testing to repo (#1569) 2024-04-10 14:33:32 -04:00
Pariece McKinney b14e5cfcb0 Public Release 3.0 2024-03-28 19:39:04 -04:00
Louie fee76c2d93 Merge branch 'stable' into main 2023-12-05 14:00:17 -08:00
Louie a07041901b Public Release 2.2.15
Various ORKTextChoiceOther and ORKChoiceOtherViewCell improvements
Bumped version to 2.2.15
Bumped Cocoapod version to 2.2.15
2023-12-05 11:19:31 -08:00
Louie Chatta c370011616 Public Release 2.2.15
- Various ORKTextChoiceOther and ORKChoiceOtherViewCell improvements 
- Bumped version to 2.2.15
- Bumped Cocoapod version to 2.2.15
2023-12-05 11:02:55 -08:00
Pariece McKinney b8f155974c Public release/2.2.12 (#1555)
- Fixed `ORKHealthKitQuantityTypeAnswerFormat`issues
- Improved `ORKReviewStep` initialization
- Introduced a new property called `shouldAutomaticallyAdjustImageTintColor` on `ORKStep` to automatically adopt dark mode version of an image
- Added `ORKSESQuestionResult` to Table View Providers
- ORKCatalog Improvements
- ORKImageSelectionView improvements
- Bumped version to 2.2.12
2023-11-01 18:18:20 -04:00
Pariece McKinney 2fb22a6256 Public release/2.2.10 (#1548)
Fix ORKNavigationContainerView so that it does not call didMoveToWindow from tintColorDidChange
Bumped version to 2.2.10
2023-05-10 17:40:25 -04:00
ronzilla-apple bd60d945bb Public release/2.2.9 (#1541)
* Address issue where there was no option to "Save Results" if task is cancelled (Issue #1536/1540)
* Address an issue where ORKTaskViewController setting tintColor on stepViewController views broke ORKStepViewController's addResult:

* Fixed order issue of tone audiometry steps
* Include missing ORKSpeechRecognition header export (Issue #1534)
* Switch to contentEdgeInsets API in ORKContinueButton to fix an issue where button title wouldn't always fit onscreen (on iOS 16 during long press) (Issue #1533)
* Remove min/max values for ORKCatalog "Numeric with Display Unit"

* xcconfig file updates for version and driving ORKCatalog bundleID
* Addressing compiler warnings
* Added unit tests for init'ing taskViewController with restoration data
* Adding task restoration feature to ORKCatalog's taskViewController presentation
2023-02-13 11:03:48 -08:00
Pariece McKinney 8f58410af9 Release 2.2.8
-Bug fixes and enhancements
-New helper method (ORKViewTintColor) for setting tintColor
-New “displayUnit” property added to ORKAnswerFormat
-Updates in ORKNormalizedReactionTimeResult’s secure coding (breaks compatibility with previous archives).
2022-12-20 11:14:59 -08:00
Louie fc67cc944c Merge pull request #1519 from cbaker6/fixTintColor
Propagate tintColor if window not available
2022-11-29 20:22:37 -08:00
Louie c8473017ec Merge pull request #1531 from ResearchKit/cocoapod_fix
remove deprecated ORKConsent files
2022-11-29 13:21:51 -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 2bc0033aa8 remove deprecated ORKConsent files 2022-11-29 11:51:42 -08:00
Louis Chatta e71d71cf9c Point ResearchKit.podspec to 2.1.0 2022-11-29 11:48:27 -08:00
Corey Baker 64a068596b make suggested changes 2022-11-28 15:25:59 -05:00
Corey Baker c10693930d Fix tintColor for ORKWebViewStepViewController buttons 2022-11-15 20:48:25 -05:00
Corey Baker c0f309edf3 only check for tintColor once in viewControllerForStep 2022-11-15 09:16:44 -05:00
Corey Baker b1cc631748 propagate tintColor if window not available 2022-11-14 14:46:02 -05:00
Pariece McKinney a89059f5dc 2.1.1 Release
-Bug fixes
-New ORKAccuracyStroopStep
-AudioStep now allows for audio recording 
-New Styles for ORKDontKnowButton
-General layout and UI improvements
2022-10-26 16:07:45 -07:00
Will 2cc8f9e7d5 Prevent isPasscodeStoredInKeychain crash, correct warnings (#1505)
* fix: prevent isPasscodeStoredInKeychain from causing a crash

* fix: prevent nskeyedunarchiver warnings, add missing classes
2022-06-16 10:55:09 -07: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
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
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
David Evans c424ada8fd Adjusted 'finish' angle calculation in line with ORKRangeOfMotionStepViewController 2018-08-01 11:55:09 +01: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
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
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
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 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
Ricardo Sanchez-Saez 5592966027 [ORKPieChartView] Allow skipping segment legend labels 2018-04-04 03:20:43 -07: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
2360 changed files with 80167 additions and 183720 deletions
+26
View File
@@ -0,0 +1,26 @@
name: Build
on:
push:
branches: [ 'main', 'stable' ]
pull_request:
branches: [ 'main', 'stable' ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: macos-14
strategy:
matrix:
destination: ['platform=iOS\ Simulator,OS=17.4,name=iPhone\ 15\ Pro']
scheme: ['ResearchKit']
name: ${{ matrix.scheme }} Unit Tests
steps:
- uses: actions/checkout@v4
- name: Set Xcode Version
run: sudo xcode-select -s /Applications/Xcode_15.3.app
- name: Test
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -verbose -workspace RKWorkspace.xcworkspace -scheme ${{ matrix.scheme }} -destination ${{ matrix.destination }} build test | xcpretty
+16 -19
View File
@@ -6,7 +6,7 @@ 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.
on the [*ResearchKit* Forum](https://developer.apple.com/forums/tags/researchkit) or [contact us](mailto:researchkit@apple.com) for guidance.
Contributing software
@@ -16,8 +16,7 @@ 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)
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:
@@ -27,7 +26,7 @@ To contribute to ResearchKit:
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.
7. Once accepted, your pull request will be merged into main.
Choosing an issue to work on<a name="create"></a>
----------------------------
@@ -36,13 +35,12 @@ 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
* Improving the APIs needed to get started with a ResearchKit project
* New Active Tasks
* Data analysis for Active Tasks
* Backend integrations
If in doubt, bring your idea up on [researchkit-dev](https://lists.apple.com/mailman/listinfo/researchkit-dev).
If in doubt, bring your idea up on the [ResearchKit Forum](https://developer.apple.com/forums/tags/researchkit).
Creating a personal fork<a name="fork"></a>
@@ -56,8 +54,7 @@ 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).
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
@@ -78,7 +75,7 @@ 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)
audit your components with VoiceOver (or other relevant assistive technologies)
enabled.
Keep changes that fix different issues separate. For bug fixes,
@@ -99,11 +96,11 @@ 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).
* Multiple device form factors (for instance, iPhone SE, iPhone 14, iPhone 15 Pro, iPhone 15 Pro Max).
* 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
You can use the `ORKCatalog` app in the `samples` directory to
test your changes.
Submit a pull request<a name="request"></a>
@@ -120,7 +117,7 @@ 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
to main. You are still responsible for your change after it is
accepted. Stay in contact, in case bugs are detected that may require
your attention.
@@ -134,7 +131,7 @@ documentation, or other issues during this process.
Release process
-----------------
The `master` branch is used for work in progress. On `master`:
The `main` branch is used for work in progress. On `main`:
* All test apps should build and run error free.
* Unit tests should all pass.
@@ -142,9 +139,9 @@ The `master` branch is used for work in progress. On `master`:
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,
will branch from `main` 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:
`main`. On the convergence branch, changes will be made only to:
* Fix high priority issues.
* Update documentation.
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2015, Apple Inc. All rights reserved.
Copyright (c) 2015-2024, 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:
+141 -249
View File
@@ -1,283 +1,175 @@
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, taskRun: nil)
let orderedTask = ORKOrderedTask.dBHLToneAudiometryTask(withIdentifier: "dBHLToneAudiometryTaskIdentifier",
intendedUseDescription: nil, options: [])
let taskViewController = ORKTaskViewController(task: orderedTask, taskRun: nil)
taskViewController.delegate = self
present(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(animated: 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 - 2018, 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.
+41
View File
@@ -1,5 +1,46 @@
# ResearchKit Release Notes
## ResearchKit 3.0.1 Release Notes
In addition to general stability and performance improvements, ResearchKit 3.0.1 includes the following updates:
- **ORKFormStep**
The `ORKFormStep` has an additional property named `autoScrollEnabled` that allows developers to disable autoscrolling.
- **ORKBodyItem**
The `ORKBodyItem` has an additional property named `alignImageToTop` that will align a body item's image and text to the top of each other.
- **ORK3DModelStep**
An example of the `ORK3DModelStep` has been added to the ORKCatalog app.
## ResearchKit 3.0 Release Notes
*ResearchKit 3.0* is a beta release
In addition to general stability and performance improvements, ResearchKit 3.0 includes the following updates.
### Framework Updates
In order to modularize ResearchKit we have separated its functionality into the following modules.
- **ResearchKit**
contains the core classes and objects needed to run ResearchKit in any environment.
- **ResearchKitUI**
contains the UI classes and objects needed to present ResearchKit views in an IOS environment.
- **ResearchKitActiveTask**
contains the classes and objects needed to present Active Tasks in an IOS enviroment. These tasks usually require access to device sensors.
### Future Deprecations
The following APIs will be labeled deprecated spring of 2025.
- **Consent**
Our `ORKConsent` APIs will be deprecated in favor of using existing functionality (e.g `ORKInstructionStep` and `ORKWebViewStep`) to achieve informed consent. Please visit the `ORKCatalog` app to view a recommended example.
- **Question Step**
The `ORKQuestionStep` will be deprecated in favor of using the `ORKFormStep`. Certain answer formats will present slightly different UI when used with a `ORKFormStep`. Updates will be made to ensure backwards compatibility before the question step is removed.
## ResearchKit 2.0 Release Notes
*ResearchKit 2.0* supports *iOS* and requires *Xcode 9.0* or newer.
-9
View File
@@ -1,19 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:samples/ORKParkinsonStudy/ORKParkinsonStudy.xcodeproj">
</FileRef>
<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 = '2.0.0'
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, '11.0'
s.requires_arc = true
end
File diff suppressed because it is too large Load Diff
@@ -2,7 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.healthkit</key>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FILEHEADER</key>
<string>
/*
Copyright (c) ___YEAR___, 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 &quot;AS IS&quot;
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.
*/</string>
</dict>
</plist>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
@@ -26,35 +26,21 @@
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>
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<TestPlans>
<TestPlanReference
reference = "container:ResearchKit.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableAddressSanitizer = "YES"
enableUBSanitizer = "YES"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
@@ -70,8 +56,6 @@
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "YES"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "86CC8E991AC09332001CCD89"
BuildableName = "ResearchKitTests.xctest"
BlueprintName = "ResearchKitTests"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES"
onlyGenerateCoverageForSpecifiedTargets = "YES">
<CodeCoverageTargets>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B183A4731A8535D100C76870"
BuildableName = "ResearchKit.framework"
BlueprintName = "ResearchKit"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</CodeCoverageTargets>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES"
testExecutionOrdering = "random">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "86CC8E991AC09332001CCD89"
BuildableName = "ResearchKitTests.xctest"
BlueprintName = "ResearchKitTests"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "ORKDataCollectionTests">
</Test>
</SkippedTests>
</TestableReference>
</Testables>
</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">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
LastUpgradeVersion = "1340"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -14,9 +14,9 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B18FF3A41A9FE25700C0C3B0"
BuildableName = "docs"
BlueprintName = "docs"
BlueprintIdentifier = "CA1C7A40288B0C68004DAB3A"
BuildableName = "ResearchKitUI.framework"
BlueprintName = "ResearchKitUI (iOS)"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -42,17 +40,6 @@
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"
@@ -63,9 +50,9 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B18FF3A41A9FE25700C0C3B0"
BuildableName = "docs"
BlueprintName = "docs"
BlueprintIdentifier = "CA1C7A40288B0C68004DAB3A"
BuildableName = "ResearchKitUI.framework"
BlueprintName = "ResearchKitUI (iOS)"
ReferencedContainer = "container:ResearchKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
+27
View File
@@ -0,0 +1,27 @@
{
"configurations" : [
{
"id" : "A9C8689E-BBEE-4643-8C5D-DBA6A5AF01B2",
"name" : "Configuration 1",
"options" : {
}
}
],
"defaultOptions" : {
},
"testTargets" : [
{
"skippedTests" : [
"ORKDataCollectionTests"
],
"target" : {
"containerPath" : "container:ResearchKit.xcodeproj",
"identifier" : "86CC8E991AC09332001CCD89",
"name" : "ResearchKitTests"
}
}
],
"version" : 1
}
@@ -1,291 +0,0 @@
/*
Copyright (c) 2018, 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 "ORKEnvironmentSPLMeterContentView.h"
#import "ORKRoundTappingButton.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
#import "ORKRingView.h"
#import "ORKProgressView.h"
static const CGFloat DBLabelFontSize = 35.0;
@implementation ORKEnvironmentSPLMeterContentView {
NSLayoutConstraint *_topToProgressViewConstraint;
UIStackView *stackView;
UIStackView *miniStackView;
UILabel *_dBValueLabel;
UILabel *_unitLabel;
UILabel *_thresholdLabel;
CGFloat preValue;
CGFloat currentValue;
CAShapeLayer *circle;
ORKProgressView *_loadingView;
UIProgressView *_progressView;
}
- (instancetype)init {
self = [super init];
if (self) {
preValue = -M_PI_2;
currentValue = 0.0;
self.translatesAutoresizingMaskIntoConstraints = NO;
_ringView = [ORKRingView new];
_ringView.animationDuration = 0.8;
[self addSubview: _ringView];
[self setupThresholdLabel];
[self setupDBValueLabel];
[self setupUnitLabel];
[_ringView addSubview:_dBValueLabel];
[_ringView addSubview:_unitLabel];
[self addSubview:_thresholdLabel];
_loadingView = [ORKProgressView new];
_loadingView.translatesAutoresizingMaskIntoConstraints = NO;
[_ringView addSubview:_loadingView];
_progressView = [UIProgressView new];
_progressView.translatesAutoresizingMaskIntoConstraints = NO;
_progressView.progressTintColor = [self tintColor];
[_progressView setAlpha:0];
[self addSubview:_progressView];
[self setUpConstraints];
}
return self;
}
- (void) setupDBValueLabel {
if (!_dBValueLabel) {
_dBValueLabel = [UILabel new];
}
_dBValueLabel.translatesAutoresizingMaskIntoConstraints = NO;
_dBValueLabel.numberOfLines = 0;
_dBValueLabel.textColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
_dBValueLabel.lineBreakMode = NSLineBreakByWordWrapping;
_dBValueLabel.textAlignment = NSTextAlignmentCenter;
[_dBValueLabel setText:ORKLocalizedString(@"ENVIRONMENTSPL_CALCULATING", nil)];
[_dBValueLabel setFont:[UIFont systemFontOfSize:DBLabelFontSize weight:UIFontWeightThin]];
}
- (void) setupUnitLabel {
if (!_unitLabel) {
_unitLabel = [UILabel new];
}
_unitLabel.translatesAutoresizingMaskIntoConstraints = NO;
_unitLabel.numberOfLines = 0;
_unitLabel.textColor = [[UIColor grayColor] colorWithAlphaComponent:1.0];
_unitLabel.lineBreakMode = NSLineBreakByWordWrapping;
_unitLabel.textAlignment = NSTextAlignmentCenter;
[_unitLabel setText:ORKLocalizedString(@"ENVIRONMENTSPL_UNIT", nil)];
[_unitLabel setHidden:YES];
[_unitLabel setFont:[UIFont systemFontOfSize:15 weight:UIFontWeightLight]];
}
- (void)setupThresholdLabel {
if (!_thresholdLabel) {
_thresholdLabel = [UILabel new];
}
_thresholdLabel.translatesAutoresizingMaskIntoConstraints = NO;
_thresholdLabel.numberOfLines = 0;
_thresholdLabel.textColor = [[UIColor grayColor] colorWithAlphaComponent:1.0];
_thresholdLabel.lineBreakMode = NSLineBreakByWordWrapping;
_thresholdLabel.textAlignment = NSTextAlignmentCenter;
[_thresholdLabel setFont:[UIFont systemFontOfSize:15 weight:UIFontWeightThin]];
}
- (void)tintColorDidChange {
[super tintColorDidChange];
_progressView.progressTintColor = [self tintColor];
}
- (void)setProgress:(CGFloat)progress
animated:(BOOL)animated {
[_progressView setProgress:progress animated:animated];
[UIView animateWithDuration:animated ? 0.2 : 0 animations:^{
[_progressView setAlpha:(progress == 0) ? 0 : 1];
}];
}
- (void)setProgressCircle:(CGFloat)progress {
[_ringView setValue:progress WithColor:progress < 1.0 ? [[UIColor greenColor] colorWithAlphaComponent:0.5] : [[UIColor redColor] colorWithAlphaComponent:0.5]];
}
- (void)setThreshold:(double)threshold {
if (_thresholdLabel) {
[_thresholdLabel setText:[NSString stringWithFormat:ORKLocalizedString(@"ENVIRONMENTSPL_THRESHOLD", nil), @(threshold)]];
}
}
- (void)setDBText:(NSString *)text {
if (_loadingView) {
[_loadingView setHidden:YES];
[_loadingView removeFromSuperview];
_loadingView = nil;
}
if (_dBValueLabel) {
[_dBValueLabel setText:[NSString stringWithFormat:@"%@", text]];
[_unitLabel setHidden:NO];
}
}
- (void)finishStep:(ORKActiveStepViewController *)viewController {
[super finishStep:viewController];
}
- (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)setUpConstraints {
NSArray *constraints = @[
[NSLayoutConstraint constraintWithItem:_ringView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0 constant:0.0],
[NSLayoutConstraint constraintWithItem:_ringView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:-80.0],
[NSLayoutConstraint constraintWithItem:_dBValueLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_ringView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0],
[NSLayoutConstraint constraintWithItem:_dBValueLabel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:_ringView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0],
[NSLayoutConstraint constraintWithItem:_unitLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_ringView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0],
[NSLayoutConstraint constraintWithItem:_unitLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_dBValueLabel
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:10.0],
[NSLayoutConstraint constraintWithItem:_thresholdLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_ringView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0],
[NSLayoutConstraint constraintWithItem:_thresholdLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_ringView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:-20.0],
[NSLayoutConstraint constraintWithItem:_loadingView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_dBValueLabel
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0],
[NSLayoutConstraint constraintWithItem:_loadingView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_dBValueLabel
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:5.0],
[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_ringView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:80.0],
[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:5.0],
[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:-5.0],
];
[self addConstraints:constraints];
[NSLayoutConstraint activateConstraints:constraints];
}
@end
@@ -1,344 +0,0 @@
/*
Copyright (c) 2018, 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 "ORKEnvironmentSPLMeterStepViewController.h"
#import "ORKActiveStepView.h"
#import "ORKRoundTappingButton.h"
#import "ORKEnvironmentSPLMeterContentView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKCollectionResult_Private.h"
#import "ORKEnvironmentSPLMeterResult.h"
#import "ORKEnvironmentSPLMeterStep.h"
#import "ORKHelpers_Internal.h"
#import <AVFoundation/AVFoundation.h>
#include <sys/sysctl.h>
@interface ORKEnvironmentSPLMeterStepViewController () {
AVAudioEngine *_audioEngine;
AVAudioInputNode *_inputNode;
AVAudioUnitEQ *_eqUnit;
AVAudioFrameCount _bufferSize;
uint32_t _sampleRate;
AVAudioFormat *_inputNodeOutputFormat;
int _countToFetch;
NSMutableArray *_rmsBuffer;
dispatch_semaphore_t _semaphoreRms;
float _rmsData;
float _spl;
double _samplingInterval;
double _thresholdValue;
double _sensitivityOffset;
NSInteger _requiredContiguousSamples;
int _counter;
NSMutableArray *_recordedSamples;
}
@property (nonatomic, strong) ORKEnvironmentSPLMeterContentView *environmentSPLMeterContentView;
@end
@implementation ORKEnvironmentSPLMeterStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
_rmsBuffer = [NSMutableArray new];
_semaphoreRms = dispatch_semaphore_create(1);
_rmsData = 0.0;
_spl = 0.0;
_counter = 0;
_samplingInterval = 1.0;
_requiredContiguousSamples = 1;
_sensitivityOffset = -23.3;
_recordedSamples = [NSMutableArray new];
}
return self;
}
- (void)initializeInternalButtonItems {
[super initializeInternalButtonItems];
// Don't show next button
self.internalContinueButtonItem = nil;
self.internalDoneButtonItem = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
_sensitivityOffset = [self sensitivityOffsetForDevice];
_environmentSPLMeterContentView = [ORKEnvironmentSPLMeterContentView new];
[_environmentSPLMeterContentView setProgress:0.01 animated:YES];
self.activeStepView.activeCustomView = _environmentSPLMeterContentView;
[self requestMicrophoneAuthorization];
[self configureAudioSession];
_audioEngine = [[AVAudioEngine alloc] init];
_eqUnit = [[AVAudioUnitEQ alloc] initWithNumberOfBands:6];
_inputNode = [_audioEngine inputNode];
_inputNodeOutputFormat = [_inputNode inputFormatForBus:0];
_sampleRate = (uint32_t)_inputNodeOutputFormat.sampleRate;
_bufferSize = _sampleRate/10;
_countToFetch = _sampleRate/(int)_bufferSize;
[self configureEQ];
[_audioEngine attachNode:_eqUnit];
[_audioEngine connect:_inputNode to:_eqUnit format:_inputNodeOutputFormat];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self start];
_samplingInterval = [self environmentSPLMeterStep].samplingInterval;
_requiredContiguousSamples = [self environmentSPLMeterStep].requiredContiguousSamples;
_thresholdValue = [self environmentSPLMeterStep].thresholdValue;
[_environmentSPLMeterContentView setThreshold:_thresholdValue];
[self splWorkBlock];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[_eqUnit removeTapOnBus:0];
[_audioEngine stop];
[_rmsBuffer removeAllObjects];
}
- (NSString *)deviceType {
return [[UIDevice currentDevice] model];
}
- (double)sensitivityOffsetForDevice {
NSDictionary *lookupTable = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"splMeter_sensitivity_offset" ofType:@"plist"]];
NSString *deviceTypeString = [self deviceType];
double sensitivity = [[lookupTable valueForKey:deviceTypeString] doubleValue];
return ( sensitivity ? : _sensitivityOffset);
}
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
// "Now" is the end time of the result, which is either actually now,
// or the last time we were in the responder chain.
NSDate *now = sResult.endDate;
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKEnvironmentSPLMeterResult *splResult = [[ORKEnvironmentSPLMeterResult alloc] initWithIdentifier:self.step.identifier];
splResult.startDate = sResult.startDate;
splResult.endDate = now;
splResult.sensitivityOffset = _sensitivityOffset;
splResult.recordedSPLMeterSamples = [_recordedSamples copy];
[results addObject:splResult];
sResult.results = [results copy];
return sResult;
}
- (void)requestMicrophoneAuthorization {
[[AVAudioSession sharedInstance] recordPermission];
}
- (void)configureAudioSession {
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord mode:AVAudioSessionModeMeasurement options:AVAudioSessionCategoryOptionMixWithOthers error:&error];
if ([AVAudioSession sharedInstance].isOtherAudioPlaying) {
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive:YES error:&activationError];
}
}
- (void)configureEQ {
_eqUnit.globalGain = 0;
// A-weighting EQ
AVAudioUnitEQFilterParameters *eqCoefficient = _eqUnit.bands[0];
eqCoefficient.filterType = AVAudioUnitEQFilterTypeHighPass;
eqCoefficient.frequency = 290;
eqCoefficient.bypass = NO;
eqCoefficient = _eqUnit.bands[1];
eqCoefficient.filterType = AVAudioUnitEQFilterTypeParametric;
eqCoefficient.frequency = 243;
eqCoefficient.bandwidth = 1.3882;
eqCoefficient.gain = -4.5;
eqCoefficient.bypass = NO;
eqCoefficient = _eqUnit.bands[2];
eqCoefficient.filterType = AVAudioUnitEQFilterTypeParametric;
eqCoefficient.frequency = 450;
eqCoefficient.bandwidth = 0.94428;
eqCoefficient.gain = -1.5;
eqCoefficient.bypass = NO;
eqCoefficient = _eqUnit.bands[3];
eqCoefficient.filterType = AVAudioUnitEQFilterTypeParametric;
eqCoefficient.frequency = 2650;
eqCoefficient.bandwidth = 2.4924;
eqCoefficient.gain = 1.25;
eqCoefficient.bypass = NO;
eqCoefficient = _eqUnit.bands[4];
eqCoefficient.filterType = AVAudioUnitEQFilterTypeParametric;
eqCoefficient.frequency = 10000;
eqCoefficient.bandwidth = 1.0246;
eqCoefficient.gain = -1.5;
eqCoefficient.bypass = NO;
eqCoefficient = _eqUnit.bands[5];
eqCoefficient.filterType = AVAudioUnitEQFilterTypeLowPass;
eqCoefficient.frequency = 11800;
eqCoefficient.bypass = NO;
}
- (void)splWorkBlock {
if (!_audioEngine.isRunning && ![[AVAudioSession sharedInstance] isOtherAudioPlaying]) {
[_eqUnit installTapOnBus:0
bufferSize:_bufferSize
format:_inputNodeOutputFormat
block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
if ([AVAudioSession sharedInstance].recordPermission == AVAudioSessionRecordPermissionGranted) {
if (buffer.frameLength != _bufferSize) {
_bufferSize = buffer.frameLength;
}
int sampleCount = _samplingInterval * _countToFetch;
float rms = 0.0;
for (int i = 0; i < buffer.frameLength; i++) {
float value = [@(buffer.floatChannelData[0][i]) floatValue];
rms += value * value;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_rmsBuffer addObject:@(rms)];
// perform averaging based on capture interval
if (_rmsBuffer.count >= sampleCount + 1) {
float rmsSum = 0.0;
int i = sampleCount;
NSUInteger j = _rmsBuffer.count - 1;
while (i>0) {
rmsSum += [_rmsBuffer[j] floatValue];
i --;
j --;
}
_rmsData = rmsSum/_samplingInterval;
float calValue = _sensitivityOffset;
_spl = (20 * log10f(sqrtf(_rmsData/(float)_sampleRate))) - calValue + 94;
[_recordedSamples addObject:[NSNumber numberWithFloat:_spl]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.environmentSPLMeterContentView setProgressCircle:(_spl/_thresholdValue)];
[self.environmentSPLMeterContentView setDBText:[NSString stringWithFormat:@"%.f", _spl]];
});
[self evaluateThreshold:_spl];
[_rmsBuffer removeAllObjects];
}
dispatch_semaphore_signal(_semaphoreRms);
});
dispatch_semaphore_wait(_semaphoreRms, DISPATCH_TIME_FOREVER);
} else if ([AVAudioSession sharedInstance].recordPermission == AVAudioSessionRecordPermissionDenied) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.environmentSPLMeterContentView setDBText:[NSString stringWithFormat:@"N/A"]];
[_eqUnit removeTapOnBus:0];
[_audioEngine stop];
[_rmsBuffer removeAllObjects];
});
}
}];
if (!_audioEngine.isRunning && ![[AVAudioSession sharedInstance] isOtherAudioPlaying]) {
NSError *error = nil;
[_audioEngine startAndReturnError:&error];
} else {
[_eqUnit removeTapOnBus:0];
[_audioEngine stop];
[_rmsBuffer removeAllObjects];
}
}
}
- (void) evaluateThreshold: (float)spl {
if (spl < _thresholdValue) {
_counter += 1;
if (_counter >= _requiredContiguousSamples) {
dispatch_async(dispatch_get_main_queue(), ^{
[self finish];
});
}
} else {
_counter = 0;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.environmentSPLMeterContentView setProgress:((float)_counter/_requiredContiguousSamples) + 0.01 animated:YES];
});
}
- (void) resetAudioSession {
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeDefault options:AVAudioSessionCategoryOptionMixWithOthers error:&error];
if (error) {
ORK_Log_Error(@"Setting AVAudioSessionCategory failed with error message: \"%@\"", error.localizedDescription);
}
if ([AVAudioSession sharedInstance].isOtherAudioPlaying) {
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive:YES error:&activationError];
if (activationError) {
ORK_Log_Error(@"Activating AVAudioSession failed with error message: \"%@\"", activationError.localizedDescription);
}
}
}
- (void)stepDidFinish {
[super stepDidFinish];
[self.environmentSPLMeterContentView finishStep:self];
[self resetAudioSession];
[self goForward];
}
- (void)start {
[super start];
}
- (ORKEnvironmentSPLMeterStep *)environmentSPLMeterStep {
return (ORKEnvironmentSPLMeterStep *)self.step;
}
@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
@@ -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,257 +0,0 @@
/*
Copyright (c) 2018, 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 "ORKSpeechRecognitionContentView.h"
#import "ORKAudioGraphView.h"
#import "ORKHeadlineLabel.h"
#import "ORKSubheadlineLabel.h"
#import "ORKLabel.h"
#import "ORKAccessibility.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
#import "ORKBorderedButton.h"
@interface ORKSpeechRecognitionContentView () <UITextFieldDelegate>
@property (nonatomic, strong) ORKHeadlineLabel *alertLabel;
@property (nonatomic, strong) ORKAudioGraphView *graphView;
@property (nonatomic, strong) ORKSubheadlineLabel *transcriptLabel;
@end
@implementation ORKSpeechRecognitionContentView {
NSMutableArray *_samples;
UIColor *_keyColor;
UIImageView *_imageView;
UILabel *_textLabel;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.layoutMargins = ORKStandardFullScreenLayoutMarginsForView(self);
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setupTranscriptLabel];
[self setupGraphView];
[self setupRecordButton];
[self setupImageView];
[self setupTextLabel];
[self updateGraphSamples];
[self applyKeyColor];
[self setUpConstraints];
}
return self;
}
- (void)setupImageView {
_imageView = [UIImageView new];
_imageView.contentMode = UIViewContentModeScaleAspectFit;
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_imageView];
}
- (void)setupTextLabel {
_textLabel = [UILabel new];
_textLabel.font = [[UIFontMetrics metricsForTextStyle:UIFontTextStyleTitle2] scaledFontForFont:[UIFont systemFontOfSize:25.0 weight:UIFontWeightMedium]];
_textLabel.textColor = [self tintColor];
_textLabel.textAlignment = NSTextAlignmentCenter;
_textLabel.translatesAutoresizingMaskIntoConstraints = NO;
_textLabel.lineBreakMode = NSLineBreakByWordWrapping;
_textLabel.numberOfLines = 0;
_textLabel.adjustsFontForContentSizeCategory = YES;
[self addSubview:_textLabel];
}
- (void)setupGraphView {
self.graphView = [ORKAudioGraphView new];
_graphView.translatesAutoresizingMaskIntoConstraints = NO;
_graphView.isAccessibilityElement = YES;
_graphView.accessibilityLabel = ORKLocalizedString(@"AX_SPEECH_RECOGNITION_WAVEFORM", nil);
_graphView.accessibilityTraits = UIAccessibilityTraitImage;
[self addSubview:_graphView];
}
- (void)setupTranscriptLabel {
_transcriptLabel = [ORKSubheadlineLabel new];
_transcriptLabel.textAlignment = NSTextAlignmentCenter;
_transcriptLabel.translatesAutoresizingMaskIntoConstraints = NO;
_transcriptLabel.text = ORKLocalizedString(@"SPEECH_RECOGNITION_TRANSCRIPTION_LABEL", nil);
_transcriptLabel.lineBreakMode = NSLineBreakByWordWrapping;
_transcriptLabel.numberOfLines = 0;
[self addSubview:_transcriptLabel];
}
- (void)setupRecordButton {
self.recordButton = [[ORKBorderedButton alloc] init];
self.recordButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.recordButton setTitle:ORKLocalizedString(@"SPEECH_RECOGNITION_START_RECORD_LABEL", nil)
forState:UIControlStateNormal];
self.recordButton.enabled = YES;
self.recordButton.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitStartsMediaSession;
self.recordButton.accessibilityHint = ORKLocalizedString(@"AX_SPEECH_RECOGNITION_START_RECORDING_HINT", nil);
[self addSubview:_recordButton];
}
- (void)setSpeechRecognitionText:(NSString *)speechRecognitionText {
_speechRecognitionText = speechRecognitionText;
[_textLabel setText:speechRecognitionText];
}
- (void)setSpeechRecognitionImage:(UIImage *)speechRecognitionImage {
_speechRecognitionImage = speechRecognitionImage;
[_imageView setImage:speechRecognitionImage];
}
- (void)tintColorDidChange {
[self applyKeyColor];
}
- (void)setFinished:(BOOL)finished {
_finished = finished;
}
- (void)applyKeyColor {
UIColor *keyColor = [self keyColor];
_graphView.keyColor = keyColor;
}
- (UIColor *)keyColor {
return _keyColor ? : [self tintColor];
}
- (void)setKeyColor:(UIColor *)keyColor {
_keyColor = keyColor;
[self applyKeyColor];
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_imageView, _textLabel, _transcriptLabel, _graphView, _recordButton);
const CGFloat graphHeight = 150;
// In case the text on the button is large, ensure that the button can grow larger than the default height if needed
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_imageView]-[_textLabel]-(5)-[_graphView(graphHeight)]-[_transcriptLabel]-buttonGap-[_recordButton(50@250)]-topBottomMargin-|"
options:(NSLayoutFormatOptions)0
metrics:@{
@"graphHeight": @(graphHeight),
@"topBottomMargin" : @(5),
@"buttonGap" : @(20)
}
views:views]];
const CGFloat sideMargin = self.layoutMargins.left + (2 * ORKStandardLeftMarginForTableViewCell(self));
const CGFloat twiceSideMargin = sideMargin * 2;
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_imageView]-|"
options:0
metrics: nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_textLabel]-|"
options:0
metrics: nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-sideMargin-[_graphView]-sideMargin-|"
options:0
metrics: @{@"sideMargin": @(sideMargin)}
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_transcriptLabel]-|"
options:0
metrics: @{@"sideMargin": @(sideMargin)}
views:views]];
// In case the text on the button is large, ensure that the button can grow larger than the default width if needed
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-twiceSideMargin@250-[_recordButton(200@250)]-twiceSideMargin@250-|"
options:0
metrics: @{@"twiceSideMargin": @(twiceSideMargin)}
views:views]];
[constraints addObject:[_recordButton.centerXAnchor constraintEqualToAnchor:self.centerXAnchor]];
[constraints addObject:[_recordButton.leadingAnchor constraintGreaterThanOrEqualToAnchor:self.layoutMarginsGuide.leadingAnchor]];
[constraints addObject:[_recordButton.trailingAnchor constraintLessThanOrEqualToAnchor:self.layoutMarginsGuide.trailingAnchor]];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)setShouldHideTranscript:(BOOL)shouldHideTranscript {
_shouldHideTranscript = shouldHideTranscript;
if (shouldHideTranscript) {
_transcriptLabel.text = nil;
}
}
- (void)updateGraphSamples {
_graphView.values = _samples;
}
- (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)updateRecognitionText:(NSString *)recognitionText {
if (!_shouldHideTranscript) {
_transcriptLabel.text = recognitionText;
}
}
- (void)addRecognitionError:(NSString *)errorMsg {
_transcriptLabel.textColor = [UIColor ork_redColor];
_transcriptLabel.text = errorMsg;
}
- (void)removeAllSamples {
_samples = nil;
[self updateGraphSamples];
}
@end
@@ -1,283 +0,0 @@
/*
Copyright (c) 2018, 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 AVFoundation;
@import Accelerate;
#import "ORKSpeechRecognitionStepViewController.h"
#import "ORKQuestionStep.h"
#import "ORKAnswerFormat.h"
#import "ORKTask.h"
#import "ORKActiveStepView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKSpeechRecognitionContentView.h"
#import "ORKStreamingAudioRecorder.h"
#import "ORKSpeechRecognizer.h"
#import "ORKSpeechRecognitionStep.h"
#import "ORKSpeechRecognitionError.h"
#import "ORKHelpers_Internal.h"
#import "ORKBorderedButton.h"
#import "ORKSpeechRecognitionResult.h"
#import "ORKResult_Private.h"
#import "ORKCollectionResult_Private.h"
#import "ORKStepViewController_Internal.h"
#import "ORKTaskViewController.h"
#import "ORKOrderedTask.h"
@interface ORKSpeechRecognitionStepViewController () <ORKStreamingAudioResultDelegate, ORKSpeechRecognitionDelegate, UITextFieldDelegate>
@end
@implementation ORKSpeechRecognitionStepViewController {
ORKSpeechRecognitionContentView *_speechRecognitionContentView;
ORKStreamingAudioRecorder *_audioRecorder;
ORKSpeechRecognizer *_speechRecognizer;
dispatch_queue_t _speechRecognitionQueue;
ORKSpeechRecognitonResult *_localResult;
BOOL _errorState;
float _peakPower;
}
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = YES;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
ORKSpeechRecognitionStep *step = (ORKSpeechRecognitionStep *) self.step;
_speechRecognitionContentView = [ORKSpeechRecognitionContentView new];
_speechRecognitionContentView.shouldHideTranscript = step.shouldHideTranscript;
self.activeStepView.activeCustomView = _speechRecognitionContentView;
_speechRecognitionContentView.speechRecognitionImage = step.speechRecognitionImage;
_speechRecognitionContentView.speechRecognitionText = step.speechRecognitionText;
[_speechRecognitionContentView.recordButton addTarget:self
action:@selector(recordButtonPressed:)
forControlEvents:UIControlEventTouchDown];
_errorState = NO;
[ORKSpeechRecognizer requestAuthorization];
_localResult = [[ORKSpeechRecognitonResult alloc] initWithIdentifier:self.step.identifier];
_speechRecognitionQueue = dispatch_queue_create("SpeechRecognitionQueue", DISPATCH_QUEUE_SERIAL);
}
- (void)initializeRecognizer {
_speechRecognizer = [[ORKSpeechRecognizer alloc] init];
if (_speechRecognizer) {
[_speechRecognizer startRecognitionWithLocale:[NSLocale localeWithLocaleIdentifier:((ORKSpeechRecognitionStep *)self.step).speechRecognizerLocale] reportPartialResults:YES responseDelegate:self errorHandler:^(NSError *error) {
if (error) {
[self stopWithError:error];
}
}];
}
}
- (void)recordButtonPressed:(id)sender {
if (sender == _speechRecognitionContentView.recordButton) {
if ([_speechRecognitionContentView.recordButton.titleLabel.text
isEqualToString:ORKLocalizedString(@"SPEECH_RECOGNITION_STOP_RECORD_LABEL", nil)]) {
[self stopWithError:nil];
} else {
[self initializeRecognizer];
[self start];
[_speechRecognitionContentView.recordButton setTitle:ORKLocalizedString(@"SPEECH_RECOGNITION_STOP_RECORD_LABEL", nil)
forState:UIControlStateNormal];
_speechRecognitionContentView.recordButton.enabled = YES;
}
}
}
- (void)recordersDidChange {
ORKStreamingAudioRecorder *audioRecorder = nil;
for (ORKRecorder *recorder in self.recorders) {
if ([recorder isKindOfClass:[ORKStreamingAudioRecorder class]]) {
audioRecorder = (ORKStreamingAudioRecorder *)recorder;
break;
}
}
_audioRecorder = audioRecorder;
}
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
if (_speechRecognitionQueue) {
dispatch_sync(_speechRecognitionQueue, ^{
if (_localResult != nil) {
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
[results addObject:_localResult];
sResult.results = [results copy];
}
});
}
return sResult;
}
- (void)stopWithError:(NSError *)error {
if (_speechRecognizer) {
[_speechRecognizer endAudio];
}
if (error) {
ORK_Log_Error(@"Speech recognition failed with error message: \"%@\"", error.localizedDescription);
[_speechRecognitionContentView addRecognitionError:error.localizedDescription];
_speechRecognitionContentView.recordButton.enabled = NO;
_errorState = YES;
}
[self stopRecorders];
}
- (void)resume {
// Background processing is not supported
}
- (void)goForward {
if ([self hasNextStep]) {
ORKQuestionStep *nextStep = [self nextStep];
if (nextStep) {
[((ORKTextAnswerFormat *)nextStep.answerFormat) setDefaultTextAnswer: [_localResult.transcription formattedString]];
}
}
[super goForward];
}
- (nullable ORKQuestionStep *)nextStep {
ORKOrderedTask *task = (ORKOrderedTask *)[self.taskViewController task];
NSUInteger nextStepIndex = [task indexOfStep:[self step]] + 1;
ORKStep *nextStep = [task steps][nextStepIndex];
if ([nextStep isKindOfClass:[ORKQuestionStep class]]) {
return (ORKQuestionStep *)nextStep;
} else {
return nil;
}
}
- (void)stepDidFinish {
_speechRecognitionContentView.finished = YES;
}
- (void)recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error {
[super recorder:recorder didFailWithError:error];
[self stopWithError:error];
}
// Methods running on a different thread
#pragma mark - ORKStreamingAudioResultDelegate
- (void)audioAvailable:(AVAudioPCMBuffer *)buffer {
if (_errorState) {
return;
}
[_speechRecognizer addAudio:buffer];
// audio metering display
float * const *channelData = [buffer floatChannelData];
if (channelData[0]) {
float avgValue = 0;
unsigned long nFrames = [buffer frameLength];
vDSP_maxmgv(channelData[0], 1 , &avgValue, nFrames);
float lvlLowPassTrig = 0.3;
_peakPower = lvlLowPassTrig * ((avgValue == 0)? -100 : 20* log10(avgValue)) + (1 - lvlLowPassTrig) * _peakPower;
float clampedValue = MAX(_peakPower / 60.0, -1) + 1;
dispatch_async(dispatch_get_main_queue(), ^{
[_speechRecognitionContentView addSample:@(clampedValue)];
});
}
}
#pragma mark - ORKSpeechRecognitionDelegate
- (void)didFinishRecognitionWithError:(NSError *)error {
if (_errorState) {
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
ORK_Log_Error(@"Speech framework failed with error code: %ld, and error description: %@", (long)error.code, error.localizedDescription);
NSError *recognitionError = [NSError errorWithDomain:ORKErrorDomain
code:ORKSpeechRecognitionErrorRecognitionFailed
userInfo:@{NSLocalizedDescriptionKey:ORKLocalizedString(@"SPEECH_RECOGNITION_FAILED", nil)}];
[self stopWithError:recognitionError];
} else {
[self stopWithError:nil];
[self finish];
}
});
}
- (void)didHypothesizeTranscription:(SFTranscription *)transcription {
if (_errorState) {
return;
}
dispatch_sync(_speechRecognitionQueue, ^{
_localResult.transcription = transcription;
});
dispatch_async(dispatch_get_main_queue(), ^{
[_speechRecognitionContentView updateRecognitionText:[transcription formattedString]];
});
}
- (void)availabilityDidChange:(BOOL)available {
if (!available) {
dispatch_async(dispatch_get_main_queue(), ^{
[self stopWithError:[NSError errorWithDomain:ORKErrorDomain
code:ORKSpeechRecognitionErrorLanguageNotAvailable
userInfo:@{NSLocalizedDescriptionKey:ORKLocalizedString(@"Speech recognizer not available", nil)}]];
});
}
}
- (void)recordersWillStart {
NSLog(@"Recorder is starting");
}
@end
@@ -1,303 +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 "ORKToneAudiometryContentView.h"
#import "ORKRoundTappingButton.h"
#import "ORKUnitLabel.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@interface ORKToneAudiometryContentView ()
@property (nonatomic, strong) ORKUnitLabel *captionLabel;
@property (nonatomic, strong) UIProgressView *progressView;
@end
@implementation ORKToneAudiometryContentView {
NSLayoutConstraint *_topToProgressViewConstraint;
NSLayoutConstraint *_topToCaptionLabelConstraint;
NSLayoutConstraint *_leftButtonToBottomConstraint;
NSLayoutConstraint *_rightButtonToBottomConstraint;
UILabel *_leftLabel;
UILabel *_rightLabel;
}
- (instancetype)init {
self = [super init];
if (self) {
_captionLabel = [ORKUnitLabel new];
_captionLabel.textAlignment = NSTextAlignmentCenter;
_captionLabel.translatesAutoresizingMaskIntoConstraints = NO;
_progressView = [UIProgressView new];
_progressView.translatesAutoresizingMaskIntoConstraints = NO;
_progressView.progressTintColor = [self tintColor];
[_progressView setAlpha:0];
_leftButton = [[ORKRoundTappingButton alloc] init];
_leftButton.translatesAutoresizingMaskIntoConstraints = NO;
[_leftButton setTitle:ORKLocalizedString(@"TAP_BUTTON_TITLE", nil) forState:UIControlStateNormal];
_rightButton = [[ORKRoundTappingButton alloc] init];
_rightButton.translatesAutoresizingMaskIntoConstraints = NO;
[_rightButton setTitle:ORKLocalizedString(@"TAP_BUTTON_TITLE", nil) forState: UIControlStateNormal];
_leftLabel = [ORKUnitLabel new];
_rightLabel = [ORKUnitLabel new];
_leftLabel.text = ORKLocalizedString(@"TONE_AUDIOMETRY_LABEL_LEFT_EAR", nil);
_rightLabel.text = ORKLocalizedString(@"TONE_AUDIOMETRY_LABEL_RIGHT_EAR", nil);
_leftLabel.textColor = [UIColor lightGrayColor];
_rightLabel.textColor = [UIColor lightGrayColor];
_leftLabel.translatesAutoresizingMaskIntoConstraints = NO;
_rightLabel.translatesAutoresizingMaskIntoConstraints = NO;
_leftButton.accessibilityLabel = ORKLocalizedString(@"AX_TONE_AUDIOMETRY_BUTTON_LEFT_EAR_LABEL", nil);
_leftButton.accessibilityHint = ORKLocalizedString(@"AX_TONE_AUDIOMETRY_BUTTON_LEFT_EAR_HINT", nil);
_rightButton.accessibilityLabel = ORKLocalizedString(@"AX_TONE_AUDIOMETRY_BUTTON_RIGHT_EAR_LABEL", nil);
_rightButton.accessibilityHint = ORKLocalizedString(@"AX_TONE_AUDIOMETRY_BUTTON_RIGHT_EAR_HINT", nil);
// The labels will be included in the button accessibility label, so we should not expose them additionally here.
_leftLabel.isAccessibilityElement = NO;
_rightLabel.isAccessibilityElement = NO;
[self addSubview:_captionLabel];
[self addSubview:_progressView];
[self addSubview:_leftButton];
[self addSubview:_rightButton];
[self addSubview:_leftLabel];
[self addSubview:_rightLabel];
self.translatesAutoresizingMaskIntoConstraints = NO;
_captionLabel.text = nil;
[_captionLabel setHidden:YES];
[self setUpConstraints];
[self updateConstraintConstantsForWindow:self.window];
}
return self;
}
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
[self updateConstraintConstantsForWindow:newWindow];
}
- (void)tintColorDidChange {
[super tintColorDidChange];
self.progressView.progressTintColor = [self tintColor];
}
- (void)setProgress:(CGFloat)progress
caption:(NSString *)caption
animated:(BOOL)animated {
self.captionLabel.text = caption;
[self.progressView setProgress:progress animated:animated];
[UIView animateWithDuration:animated ? 0.2 : 0 animations:^{
[self.progressView setAlpha:(progress == 0) ? 0 : 1];
}];
}
- (void)finishStep:(ORKActiveStepViewController *)viewController {
[super finishStep:viewController];
self.leftButton.enabled = NO;
self.rightButton.enabled = NO;
}
- (void)updateConstraintConstantsForWindow:(UIWindow *)window {
const CGFloat HeaderBaselineToCaptionTop = ORKGetMetricForWindow(ORKScreenMetricCaptionBaselineToTappingLabelTop, window);
const CGFloat AssumedHeaderBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window);
static const CGFloat buttonBottomToBottom = 36.0;
_topToProgressViewConstraint.constant = (HeaderBaselineToCaptionTop / 3) - AssumedHeaderBaselineToStepViewTop;
_topToCaptionLabelConstraint.constant = HeaderBaselineToCaptionTop - AssumedHeaderBaselineToStepViewTop;
_leftButtonToBottomConstraint.constant = buttonBottomToBottom;
_rightButtonToBottomConstraint.constant = buttonBottomToBottom;
}
- (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)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _captionLabel, _leftButton, _rightButton, _leftLabel, _rightLabel);
_topToProgressViewConstraint = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]; // constant will be set in updateConstraintConstantsForWindow:
[constraints addObject:_topToProgressViewConstraint];
_topToCaptionLabelConstraint = [NSLayoutConstraint constraintWithItem:_captionLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]; // constant will be set in updateConstraintConstantsForWindow:
[constraints addObject:_topToCaptionLabelConstraint];
_leftButtonToBottomConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_leftButton
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]; // constant will be set in updateConstraintConstantsForWindow:
[constraints addObject:_leftButtonToBottomConstraint];
_rightButtonToBottomConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_rightButton
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
[constraints addObject:_rightButtonToBottomConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_captionLabel
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:_leftButton
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_captionLabel
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:_rightButton
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_leftLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_leftButton
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_rightLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_rightButton
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_captionLabel]-(>=10)-[_leftButton]"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_captionLabel]-(>=10)-[_rightButton]"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_leftButton]-(>=10)-[_leftLabel]"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_rightButton]-(>=10)-[_rightLabel]"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
NSLayoutConstraint *progressWidthConstraint = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
progressWidthConstraint.priority = UILayoutPriorityRequired - 1;
[constraints addObject:progressWidthConstraint];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_captionLabel]-|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[self addConstraints:constraints];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)updateConstraints {
[self updateConstraintConstantsForWindow:self.window];
[super updateConstraints];
}
@end
@@ -1,150 +0,0 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Copyright (c) 2018, 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 "ORKdBHLToneAudiometryContentView.h"
#import "ORKRoundTappingButton.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@implementation ORKdBHLToneAudiometryContentView {
NSLayoutConstraint *_topToProgressViewConstraint;
}
- (instancetype)init {
self = [super init];
if (self) {
_progressView = [UIProgressView new];
_progressView.translatesAutoresizingMaskIntoConstraints = NO;
_progressView.progressTintColor = [self tintColor];
[_progressView setAlpha:0];
[self addSubview:_progressView];
_tapButton = [[ORKRoundTappingButton alloc] init];
[_tapButton setDiameter:200];
_tapButton.translatesAutoresizingMaskIntoConstraints = NO;
[_tapButton setTitle:ORKLocalizedString(@"TAP_BUTTON_TITLE", nil) forState:UIControlStateNormal];
_tapButton.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitAllowsDirectInteraction;
[self addSubview:_tapButton];
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setUpConstraints];
[self updateConstraintConstantsForWindow:self.window];
}
return self;
}
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
[self updateConstraintConstantsForWindow:newWindow];
}
- (void)didMoveToWindow {
if (self.window != nil && UIAccessibilityIsVoiceOverRunning()) {
// Ensure that VoiceOver is aware of the direct touch area so that the first tap gets registered
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, _tapButton);
}
}
- (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)finishStep:(ORKActiveStepViewController *)viewController {
[super finishStep:viewController];
self.tapButton.enabled = NO;
}
- (void)updateConstraintConstantsForWindow:(UIWindow *)window {
const CGFloat HeaderBaselineToCaptionTop = ORKGetMetricForWindow(ORKScreenMetricCaptionBaselineToTappingLabelTop, window);
const CGFloat AssumedHeaderBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window);
_topToProgressViewConstraint.constant = (HeaderBaselineToCaptionTop / 3) - AssumedHeaderBaselineToStepViewTop;
}
- (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)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _tapButton);
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(100)-[_tapButton]-(100)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_progressView]|"
options:NSLayoutFormatDirectionLeftToRight
metrics:nil
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[_tapButton]-(50)-|"
options:NSLayoutFormatDirectionLeftToRight
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
[self addConstraints:constraints];
[NSLayoutConstraint activateConstraints:constraints];
}
@end
@@ -1,384 +0,0 @@
/*
Copyright (c) 2018, 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 "ORKdBHLToneAudiometryStepViewController.h"
#import "ORKActiveStepView.h"
#import "ORKdBHLToneAudiometryAudioGenerator.h"
#import "ORKRoundTappingButton.h"
#import "ORKdBHLToneAudiometryContentView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKCollectionResult_Private.h"
#import "ORKdBHLToneAudiometryResult.h"
#import "ORKdBHLToneAudiometryStep.h"
#import "ORKHelpers_Internal.h"
@interface ORKdBHLToneAudiometryTransitions: NSObject
@property (nonatomic, assign) float userInitiated;
@property (nonatomic, assign) float totalTransitions;
@end
@implementation ORKdBHLToneAudiometryTransitions
- (instancetype)init
{
self = [super init];
if (self) {
_userInitiated = 1;
_totalTransitions = 1;
}
return self;
}
@end
@interface ORKdBHLToneAudiometryStepViewController () <ORKdBHLToneAudiometryAudioGeneratorDelegate> {
double _prevFreq;
double _currentdBHL;
double _dBHLStepUpSize;
double _dBHLStepDownSize;
int _currentTestIndex;
int _indexOfFreqLoopList;
int _numberOfTransitionsPerFreq;
NSInteger _maxNumberOfTransitionsPerFreq;
BOOL _initialDescent;
BOOL _ackOnce;
ORKdBHLToneAudiometryAudioGenerator *_audioGenerator;
NSArray *_freqLoopList;
NSMutableArray *_arrayOfResultSamples;
NSMutableArray *_arrayOfResultUnits;
NSMutableDictionary *_transitionsDictionary;
UIImpactFeedbackGenerator *_hapticFeedback;
ORKdBHLToneAudiometryFrequencySample *_resultSample;
ORKdBHLToneAudiometryUnit *_resultUnit;
ORKAudioChannel _audioChannel;
dispatch_block_t _preStimulusDelayWorkBlock;
dispatch_block_t _pulseDurationWorkBlock;
dispatch_block_t _postStimulusDelayWorkBlock;
}
@property (nonatomic, strong) ORKdBHLToneAudiometryContentView *dBHLToneAudiometryContentView;
@end
@implementation ORKdBHLToneAudiometryStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = YES;
_indexOfFreqLoopList = 0;
_initialDescent = YES;
_ackOnce = NO;
_prevFreq = 0;
_currentTestIndex = 0;
_transitionsDictionary = [NSMutableDictionary dictionary];
_arrayOfResultSamples = [NSMutableArray array];
_arrayOfResultUnits = [NSMutableArray array];
}
return self;
}
- (void)initializeInternalButtonItems {
[super initializeInternalButtonItems];
// Don't show next button
self.internalContinueButtonItem = nil;
self.internalDoneButtonItem = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
_maxNumberOfTransitionsPerFreq = [self dBHLToneAudiometryStep].maxNumberOfTransitionsPerFrequency;
_freqLoopList = [self dBHLToneAudiometryStep].frequencyList;
_currentdBHL = [self dBHLToneAudiometryStep].initialdBHLValue;
_dBHLStepDownSize = [self dBHLToneAudiometryStep].dBHLStepDownSize;
_dBHLStepUpSize = [self dBHLToneAudiometryStep].dBHLStepUpSize;
self.dBHLToneAudiometryContentView = [[ORKdBHLToneAudiometryContentView alloc] init];
self.activeStepView.activeCustomView = self.dBHLToneAudiometryContentView;
[self.dBHLToneAudiometryContentView.tapButton addTarget:self action:@selector(tapButtonPressed) forControlEvents:UIControlEventTouchDown];
_audioChannel = [self dBHLToneAudiometryStep].earPreference;
_audioGenerator = [[ORKdBHLToneAudiometryAudioGenerator alloc] initForHeadphones:[self dBHLToneAudiometryStep].headphoneType];
_audioGenerator.delegate = self;
_hapticFeedback = [[UIImpactFeedbackGenerator alloc] initWithStyle: UIImpactFeedbackStyleHeavy];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self start];
[self addAnimationToButton:self.dBHLToneAudiometryContentView.tapButton];
}
- (void)addAnimationToButton:(UIButton *)button {
CABasicAnimation *pulseAnimation;
pulseAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale.xy"];
pulseAnimation.duration=1.0;
pulseAnimation.repeatCount=HUGE_VALF;
pulseAnimation.autoreverses=YES;
pulseAnimation.fromValue=[NSNumber numberWithFloat:1.0];
pulseAnimation.toValue=[NSNumber numberWithFloat:0.85];
[button.layer addAnimation:pulseAnimation forKey:@"pulse"];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (_preStimulusDelayWorkBlock) {
dispatch_block_cancel(_preStimulusDelayWorkBlock);
dispatch_block_cancel(_pulseDurationWorkBlock);
dispatch_block_cancel(_postStimulusDelayWorkBlock);
}
[_audioGenerator stop];
}
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
// "Now" is the end time of the result, which is either actually now,
// or the last time we were in the responder chain.
NSDate *now = sResult.endDate;
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKdBHLToneAudiometryResult *toneResult = [[ORKdBHLToneAudiometryResult alloc] initWithIdentifier:self.step.identifier];
toneResult.startDate = sResult.startDate;
toneResult.endDate = now;
toneResult.samples = [_arrayOfResultSamples copy];
toneResult.outputVolume = [AVAudioSession sharedInstance].outputVolume;
toneResult.headphoneType = self.dBHLToneAudiometryStep.headphoneType;
toneResult.tonePlaybackDuration = [self dBHLToneAudiometryStep].toneDuration;
toneResult.postStimulusDelay = [self dBHLToneAudiometryStep].postStimulusDelay;
[results addObject:toneResult];
sResult.results = [results copy];
return sResult;
}
- (void)stepDidFinish {
[super stepDidFinish];
if (_preStimulusDelayWorkBlock) {
dispatch_block_cancel(_preStimulusDelayWorkBlock);
dispatch_block_cancel(_pulseDurationWorkBlock);
dispatch_block_cancel(_postStimulusDelayWorkBlock);
}
[self.dBHLToneAudiometryContentView finishStep:self];
[self goForward];
}
- (void)start {
[super start];
[self estimatedBHLAndPlayToneWithFrequency:_freqLoopList[_indexOfFreqLoopList]];
}
- (void)estimatedBHLAndPlayToneWithFrequency: (NSNumber *)freq {
[_audioGenerator stop];
if (_preStimulusDelayWorkBlock) {
dispatch_block_cancel(_preStimulusDelayWorkBlock);
dispatch_block_cancel(_pulseDurationWorkBlock);
dispatch_block_cancel(_postStimulusDelayWorkBlock);
}
if (_prevFreq != [freq doubleValue]) {
CGFloat progress = 0.001 + (CGFloat)_indexOfFreqLoopList / _freqLoopList.count;
[self.dBHLToneAudiometryContentView setProgress:progress
animated:YES];
_numberOfTransitionsPerFreq = 0;
_currentdBHL = [self dBHLToneAudiometryStep].initialdBHLValue;
_initialDescent = YES;
_ackOnce = NO;
_transitionsDictionary = nil;
_transitionsDictionary = [NSMutableDictionary dictionary];
if (_resultSample) {
_resultSample.units = [_arrayOfResultUnits copy];
}
_arrayOfResultUnits = [NSMutableArray array];
_prevFreq = [freq doubleValue];
_resultSample = [ORKdBHLToneAudiometryFrequencySample new];
_resultSample.channel = _audioChannel;
_resultSample.frequency = [freq doubleValue];
_resultSample.calculatedThreshold = NAN;
[_arrayOfResultSamples addObject:_resultSample];
} else {
_numberOfTransitionsPerFreq += 1;
if (_numberOfTransitionsPerFreq >= _maxNumberOfTransitionsPerFreq) {
_indexOfFreqLoopList += 1;
if (_indexOfFreqLoopList >= _freqLoopList.count) {
_resultSample.units = [_arrayOfResultUnits copy];
[self finish];
return;
} else {
[self estimatedBHLAndPlayToneWithFrequency:_freqLoopList[_indexOfFreqLoopList]];
return;
}
}
}
_resultUnit = [ORKdBHLToneAudiometryUnit new];
_resultUnit.dBHLValue = _currentdBHL;
_resultUnit.startOfUnitTimeStamp = self.runtime;
[_arrayOfResultUnits addObject:_resultUnit];
ORKdBHLToneAudiometryTransitions *currentTransition = [_transitionsDictionary objectForKey:[NSNumber numberWithFloat:_currentdBHL]];
if (!_initialDescent) {
if (currentTransition) {
currentTransition.userInitiated += 1;
currentTransition.totalTransitions += 1;
} else {
currentTransition = [[ORKdBHLToneAudiometryTransitions alloc] init];
[_transitionsDictionary setObject:currentTransition forKey:[NSNumber numberWithFloat:_currentdBHL]];
}
}
const NSTimeInterval toneDuration = [self dBHLToneAudiometryStep].toneDuration;
const NSTimeInterval postStimulusDelay = [self dBHLToneAudiometryStep].postStimulusDelay;
double delay1 = arc4random_uniform([self dBHLToneAudiometryStep].maxRandomPreStimulusDelay - 1);
double delay2 = (double)arc4random_uniform(10)/10;
double preStimulusDelay = delay1 + delay2 + 1;
_resultUnit.preStimulusDelay = preStimulusDelay;
_preStimulusDelayWorkBlock = dispatch_block_create(0, ^{
[_audioGenerator playSoundAtFrequency:[freq floatValue] onChannel:_audioChannel dBHL:_currentdBHL];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(preStimulusDelay * NSEC_PER_SEC)), dispatch_get_main_queue(), _preStimulusDelayWorkBlock);
_pulseDurationWorkBlock = dispatch_block_create(0, ^{
[_audioGenerator stop];
});
// adding 0.2 seconds to account for the fadeInDuration which is being set in ORKdBHLToneAudiometryAudioGenerator
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((preStimulusDelay + toneDuration + 0.2) * NSEC_PER_SEC)), dispatch_get_main_queue(), _pulseDurationWorkBlock);
ORKWeakTypeOf(self)weakSelf = self;
_postStimulusDelayWorkBlock = dispatch_block_create(0, ^{
ORKStrongTypeOf(self) strongSelf = weakSelf;
NSUInteger storedTestIndex = _currentTestIndex;
if (_currentTestIndex == storedTestIndex) {
if (_initialDescent && _ackOnce) {
_initialDescent = NO;
ORKdBHLToneAudiometryTransitions *newTransition = [[ORKdBHLToneAudiometryTransitions alloc] init];
newTransition.userInitiated -= 1;
[_transitionsDictionary setObject:newTransition forKey:[NSNumber numberWithFloat:_currentdBHL]];
}
_currentdBHL = _currentdBHL + _dBHLStepUpSize;
if (currentTransition) {
currentTransition.userInitiated -= 1;
}
_resultUnit.timeoutTimeStamp = self.runtime;
_currentTestIndex += 1;
[strongSelf estimatedBHLAndPlayToneWithFrequency:_freqLoopList[_indexOfFreqLoopList]];
return;
}
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((preStimulusDelay + toneDuration + postStimulusDelay) * NSEC_PER_SEC)), dispatch_get_main_queue(), _postStimulusDelayWorkBlock);
}
- (void)tapButtonPressed {
_ackOnce = YES;
[_hapticFeedback impactOccurred];
_currentTestIndex += 1;
_resultUnit.userTapTimeStamp = self.runtime;
[_audioGenerator stop];
if (_preStimulusDelayWorkBlock) {
dispatch_block_cancel(_preStimulusDelayWorkBlock);
dispatch_block_cancel(_pulseDurationWorkBlock);
dispatch_block_cancel(_postStimulusDelayWorkBlock);
}
if ([self validateResultFordBHL:_currentdBHL]) {
_resultSample.calculatedThreshold = _currentdBHL;
_indexOfFreqLoopList += 1;
if (_indexOfFreqLoopList >= _freqLoopList.count) {
_resultSample.units = [_arrayOfResultUnits copy];
[self finish];
return;
} else {
_currentdBHL = [self dBHLToneAudiometryStep].initialdBHLValue;
[self estimatedBHLAndPlayToneWithFrequency:_freqLoopList[_indexOfFreqLoopList]];
return;
}
} else {
_currentdBHL = _currentdBHL - _dBHLStepDownSize;
[self estimatedBHLAndPlayToneWithFrequency:_freqLoopList[_indexOfFreqLoopList]];
return;
}
}
- (BOOL)validateResultFordBHL:(float)dBHL {
NSNumber *currentKey = [NSNumber numberWithFloat:_currentdBHL];
ORKdBHLToneAudiometryTransitions *currentTransitionObject = [_transitionsDictionary objectForKey:currentKey];
if ((currentTransitionObject.userInitiated/currentTransitionObject.totalTransitions >= 0.5) && currentTransitionObject.totalTransitions >= 2) {
ORKdBHLToneAudiometryTransitions *previousTransitionObject = [_transitionsDictionary objectForKey:[NSNumber numberWithFloat:(dBHL - _dBHLStepUpSize)]];
if ((previousTransitionObject.userInitiated/previousTransitionObject.totalTransitions <= 0.5) && (previousTransitionObject.totalTransitions >= 2)) {
if (currentTransitionObject.totalTransitions == 2) {
if (currentTransitionObject.userInitiated/currentTransitionObject.totalTransitions == 1.0) {
_resultSample.calculatedThreshold = dBHL;
return YES;
} else {
return NO;
}
} else {
_resultSample.calculatedThreshold = dBHL;
return YES;
}
}
}
return NO;
}
- (void)toneWillStartClipping {
_indexOfFreqLoopList += 1;
if (_indexOfFreqLoopList >= _freqLoopList.count) {
_resultSample.units = [_arrayOfResultUnits copy];
[self finish];
} else {
[self estimatedBHLAndPlayToneWithFrequency:_freqLoopList[_indexOfFreqLoopList]];
}
}
- (ORKdBHLToneAudiometryStep *)dBHLToneAudiometryStep {
return (ORKdBHLToneAudiometryStep *)self.step;
}
@end
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Face.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Face@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Face@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "guideAreaCorners.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "airpods@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "airpods@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "airpods@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "airpods_3rd_gen@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "airpods_3rd_gen@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "airpods_3rd_gen@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "airpods_max@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "airpods_max@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "airpods_max@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "airpods_pro@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "airpods_pro@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "airpods_pro@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

@@ -1,27 +1,18 @@
{
"images" : [
{
"idiom" : "iphone",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "iphone",
"idiom" : "universal",
"filename" : "amslerGrid@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"idiom" : "universal",
"filename" : "amslerGrid@3x.png",
"scale" : "3x"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"filename" : "amslerGrid@2x~ipad.png",
"scale" : "2x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 23 KiB

@@ -2,15 +2,16 @@
"images" : [
{
"idiom" : "universal",
"filename" : "audiometry.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "audiometry@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "audiometry@3x.png",
"scale" : "3x"
}
],
Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "earpods@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "earpods@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "earpods@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Tone-Audiometry-Headphones.pdf",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Tone-Audiometry-Headphones@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "Tone-Audiometry-Headphones@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1,42 +1,18 @@
{
"images" : [
{
"idiom" : "iphone",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "1x"
},
{
"idiom" : "iphone",
"idiom" : "universal",
"filename" : "heart-fitness@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"idiom" : "universal",
"filename" : "heart-fitness@3x.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "3x"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"filename" : "heart-fitness@2x~ipad.png",
"scale" : "2x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 454 B

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 B

After

Width:  |  Height:  |  Size: 17 KiB

@@ -1,42 +1,18 @@
{
"images" : [
{
"idiom" : "iphone",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "1x"
},
{
"idiom" : "iphone",
"idiom" : "universal",
"filename" : "heartbeat@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"idiom" : "universal",
"filename" : "heartbeat@3x.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "3x"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"filename" : "heartbeat@2x~ipad.png",
"scale" : "2x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 17 KiB

@@ -1,42 +1,18 @@
{
"images" : [
{
"idiom" : "iphone",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "1x"
},
{
"idiom" : "iphone",
"idiom" : "universal",
"filename" : "holepegtest1@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"idiom" : "universal",
"filename" : "holepegtest1@3x.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "3x"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"filename" : "holepegtest1@2x~ipad.png",
"scale" : "2x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

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