Compare commits

...

847 Commits

Author SHA1 Message Date
Yuan Zhu 4259a1cc92 Update pod spec version number. 2016-05-24 10:54:15 -07:00
Ben DiFrancesco 70d4532d0e Declare ORKScrollToTopAnimationDuration and ORKCGFloatInvalidValue as extern in ORKHelpers.h; fixes #679 2016-05-24 10:53:53 -07:00
Yuan Zhu 23900bed0e Merge pull request #663 from YuanZhu-apple/stable_class_visibility
Fix class visibility
2016-04-19 17:10:44 -07:00
Yuan Zhu 8c8a1adc47 Fix class visibility 2016-04-19 17:05:49 -07:00
Yuan Zhu 429c3c9886 Update the versioning and pod spec 2016-01-11 15:20:01 -08:00
Yuan Zhu 4228cf46c6 Merge pull request #598 from YuanZhu-apple/convergence_batch2
Doc updates and other fixes for convergence
2016-01-11 11:25:46 -08:00
Umer Khan ce31ebd366 Merge branch 'releaseNotes' into 'convergence'
Release notes

See merge request !35
2016-01-08 12:17:11 -08:00
Umer Khan 135ec4a3f2 Minor edits. 2016-01-08 12:10:56 -08:00
Umer Khan a30119aa0d Merge branch 'convergence_active_task_should_resume_properly' into 'convergence'
Convergence active task should resume properly

Fix for <rdar://problem/24095971> ResearchKit: progress for 2 finger tapping stopped after the passcode auth.

Stop using background delivery in health recorder.

See merge request !37
2016-01-07 16:12:36 -08:00
Yuan Zhu 31526c6664 Disable background delivery in health recorder. 2016-01-07 15:29:59 -08:00
Yuan Zhu e5ac62f298 Fix for progress for 2 finger tapping stopped after the passcode auth 2016-01-07 15:29:21 -08:00
Yuan Zhu bb1be965a2 Merge branch 'convergence_incorporate_documentation' into 'convergence'
Convergence incorporate documentation

Incorporate documentation update from devpubs.

See merge request !36
2016-01-06 17:42:42 -08:00
Yuan Zhu 3fb266139e More doc update. 2016-01-06 13:59:38 -08:00
Yuan Zhu 0b2216c6cf Update for review. 2016-01-06 13:56:39 -08:00
Yuan Zhu c90d8c7fbd One more merge conflict 2016-01-06 11:06:09 -08:00
Yuan Zhu 3cb705c123 Fix appledoc warnings 2016-01-06 11:03:26 -08:00
Yuan Zhu 1817398f61 Merge branch 'convergence' into convergence_incorporate_documentation
Conflicts:
	ResearchKit/Charts/ORKGraphChartView.h
	ResearchKit/Common/ORKAnswerFormat.h
	ResearchKit/Common/ORKDefines.h
	ResearchKit/Common/ORKNavigableOrderedTask.h
	ResearchKit/Common/ORKResult.h
	ResearchKit/Common/ORKResultPredicate.h
	ResearchKit/Consent/ORKConsentReviewController.m
2016-01-05 23:18:21 -08:00
Umer Khan b542c46189 Formatting fixes. 2016-01-05 18:36:46 -08:00
Umer Khan b6cc636975 Minor fixes. 2016-01-05 18:30:24 -08:00
Umer Khan 1844a0774c Added Sample App info. 2016-01-05 18:29:27 -08:00
Yuan Zhu 6a1343622d Update charts documentation. 2016-01-05 18:00:56 -08:00
Yuan Zhu a3b45b6268 Merge branch 'convergence' of https://github.com/ResearchKit/ResearchKit into convergence 2016-01-05 16:34:20 -08:00
Yuan Zhu f076b69a98 Merge pull request #594 from rsanchezsaez/rsanchezsaez-convergence-ORKGraphChartView
[ORKGraphChartView] Fix wrong selector check on accessibility (convergence)
2016-01-05 16:15:25 -08:00
Umer Khan 39e17e7867 Added RK 1.3 notes. 2016-01-05 14:52:53 -08:00
Ricardo Sánchez-Sáez 663426250f [ORKGraphChartView] Fix wrong selector check on accessibility 2016-01-05 02:27:50 +00:00
Umer Khan 197eb8422a Merge branch 'convergence_fix_responder_check' into 'convergence'
Fix "ORKGraphChartView checks wrong delegate method for respondsToSelector"

Use the correct `respondsToSelector:` checking.

This is an issue reported by https://github.com/ResearchKit/ResearchKit/issues/589

See merge request !34
2016-01-04 11:53:14 -08:00
Yuan Zhu fe10cd8a71 Merge branch 'convergence' of https://github.com/ResearchKit/ResearchKit into convergence 2016-01-04 11:40:16 -08:00
Yuan Zhu 63dfad2b0d Merge pull request #590 from rsanchezsaez/rsanchezsaez-convergence-ORKSampleFix
ORKSample fixes
2016-01-04 11:39:36 -08:00
Yuan Zhu 886605e013 Use the correct respondsToSelector: checking 2016-01-04 10:43:49 -08:00
Ricardo Sánchez-Sáez 4c0a4a1e51 [ORKSample] Fix project
- Add ResearchKit as an embed framework (otherwise it won't run on the device)
- Remove extraneous Development Team
2015-12-23 20:38:24 +00:00
Yuan Zhu aa2b1f9e61 Merge pull request #587 from YuanZhu-apple/convergence_batch
Convergence patch
2015-12-22 12:35:23 -08:00
John Earl fed9fb9ce6 Merge branch 'convergence_fix_progress_is_missing_on_first_step' into 'convergence'
Fix task progress is missing on first step.

Fix for <rdar://problem/23940893> Question form does not show "1 of 6" progress at the top when the modal is displayed

Since we pulled `currentStepViewController` into `shouldDisplayProgressLabel`, we also need to move progressLabel generation after `currentStepViewController` has been assigned.

Today's `shouldDisplayProgressLabel`:
```
- (BOOL)shouldDisplayProgressLabel {
    return self.showsProgressInNavigationBar && [_task respondsToSelector:@selector(progressOfCurrentStep:withResult:)] && self.currentStepViewController.step.showsProgress;
}
```

See merge request !33
2015-12-17 13:47:00 -08:00
Yuan Zhu 6a786cfb37 Fix task progress is missing on first step. 2015-12-17 13:27:39 -08:00
Umer Khan 39d76c8ed6 Merge branch 'convergence_fix_orksample_dependency' into 'convergence'
Add RK as ORKSample's dependency.

See merge request !31
2015-12-16 16:05:26 -08:00
Yuan Zhu 7059bd39a6 Add RK as ORKSample's dependency. 2015-12-16 14:52:28 -08:00
Umer Khan dddc633e3a Merge branch 'convergence_ax_wait_step' into 'convergence'
AX for wait step

From Ryan, even through `UIProgressView` is not accessible.

See merge request !30
2015-12-16 11:18:36 -08:00
Umer Khan 9e358e7fc5 Merge branch 'convergence_fix_catalog_after_verification_step_change' into 'convergence'
API changed after verification step update, need to update ORKCatalog as well.

See merge request !29
2015-12-16 11:10:45 -08:00
Yuan Zhu 0aacde2057 AX for wait step 2015-12-16 10:59:56 -08:00
Yuan Zhu 5bdd973315 Fix unit tests. 2015-12-16 10:30:09 -08:00
Yuan Zhu cb4514328e API changed after verification step update, need to update ORKCatalog as well. 2015-12-15 17:49:33 -08:00
Umer Khan 84710f773f Merge branch 'convergence_update_pod_spec' into 'convergence'
Update pod spec to include `swift` files

According to
https://github.com/ResearchKit/ResearchKit/pull/383#issuecomment-161036351

See merge request !28
2015-12-15 16:54:04 -08:00
Yuan Zhu 42005af39c Update pod spec to include swift files
According to
https://github.com/ResearchKit/ResearchKit/pull/383#issuecomment-161036351
2015-12-15 16:51:46 -08:00
Yuan Zhu 9c847f8fe6 Merge branch 'passcodeIcon' into 'convergence'
Adding app icon to ORKPasscodeStep.

See merge request !27
2015-12-15 13:06:06 -08:00
Umer Khan aac584b2f1 Resolving merge conflicts. 2015-12-15 11:05:09 -08:00
Yuan Zhu 4be283e888 Localization strings update. 2015-12-14 17:36:31 -08:00
Umer Khan 4d37142873 Merge branch 'convergence_new_sample_app' into 'convergence'
Checkin the new sample app

New app was added as `ORKSample` under `samples` folder.

See merge request !23
2015-12-14 17:06:30 -08:00
Umer Khan 08b48589da Added new metric for icon on vertical container view to support iPad. 2015-12-14 17:04:34 -08:00
Umer Khan 6ba85a1504 Merge branch 'convergence_accessibility_fix_value_picker' into 'convergence'
Accessibility fix value picker

R=me.

From Ryan:
This next issue is with VoiceOver speaking the wrong words when changing ORKValuePicker’s value.  Ultimately, we need to fix this on our side:
<rdar://problem/23885294> UITextField AX broken when connected as the firstResponder to a UIPicker.

I have attached a workaround patch to rdar://problem/23710698. The problem is that when we change the value of the picker and a text field is the firstResponder, VoiceOver thinks this is a selection changed event and reads the delta change. For example, going from Male to Female, the delta is “LE.” The workaround is, since this textfield is not editable, to keep the selectedTextRange as 0,0 so that VO doesn’t do the selection changed behavior.

Please let me know if you have any questions!

See merge request !26
2015-12-14 16:54:18 -08:00
Yuan Zhu 5fc4316e22 Auto deselect selected cell on profile page. 2015-12-14 16:54:18 -08:00
Yuan Zhu 287dcd979c Merge branch 'verificationRedesign' into 'convergence'
Verification Step redesign.

Verification step redesign as per HI.

See merge request !20
2015-12-14 16:47:48 -08:00
Umer Khan 29f2d16676 Adding app icon to ORKPasscodeStep. 2015-12-14 16:46:33 -08:00
Yuan Zhu b022ae3589 Limit minimum date in answer format to current time. 2015-12-14 16:46:02 -08:00
Umer Khan 76bbbbe604 Delegate callback refactor for keyboard on ORKPasscodeStepViewController. 2015-12-14 16:40:32 -08:00
Umer Khan a322f0b17f Minor refactor. 2015-12-14 16:32:55 -08:00
Yuan Zhu f11d17752f Accessibility fix value picker
From Ryan:
This next issue is with VoiceOver speaking the wrong words when changing ORKValuePicker’s value.  Ultimately, we need to fix this on our side:
<rdar://problem/23885294> UITextField AX broken when connected as the firstResponder to a UIPicker.

I have attached a workaround patch to rdar://problem/23710698. The problem is that when we change the value of the picker and a text field is the firstResponder, VoiceOver thinks this is a selection changed event and reads the delta change. For example, going from Male to Female, the delta is “LE.” The workaround is, since this textfield is not editable, to keep the selectedTextRange as 0,0 so that VO doesn’t do the selection changed behavior.

Please let me know if you have any questions!
2015-12-14 14:32:10 -08:00
Umer Khan 14a815d63e Merge branch 'convergence_fix_merge_crash_bug' into 'convergence'
The `break` was in wrong place which let `confirmAnswerFormat` use a `scaleCell` instead.

It is used to crash `registration test`.

See merge request !25
2015-12-14 14:18:09 -08:00
Yuan Zhu 1b4b0166b8 The break was in wrong place which let confirmAnswerFormat use a scaleCell instead. 2015-12-14 14:13:01 -08:00
Umer Khan 669269fd45 Merge branch 'convergence_full_length_seperator_line' into 'convergence'
Apply full width section separator on from/question page (including location question)

![Simulator_Screen_Shot_Dec_10__2015__5.49.40_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/e6dc184239617bcde03b39a8d8588ca8/Simulator_Screen_Shot_Dec_10__2015__5.49.40_PM.png)
![Simulator_Screen_Shot_Dec_10__2015__5.49.37_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/74494292d8cdffb621c1d7b9fa4266d6/Simulator_Screen_Shot_Dec_10__2015__5.49.37_PM.png)
![Simulator_Screen_Shot_Dec_10__2015__5.49.24_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/50e45d20f29ac510f927d823fb9ede2e/Simulator_Screen_Shot_Dec_10__2015__5.49.24_PM.png)
![Simulator_Screen_Shot_Dec_10__2015__5.49.33_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/e0e80fe5241088ed55c1d1878e01497b/Simulator_Screen_Shot_Dec_10__2015__5.49.33_PM.png)
![Simulator_Screen_Shot_Dec_10__2015__5.49.06_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/b42e3e4005363bd00e4e7f6c144ddde9/Simulator_Screen_Shot_Dec_10__2015__5.49.06_PM.png)
![Simulator_Screen_Shot_Dec_10__2015__5.49.07_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/fb4889714cfa2c1ed6bf7ca80b2d9cf7/Simulator_Screen_Shot_Dec_10__2015__5.49.07_PM.png)
![Simulator_Screen_Shot_Dec_10__2015__5.48.59_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/11232d3553fd1b5d477f81212f5981c4/Simulator_Screen_Shot_Dec_10__2015__5.48.59_PM.png)

See merge request !22
2015-12-11 16:01:59 -08:00
Yuan Zhu 3f7c1d15d5 Checkin the new sample app 2015-12-11 15:46:30 -08:00
Yuan Zhu ca136a9ce1 Merge branch 'convergence' of gitlab.sd.apple.com:y_zhu/GitHub-ResearchKit-Fork into convergence_full_length_seperator_line
Conflicts:
	ResearchKit/Common/ORKFormStepViewController.m
2015-12-11 14:11:29 -08:00
Yuan Zhu fe2ea1e3d8 Merge branch 'eligFix' into 'convergence'
Removed eligibility module.

As per HI, the eligibility module should re-use the text choice answer format look and feel. This PR removes the current `ORKEligbilityAnswerFormat` and updates `ORKTest` and `ORKCatalog` examples of eligibility using `ORKTextChoiceAnswerFormat`.

See merge request !17
2015-12-11 13:30:50 -08:00
Yuan Zhu eedcff0ab0 Merge branch 'passcodeFix' into 'convergence'
Passcode keyboard orientation fix.

The orientation for the passcode step was not being registered from `supportedInterfaceOrientations`, so this fix forwards that instance method to a class method of the same name to retrieve the value. This allows the Task View Controller to retrieve the values before the class is initialized.

See merge request !16
2015-12-11 13:24:28 -08:00
Yuan Zhu 00bd267c1b Apply full width section separator on from/question page (including location question) 2015-12-10 17:52:28 -08:00
Umer Khan d9c005aa18 Refactored eligibility survey also. 2015-12-10 16:40:27 -08:00
Umer Khan be02e1a22a Refactored eligibility task. 2015-12-10 16:38:59 -08:00
Umer Khan b474f6f12d Added additional documentation. 2015-12-10 14:45:33 -08:00
Yuan Zhu bc263d92af Merge branch 'convergence_accessibility_fix_for_account_creation' into 'convergence'
Accessibility fix for password field

<rdar://problem/23829496> RK Accessibility Account creation control issues

I looked, it is good to me.

See merge request !21
2015-12-10 13:13:39 -08:00
Yuan Zhu 0575f21c3e Accessibility fix for password field: <rdar://problem/23829496> RK Accessibility: Account creation control issues 2015-12-09 17:58:57 -08:00
Umer Khan 88543a14d6 Verification Step redesign. 2015-12-09 17:11:35 -08:00
Yuan Zhu cd8a801738 Merge branch 'verificationRedesign' into 'convergence'
Added new strings for verification step and removed old strings.

See merge request !19
2015-12-09 15:04:26 -08:00
Umer Khan 30af7f46f7 Merge branch 'convergence_new_icon_from_hi' into 'convergence'
Use the new icon for ORKTest app

See merge request !18
2015-12-09 14:59:46 -08:00
Umer Khan 1e889ad7dc Added new strings for verification step and removed old strings. 2015-12-09 14:58:06 -08:00
Umer Khan 839c8eca53 Removed class method forwarding. 2015-12-09 14:40:14 -08:00
Yuan Zhu 48ed4b3771 Use the new icon for ORKTest app 2015-12-09 14:23:07 -08:00
Umer Khan e6f4c1deb8 Merge branch 'convergence_peg_test_missing_spoken_instruction_on_last_step' into 'convergence'
All other three of four testing steps has spoken instruction.

For <rdar://problem/23778535> [Clout]: US: RedRiver7M1453: No VoiceOver speaks at the Page of 'Put the peg behind the line using your left hand.'

See merge request !13
2015-12-09 12:47:24 -08:00
Umer Khan ae2bff43fa Merge branch 'convergence_support_multiline_in_form_header' into 'convergence'
Wrap text in form header view if the text is long.

Wrap text in form header view if the text is long.

![Simulator_Screen_Shot_Dec_8__2015__6.00.30_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/84632e2b1a3e61e56983168ddfa4e3c7/Simulator_Screen_Shot_Dec_8__2015__6.00.30_PM.png)

See merge request !14
2015-12-09 12:45:53 -08:00
Umer Khan 14260e0df1 Merge branch 'convergence_add_icon_for_ipad_pro' into 'convergence'
Add app icons for iPad pro

See merge request !15
2015-12-09 12:40:06 -08:00
Umer Khan 4153702c2d Removed eligibility answer format, survey cell, form item cell, and implementations from ORKTest and ORKCatalog. 2015-12-09 12:08:34 -08:00
Umer Khan a9494ce5d8 Passcode keyboard orientation fix. 2015-12-09 11:04:13 -08:00
Yuan Zhu 0b06d4c18a Add app icons for iPad pro 2015-12-09 10:41:22 -08:00
Yuan Zhu 2b6d1fcab9 Wrap text in form header view if the text is long. 2015-12-08 17:59:25 -08:00
Yuan Zhu eb52acefa9 All other three of four testing steps has spoken instruction. 2015-12-08 12:55:14 -08:00
Umer Khan 82de8783bd Merge branch 'convergence_fix_wait_step_progessview_size' into 'convergence'
Fix the size of progress view in wait step.

Also documented the view hierarchy of ORKVerticalContainerView

See reopened radar:
<rdar://problem/23638006> ResearchKit: updateText of ORKWaitStepViewController does not work as expected

See merge request !12
2015-12-04 16:39:52 -08:00
Yuan Zhu 0dea3dd673 Localization strings update 2015-12-04 13:51:39 -08:00
Yuan Zhu 6f4c072f93 Fix the size of progress view in wait step.
Also documented the view hierarchy of ORKVerticalContainerView
2015-12-04 12:17:13 -08:00
Yuan Zhu fee0d2d7b6 Merge branch 'regexFix' into 'convergence'
Added validation checking for Text Survey Cell.

Currently, text validation from ORKTextAnswerFormat is only applied to ORKFormItemCell.
This patch adds the validation checking to ORKSurveyAnswerCellForText.

This is in response to a radar generated by QA.
radar://23695918

See merge request !9
2015-12-03 13:26:55 -08:00
Umer Khan 610a1fd93f Minor fix. 2015-12-02 16:05:44 -08:00
Umer Khan 36bda05556 Merge branch 'convergence_ax_scale_question_fix' into 'convergence'
Fix for <rdar://problem/23710807> RK Accessibility: Scale Question

`swipe up` by passed the normal `touch to assign value` process, thus, set `showThumb = YES;` is required.

From Ryan:
1. Tap the slider
(No value is read)
(VoiceOver cursor is moved to the slider element)

2. Swipe up to increment the value (i.e. calls accessibilityIncrement which calls axBumpValue)

Expected Behavior:
Now that we incremented the slider, it has a value and should be spoken.

Actual Behavior:
No value is spoken.
(In the debugger, I can see showThumb is NO, thus we don’t speak an accessibilityValue).

Conclusion:
It seems to me once you made a change to the slider’s value (via accessibilityIncrement or accessibilityDecrement), showThumb should become YES.

See merge request !11
2015-12-02 16:03:43 -08:00
Yuan Zhu 069ea16731 Merge branch 'passcodeFix' into 'convergence'
Locked Passcode View Controllers to portrait only.

The Passcode View Controllers truncate the passcode text field in landscape mode.
To avoid this problem, this PR locks the passcode view controller orientation to portrait only.
This solves the stated problem and provides a more intuitive UI for passcode entry.

This is in response to the radar generated by QA.
radar://23713589

See merge request !10
2015-12-02 15:35:22 -08:00
Umer Khan a1ed3ea711 Refactored continue button logic and removed validation logic from textfield delegate. 2015-12-02 15:27:12 -08:00
Yuan Zhu d910062bb9 Merge branch 'dobFix' into 'convergence'
Add current date to maximum date for ORKRegistrationStep's dob answer format.

See merge request !7
2015-12-02 14:57:02 -08:00
Yuan Zhu ba5d80c6c1 Fix for <rdar://problem/23710807> RK Accessibility: Scale Question
`swipe up` by passed the normal `touch to assign value` process, thus, set `showThumb = YES;` is required.

From Ryan:
1. Tap the slider
(No value is read)
(VoiceOver cursor is moved to the slider element)

2. Swipe up to increment the value (i.e. calls accessibilityIncrement which calls axBumpValue)

Expected Behavior:
Now that we incremented the slider, it has a value and should be spoken.

Actual Behavior:
No value is spoken.
(In the debugger, I can see showThumb is NO, thus we don’t speak an accessibilityValue).

Conclusion:
It seems to me once you made a change to the slider’s value (via accessibilityIncrement or accessibilityDecrement), showThumb should become YES.
2015-12-02 14:38:54 -08:00
Umer Khan 21ada70ae4 Locked Passcode View Controllers to portrait only. 2015-12-02 14:28:53 -08:00
Umer Khan 9be3f057be Added validation checking for Text Survey Cell. 2015-12-02 13:43:02 -08:00
Umer Khan 51c23ccf17 Changed dispatch_once to an ivar. 2015-12-01 16:20:22 -08:00
Umer Khan 113b7422a0 Added additional initializer. 2015-12-01 16:09:08 -08:00
Umer Khan c852c62262 Added static, updated formItems to generate today's date for maximumDate, and fixed serialization issues. 2015-12-01 15:50:52 -08:00
Yuan Zhu c27b784870 Merge branch 'convergence' of https://github.com/ResearchKit/ResearchKit into convergence 2015-12-01 15:31:58 -08:00
Andrew Hill 2510bc7f97 Correct Destionation
Changed all instances of Destionation to Destination
2015-12-01 15:30:04 -08:00
Tom Welsh de7860b60a Allow ORKLoginStepViewController to be subclassed by making the class symbol visible 2015-12-01 15:28:35 -08:00
Yuan Zhu 37c65bdc55 Merge branch 'convergence' of https://github.com/ResearchKit/ResearchKit into convergence 2015-12-01 14:40:52 -08:00
Umer Khan 4fe13d0b27 Minor refactor. 2015-12-01 13:29:29 -08:00
Umer Khan 853d4384fd Refactored registration form items generation. 2015-12-01 13:16:43 -08:00
Yuan Zhu f9669508dc Merge branch 'tappingResultBugFix' into 'convergence'
Tapping sample result bug fix.

See merge request !8
2015-12-01 10:29:32 -08:00
Umer Khan e1ea72b861 Tapping sample result bug fix. 2015-11-30 17:58:46 -08:00
Umer Khan 1cf445af09 Add current date to maximum date for ORKRegistrationStep's dob answer format. 2015-11-30 14:03:53 -08:00
Yuan Zhu fc1c328b68 localized strings update on convergence branch. 2015-11-30 13:26:47 -08:00
Umer Khan 7b7a851cca Merge branch 'convergence_fix_pie_chart_label_overlap' into 'convergence'
Fix issue https://github.com/ResearchKit/ResearchKit/issues/558

Corrected the calculation inside `ORKCenteredCollectionViewLayout`

To test, update `ChartDataSources.swift`'s `pieChartView` method to be like this:
```
     func pieChartView(pieChartView: ORKPieChartView, titleForSegmentAtIndex index: Int) -> String {
        switch index {
        case 0:
            return "Steps"
        case 1:
            return "Tasks"
        case 2:
            return "Surveys completed"
        default:
            return "test"
        }
     }

```

After this fix:

![Screen_Shot_2015-11-19_at_6.02.59_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/d574cf99032e90264eee6afaf3370ad9/Screen_Shot_2015-11-19_at_6.02.59_PM.png)

See merge request !3
2015-11-30 13:16:44 -08:00
Umer Khan 37ac134b5e Merge branch 'convergence_change_activity_indicator' into 'convergence'
Change to use system activity indicator in wait step.

![Simulator_Screen_Shot_Nov_20__2015__3.26.51_PM](https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork/uploads/20c83818ac6c6be1debef7bef0f8be9c/Simulator_Screen_Shot_Nov_20__2015__3.26.51_PM.png)

See merge request !5
2015-11-30 13:16:21 -08:00
Umer Khan 067f8f8e3d Merge branch 'convergence_add_ORKWaitStepViewController_to_RK.h' into 'convergence'
Make WaitStepVC public and add it to `ResearchKit.h`

This is a fix for `<rdar://problem/23621910> ResearchKit: ORKWaitStepViewController.h is not included in the <ResearchKit/ResearchKit.h>`

See merge request !4
2015-11-30 13:13:25 -08:00
Umer Khan 7d30dd09f3 Merge branch 'convergence_loc_two_lines' into 'convergence'
Fix for rdar://problem/23574379 [Clout]: RS: RedRiver7M1408: Clipping string…

Make buttons and labels multilines.

See merge request !2
2015-11-30 12:55:28 -08:00
Yuan Zhu 19921baf55 Merge pull request #569 from shazino/convergence
Fix PSAT progress indicator tint color.
2015-11-23 14:24:36 -08:00
Julien Therier ffd8552aa8 Fix PSAT progress indicator tint color. 2015-11-21 11:48:42 +01:00
Yuan Zhu 140e1ebae0 Fix for rdar://problem/23638006 ResearchKit: updateText of ORKWaitStepViewController does not work as expected 2015-11-20 17:33:05 -08:00
Yuan Zhu 9338ea8b59 Use RK native layout instead of custom layout. 2015-11-20 16:15:33 -08:00
Yuan Zhu 63d56e44f8 Change to use system activity indicator in wait step. 2015-11-20 15:22:23 -08:00
Yuan Zhu 3daf9484c4 Make WaitStepVC public and add it to ResearchKit.h 2015-11-20 11:21:26 -08:00
Yuan Zhu d87372923b Fix issue https://github.com/ResearchKit/ResearchKit/issues/558
Corrected the calculation inside `ORKCenteredCollectionViewLayout`
2015-11-19 17:58:53 -08:00
Yuan Zhu 3dccc6d438 Fix radar <rdar://problem/23574379> [Clout]: RS: RedRiver7M1408: Clipping string RESEND_EMAIL_BUTTON_TITLE.
Make buttons and labels multiline.
2015-11-19 14:32:03 -08:00
Yuan Zhu 50cf8171f5 Change english string for "LOCATION_ERROR_TITLE" 2015-11-18 17:03:23 -08:00
Yuan Zhu d2c51201ef Strings update 2nd round 2015-11-18 15:53:49 -08:00
Yuan Zhu 8a320f0b72 Use seperate string for left and right hand. 2015-11-18 14:03:54 -08:00
Yuan Zhu 2988cb0fa6 Change circle to peg 2015-11-18 13:07:34 -08:00
Yuan Zhu 59788e53ec change the string of "PASSCODE_INVALID_ALERT_TITLE" 2015-11-18 10:52:31 -08:00
Yuan Zhu af823d1f63 Change WiFi to Wi-Fi 2015-11-17 18:09:59 -08:00
Yuan Zhu 75ac5d3366 Fix typo. 2015-11-17 17:50:56 -08:00
Yuan Zhu 932024c4af Loc en string fixes 2015-11-13 15:16:15 -08:00
Yuan Zhu 26cf7e4d64 add ORK_CLASS_AVAILABLE for ORKLoginStepViewController 2015-11-13 15:12:24 -08:00
Yuan Zhu fa2b18da42 1st round localization 2015-11-13 12:52:07 -08:00
Yuan Zhu 304d93a79a Add charts sections 2015-11-10 14:21:39 -08:00
Yuan Zhu a57a8d8370 Merge pull request #383 from rsanchezsaez/rsanchezsaez-navigationrules
Add Swift tuple initializer overlay to ORKPredicateStepNavigationRule
2015-11-09 10:31:44 -08:00
Yuan Zhu d44676d816 Merge pull request #559 from umerkhan-apple/localizationBug
ORKCatalog Localization Files
2015-11-05 11:10:08 -08:00
Yuan Zhu 18d50721cc Merge pull request #556 from rsanchezsaez/rsanchezsaez-ORKTestNamingConventions
ORKTest: improve some class and method names
2015-11-05 10:52:21 -08:00
Yuan Zhu 967518a576 Merge pull request #557 from umerkhan-apple/readme
Updating README for RK Forum.
2015-11-05 10:39:09 -08:00
Yuan Zhu ef8c1e1b3a Merge pull request #553 from YuanZhu-apple/master_location_question_enhancement
Switch `ORKLocationResult`'s answer from `ORKPlacemark` to `ORKLocation`
2015-11-05 10:38:57 -08:00
Yuan Zhu 6563ebdca4 Clean up NSLog 2015-11-05 10:38:34 -08:00
Yuan Zhu f85faecb49 Merge branch 'master' of github.com:ResearchKit/ResearchKit into master_location_question_enhancement 2015-11-05 10:28:08 -08:00
Umer Khan 0341e511ab Adding localization files for all other supported languages. No translations, only placeholder files in order to enable localization for RK Framework strings. 2015-11-04 17:07:53 -08:00
Umer Khan 8f9ab33897 Updating README for RK Forum. 2015-11-04 10:52:47 -08:00
Yuan Zhu 372fbaaaa4 Merge pull request #546 from huguesbr/master
Fix localization when using  ResearchKit as Pod (Localizable.strings > ResearchKit.strings)
2015-11-03 16:19:48 -08:00
Hugues Bernet-Rollande a3c28f666c re-add missing white space 2015-11-04 01:01:33 +01:00
Ricardo Sánchez-Sáez 4c34d1e8a3 ORKCatalog: improve naming conventions and documentation for VerificationViewController and LoginViewController subclass examples 2015-11-03 23:08:17 +00:00
Ricardo Sánchez-Sáez 50c0d4b3c0 ORKTest: improve code for Wait Task progress update 2015-11-03 22:24:35 +00:00
Hugues Bernet-Rollande 4b269b8c21 Updating docs to reflect new name of localized strings (ResearchKit.strings) 2015-11-03 09:30:19 +01:00
Hugues Bernet-Rollande 143b474aff Rename Localizable.strings file to ResearchKit.strings and use table name in localization, avoiding conflict when including ResearchKit as a pod (the Localizable.strings files conflict with project one) 2015-11-03 09:30:19 +01:00
Yuan Zhu ca11a8def0 Merge branch 'master' of github.com:ResearchKit/ResearchKit into master_location_question_enhancement
Conflicts:
	ResearchKit.xcodeproj/project.pbxproj
2015-11-02 17:42:22 -08:00
Yuan Zhu 09cb204a24 Add copyright line. 2015-11-02 11:01:21 -08:00
Ricardo Sánchez-Sáez 20204946bc ORKTest: change case in comments 2015-11-01 22:20:20 +00:00
Ricardo Sánchez-Sáez 74dc33a654 ORKTest: improve some class and method names 2015-11-01 22:18:17 +00:00
Yuan Zhu f738f18570 Update to PR to improve UI experience. 2015-10-30 12:43:31 -07:00
Nidhi Gupta 7af35c7c35 Replace old PAVSAT screen shoots to reflect PASAT 2015-10-29 11:00:46 -07:00
Yuan Zhu ca2f7848f8 Merge pull request #538 from umerkhan-apple/account
Onboarding - Account Module
2015-10-28 13:48:21 -07:00
Umer Khan 85097a5e20 PR updates. 2015-10-28 13:20:48 -07:00
Yuan Zhu 60af4ce1e5 Address PR feedback, remove location question from selection survey 2015-10-27 17:56:36 -07:00
Umer Khan 8c10abfd74 Removing cancel button customization for Registration step. 2015-10-27 15:13:24 -07:00
Umer Khan 0f97c0704a Update cancel button actions for Login and Registration step. 2015-10-27 14:56:36 -07:00
Nidhi Gupta a9ea108054 Incorporated edits for the new features. 2015-10-27 14:35:32 -07:00
Yuan Zhu ac0a9a25d6 Merge branch 'master' of github.com:ResearchKit/ResearchKit into master_location_question_enhancement 2015-10-27 13:07:38 -07:00
Yuan Zhu 4ca0197532 Switch ORKLocationResult's answer from ORKPlacemark to ORKLocation
Create location questions task in ORKTest
2015-10-27 13:07:24 -07:00
Yuan Zhu e021f815ca Merge pull request #551 from umerkhan-apple/imageCaptureBug
IOI # 517 - Image capture no permissions bug
2015-10-26 17:11:46 -07:00
Yuan Zhu 1492ab82c1 Merge pull request #550 from umerkhan-apple/eligFix
IOI # 549 - Eligibility Tint Color Fix
2015-10-26 17:11:40 -07:00
Umer Khan 61408fc5f6 Consolidated tint color change method. 2015-10-26 16:28:38 -07:00
Ricardo Sánchez-Sáez 0459818613 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	Testing/ORKTest/ORKTest.xcodeproj/project.pbxproj
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-10-26 22:43:35 +00:00
Umer Khan 99bdc3cbbc Merging upstream/master 2015-10-26 15:38:23 -07:00
Umer Khan c0b751d05a Fixed error handling bug for image capture step. 2015-10-26 15:29:33 -07:00
Nidhi Gupta d3ed706680 Merge branch 'stable1.2_documentation' of https://gitlab.sd.apple.com/y_zhu/GitHub-ResearchKit-Fork into stable1.2_documentation 2015-10-26 15:02:48 -07:00
Nidhi Gupta d5175083ef Incorporated edits for the rest of the classes. 2015-10-26 15:02:20 -07:00
Umer Khan 721572a533 Minor update. 2015-10-26 12:44:42 -07:00
Umer Khan 2494895cf9 Tint color toggle bug fix. 2015-10-26 12:23:15 -07:00
Yuan Zhu 160b7c5f71 Merge pull request #478 from QuintilesRK/LocationQuestion
Location Question Type
2015-10-23 16:50:57 -07:00
Brandon McQuilkin 1b5ea88e0f Fixed issue causing tests to fail. 2015-10-22 15:13:48 -04:00
Brandon McQuilkin dd42f4740e Accidentally removed required import on merge. 2015-10-22 12:21:05 -04:00
Brandon McQuilkin 1f26d5c5a1 Merge branch 'master' of https://github.com/ResearchKit/ResearchKit into LocationQuestion
Conflicts:
	ResearchKit/Common/ORKResult.m
2015-10-22 12:16:54 -04:00
Brandon McQuilkin 0a07f24bea Removed unused error message. 2015-10-22 08:27:44 -04:00
Brandon McQuilkin 224146f7fd Handle errors that can be returned by the CLLocationManager that do not apply to the functionality of the selection view by silently absorbing the error. 2015-10-22 08:27:06 -04:00
Brandon McQuilkin 5e7768483e Forgot to add localizable strings. 2015-10-22 08:24:36 -04:00
Yuan Zhu 66884c045b Merge pull request #513 from rsanchezsaez/rsanchezsaez-NavigableOrderedTask
Use results for backwards navigation in 'ORKNavigableOrderedTask'
2015-10-21 13:47:55 -07:00
Brandon McQuilkin e7ca832c3d Updated error handling. 2015-10-21 08:59:33 -04:00
Umer Khan af3285f5f0 Bug fix for confirm answer format. 2015-10-20 22:17:41 -07:00
Umer Khan 50cd9055ac PR updates and added example to ORKTest. 2015-10-20 19:48:53 -07:00
Umer Khan d0226f29f7 Merge remote-tracking branch 'upstream/master' into account 2015-10-20 18:37:00 -07:00
Umer Khan eceeab053d PR feedback changes. 2015-10-20 18:36:30 -07:00
Yuan Zhu de0019054a Merge pull request #533 from md0u80c9/ORKFormItem-optionalConvenienceInit
ORKFormItem optionalConvenienceInit
2015-10-20 10:47:44 -07:00
Brandon McQuilkin cbf9d7284f Removed location question from form example. 2015-10-20 08:40:52 -04:00
Brandon McQuilkin 00183879ce Removed if statement left over from debugging. 2015-10-20 08:39:04 -04:00
Brandon McQuilkin 58453f5df9 Pulled edge to edge presentation logic into init. 2015-10-20 08:37:50 -04:00
Umer Khan 9c65780911 Updated confirm text answer format validation logic. 2015-10-19 18:47:23 -07:00
Ricardo Sánchez-Sáez f7f8e12d9d ORKResult: add indentation for collection classes description 2015-10-20 02:41:30 +01:00
Ricardo Sánchez-Sáez ee494c5ed1 ORKResult: add 'numberOfPaddingSpacesForIndentationLevel' constant 2015-10-20 02:30:08 +01:00
Ricardo Sánchez-Sáez 12a2d556c9 ORKHelpers: simplify 'ORKPaddingWithNumberOfSpaces' function by using Foundation API 2015-10-20 02:27:44 +01:00
Yuan Zhu ce6d4fe3ac Fix links in survey page. 2015-10-19 18:19:22 -07:00
Umer Khan 05f2fe9db4 Minor update to DOB form item in ORKRegistrationStep. 2015-10-19 15:24:52 -07:00
Umer Khan 7e8175b8a2 Added more error checking and updated registration step to adjust given & family name for locale. 2015-10-19 14:49:09 -07:00
Umer Khan c3460d8aaa Refactored string constants for login step form items. 2015-10-19 14:09:23 -07:00
Umer Khan 886bca74bf PR review modifications. 2015-10-19 14:03:36 -07:00
Umer Khan 53bb638c69 Minor fix. 2015-10-19 11:07:25 -07:00
Umer Khan 3d40007df9 Minor documentation updates. 2015-10-19 10:57:48 -07:00
Brandon McQuilkin 5070517ba3 Removed unnecessary lines. 2015-10-19 13:17:00 -04:00
Brandon McQuilkin 5bca8eb66d Updated ORKLocationQuestionResult's copy method. 2015-10-19 08:25:05 -04:00
Brandon McQuilkin 4dff0189df Removed unnecessary hash method override. 2015-10-19 08:24:09 -04:00
Brandon McQuilkin 9e1e855b70 Fixed ORKLocationQuestionResult's answer format. 2015-10-19 08:21:20 -04:00
Brandon McQuilkin 4e7f24f1c2 Reverted indentation changes to ORKESerialization. 2015-10-19 08:20:11 -04:00
Brandon McQuilkin 3229df2a48 Updated the default location place holder string's key. 2015-10-19 08:18:41 -04:00
Ricardo Sánchez-Sáez 7bc407ee90 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules 2015-10-19 01:50:43 +01:00
Ricardo Sánchez-Sáez 96e94155d7 ORKTest: fix serialization tests 2015-10-19 01:49:15 +01:00
Ricardo Sánchez-Sáez b8b5648c71 ORKResult: improve indentantion of collection results' 'description' 2015-10-19 01:42:30 +01:00
Ricardo Sánchez-Sáez 0471bf61d4 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-NavigableOrderedTask
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-10-18 20:24:10 +01:00
Andrew Hill a0ca62ec23 Reordered the initialisers per YuanZhu's feedback. 2015-10-18 00:02:30 +01:00
Umer Khan aac14a3a1a Minor formatting fixes. 2015-10-16 18:38:53 -07:00
Umer Khan 696758bdc2 Added more validation checks. 2015-10-16 18:26:05 -07:00
Umer Khan 43b6585bfa Minor updates. 2015-10-16 16:38:34 -07:00
Umer Khan f47f9d824c Updates 2015-10-16 16:23:13 -07:00
Brandon McQuilkin 9b4152ec6e Aligned text field and map with the rest of the form question cells. 2015-10-16 15:23:39 -04:00
Brandon McQuilkin b58ae6139b Adjusted map size to ensure that the text field was visible on all devices.
Removed the code to scroll the text field into view as the scroll offset change was being overriden by the animation of the keyboard changing the table view offset.
2015-10-16 15:12:57 -04:00
Brandon McQuilkin 7ba97f4089 Removed unnecessary cast. 2015-10-16 14:33:55 -04:00
Brandon McQuilkin a2bfb9a15d Switched to using predefined vertical margin. 2015-10-16 14:33:06 -04:00
Umer Khan 17b7d7d4f9 Merge remote-tracking branch 'upstream/master' into account 2015-10-16 10:47:20 -07:00
Andrew Hill d9e2f54c41 Changes made per UmerKhan-apple's suggestions 2015-10-16 08:19:34 +01:00
Umer Khan 9347ef6573 Updated serialization. 2015-10-15 18:03:49 -07:00
Nidhi Gupta ed4a50dacc Few API edits. 2015-10-15 11:47:16 -07:00
Nidhi Gupta d8d3882a1c Update ORKScaleAnswerFormat Class Reference 2015-10-15 11:43:47 -07:00
Nidhi Gupta ec8308b8bd Code snippet for ORKNavigableOrderedTask, and Email answer format. 2015-10-15 11:28:43 -07:00
Brandon McQuilkin 9296fe90bc Moved map view initialization 2015-10-15 09:16:36 -04:00
Brandon McQuilkin df9170f9cf Removed extra method. 2015-10-15 09:06:58 -04:00
Brandon McQuilkin 0deb8ba55e Switched the focus of the form cell from the map view to the text field. 2015-10-15 09:05:49 -04:00
Brandon McQuilkin b24310adbc Removed unnecessary variable. 2015-10-15 08:57:13 -04:00
Brandon McQuilkin c138f6aa02 Marked constant span values as constants. 2015-10-15 08:56:28 -04:00
Brandon McQuilkin 49e541d1b7 Set the map region's coordinate directly. 2015-10-15 08:55:28 -04:00
Brandon McQuilkin f22676a8e7 Switched isEqual to ORKEqualObjects 2015-10-15 08:54:17 -04:00
Brandon McQuilkin d34749e1ef Copy answer before setting the answer property 2015-10-15 08:52:34 -04:00
Brandon McQuilkin 0e4251d511 Directly use string from ABCreateStringWithAddressDictionary 2015-10-15 08:50:07 -04:00
Brandon McQuilkin 06ff988941 Removed unnecessary casts. 2015-10-15 08:49:26 -04:00
Brandon McQuilkin 3b3c907d39 Removed extra class from ORKResult.h 2015-10-15 08:47:27 -04:00
Brandon McQuilkin b1515e0fc2 Removed unnecessary method. 2015-10-15 08:46:43 -04:00
Brandon McQuilkin f9924ddbc0 Removed debug log from tests. 2015-10-15 08:44:24 -04:00
Brandon McQuilkin bbde9865ee suggestedCellHeightForView now returns a height based off of the screen metric. 2015-10-15 08:35:39 -04:00
Nidhi Gupta cfa9e90d76 Corrected ORKOrderedTask description. 2015-10-15 00:13:12 -07:00
Andrew Hill 851bd4e2c5 Added ORKFormStep optional convenience initialiser.
Updated the optional form test to confirm all is working.
2015-10-15 04:13:05 +01:00
Yuan Zhu 9fbabf8f3b Merge pull request #528 from rsanchezsaez/rsanchezsaez-ChartsPerformanceTest
ORKTest: add 'Test Charts Performance' item
2015-10-14 18:04:34 -07:00
Yuan Zhu 536a22f733 Merge pull request #526 from YuanZhu-apple/master_should_able_to_contine_with_default_value_on_scale
Refractor scale answer format
2015-10-14 17:42:31 -07:00
Yuan Zhu e51c9b708a Should set currentNumberValue to nil if passed in currentTextChoiceValue is not match any of the text choices. 2015-10-14 17:41:10 -07:00
Yuan Zhu b45425ba72 Update API doc 2015-10-14 17:38:06 -07:00
Yuan Zhu 181651b365 Update string. 2015-10-14 17:35:00 -07:00
Yuan Zhu b8d2c6bf86 Address review feedback 2015-10-14 17:33:42 -07:00
Ricardo Sánchez-Sáez feb5f11e3e CharDataSources.swift: add PerformanceLineGraphChartDataSource 2015-10-15 00:54:10 +01:00
Yuan Zhu 8d4b73ae8f Style adjustment 2015-10-14 16:31:57 -07:00
Yuan Zhu 81e67dc6fa Use _textChoices instead of self.textChoices 2015-10-14 16:30:24 -07:00
Yuan Zhu e873af81d6 Style adjustment. 2015-10-14 16:24:19 -07:00
Yuan Zhu 59681fbab5 Other review feedback update. 2015-10-14 16:11:41 -07:00
Yuan Zhu a3a53b7c68 Make separate ORKTextScaleAnswerFormatProvider to carry the methods for ORKTextScaleAnswerFormat 2015-10-14 15:59:28 -07:00
Yuan Zhu a28e2596bd Change protocol method from defaultNumber to defaultAnswer to better work with ScaleSliderView. 2015-10-14 15:50:04 -07:00
Yuan Zhu f5e8b40f6d Style update 2015-10-14 15:36:10 -07:00
Umer Khan 55bc242896 Removed disabled confirm textfield feature. 2015-10-14 14:51:18 -07:00
Umer Khan d3dee01678 Refactored to view controller parameter rather than Class parameter. 2015-10-14 14:47:15 -07:00
Umer Khan a6445546fd Updated confirm text answer format. 2015-10-14 14:30:38 -07:00
Brandon McQuilkin 44a786d51d Switch returned error message to localizedFailureReason. 2015-10-14 15:19:21 -04:00
Brandon McQuilkin 5954a6b254 Moved size of map to screen metric. 2015-10-14 15:15:04 -04:00
Brandon McQuilkin 06eecb054c Updated serialization and unit tests of ORKPlacemark.
- Added ORKPlacemark to public header.
- Added NSSecureCoding, NSCopying, isEqual: to ORKPlacemark
- Finished replacing MKPlacemark to ORKPlacemark
- Updated ORKTestTests
2015-10-14 14:53:50 -04:00
Brandon McQuilkin c38da58f6b Added open source license. 2015-10-14 08:45:32 -04:00
Brandon McQuilkin 17c35e6765 Updated horizontal margins. 2015-10-14 08:44:34 -04:00
Umer Khan 1074eefbbe Added confirm text answer format and cell. 2015-10-13 20:16:47 -07:00
Nidhi Gupta 6c54eea404 API reference edits incorporated (part 1) 2015-10-13 15:05:56 -07:00
Ricardo Sánchez-Sáez daa267b8f0 ORKTest: add 'Test Charts Performance' item 2015-10-13 22:43:30 +01:00
Andrew Hill 7f66623c59 Merge branch 'ResearchKit/master' 2015-10-13 22:18:32 +01:00
Umer Khan 7854c619a3 Added LoginStep and refactored minor things. 2015-10-13 14:10:21 -07:00
Brandon McQuilkin deef811bc9 Moved where the initial coordinate region is set. 2015-10-13 10:38:05 -04:00
Brandon McQuilkin b9fff0e4c0 Removed extra text color change. 2015-10-13 10:23:05 -04:00
Brandon McQuilkin f35e84189c Removed extra answerDidChange call.
Fixed extra annotations bug.
2015-10-13 09:57:42 -04:00
Brandon McQuilkin 5ff0f9324a Updated error message. 2015-10-13 09:48:44 -04:00
Brandon McQuilkin 35d33709b2 Added support for ORKNullAnswerValue to the selection view. 2015-10-13 09:46:28 -04:00
Brandon McQuilkin 0d9c98dd56 Fixed the selection view's first responder being ignored. 2015-10-13 08:14:39 -04:00
Yuan Zhu 2ac5e30d85 Refractor scale answer format.
1. fix for #511 "Continue button is disabled on scale with default values"
2. refactor ORKScaleSliderView to work better with three scale related answer format.
2015-10-12 16:23:22 -07:00
Umer Khan d1e246bba4 Adding wait step to account creation task. 2015-10-12 14:46:00 -07:00
Yuan Zhu 0dc31e4593 Merge pull request #512 from md0u80c9/restorationData
RestorationData
2015-10-12 12:01:57 -07:00
Brandon McQuilkin 521dba3d4e Removed invalid location answer error creation as it is not possible for the user to create an invalid coordinate. 2015-10-12 10:40:52 -04:00
Brandon McQuilkin 07e05298a0 Removed the MKPlacemark string conversion and replaced with a subclass of MKPlacemark. 2015-10-12 10:33:05 -04:00
Brandon McQuilkin 9214c48d41 Added ORKPlacemark class. 2015-10-12 10:06:38 -04:00
Brandon McQuilkin ebdc7a218a Added MKPlacemark serialization tests. 2015-10-12 09:47:03 -04:00
Brandon McQuilkin 3d9cc15c0b Fixed issue where previously entered answer would be overridden with current location after coming back to the question. 2015-10-12 08:42:50 -04:00
Ricardo Sánchez-Sáez f45722366c ORKNavigableOrderedTask: add loop support information to headerdocs 2015-10-11 13:16:58 +01:00
Ricardo Sánchez-Sáez 10152cfb79 ORKNavigableOrderedTask: reverse backwards navigation iteration
This fixes the behavior correct when you have visited the same step more than once (otherwise you'd get the previous step on your first visit).

Also, stop iteration as soon as possible, and improve loop warning
2015-10-11 12:50:47 +01:00
Ricardo Sánchez-Sáez 038794df0d ORKTaskViewController: make _managedStepIdentifiers array again
This is the original behavior, it follows the pop/push model. All the backward navigation stack is preserved, but older results which are ovewritten if you revisit the same step on a loop. Thus, going over a loop will produce duplicate results for the steps that are seen more than once (all the duplicate step results will point to the same result instance: the one corresponding to the last time you visited the step).
2015-10-11 12:46:53 +01:00
Ricardo Sánchez-Sáez d74bfe956f ORKResult: improve results' description
Also, use description to print task results in 'ORKTest'.
2015-10-11 12:42:47 +01:00
Steve Cadwallader af9588fd93 Revert to property notation. 2015-10-10 16:13:47 -04:00
Steve Cadwallader 80ee2b8792 Mark three ORKLocationSelectionViewDelegate event callbacks as optional. 2015-10-10 16:12:10 -04:00
Steve Cadwallader 8dffe81ea7 Replace ORKNullAnswerValue test with more complete ORKIsAnswerEmpty. 2015-10-10 15:48:29 -04:00
Steve Cadwallader 95099e34de Initialize the subview earlier, and access the placeholder directly from the form. 2015-10-10 15:42:47 -04:00
Steve Cadwallader 9dc22ff97e Remove unimplemented applyAnswerFormat from ORKFormItemLocationCell. 2015-10-10 15:15:27 -04:00
Steve Cadwallader df7a5d2ae4 Remove blank line in import statements. 2015-10-10 15:11:14 -04:00
Steve Cadwallader 475d84de73 Implement copyWithZone for ORKLocationAnswerFormat 2015-10-10 15:10:30 -04:00
Steve Cadwallader cc6380af67 Utilize constants for JSON keys. 2015-10-10 14:29:42 -04:00
Ricardo Sánchez-Sáez ebf3a5474d Unit tests: test new navigable ordered task navigation model 2015-10-10 17:04:21 +01:00
Ricardo Sánchez-Sáez f8a94a0f66 ORKTest: update unit tests 2015-10-10 16:47:48 +01:00
Ricardo Sánchez-Sáez 1afb67bf9e Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-NavigableOrderedTask
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-10-10 16:17:02 +01:00
Ricardo Sánchez-Sáez 258afcb7df ORKTest: direclty call TaskFactory method 2015-10-10 16:07:05 +01:00
Ricardo Sánchez-Sáez 8a3882d85c Fix ResearchKit unit tests not running due to Swift code 2015-10-10 16:06:46 +01:00
Ricardo Sánchez-Sáez 2bd667bc6f ORKTest: rename Swift 'TestHelpers' to 'TaskFactory' 2015-10-10 15:39:11 +01:00
Ricardo Sánchez-Sáez 7a4715dd72 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-10-10 15:37:12 +01:00
Umer Khan 8f7047220f Merging master and resolving merge conflicts. 2015-10-09 14:58:04 -07:00
Yuan Zhu fda01e8dd0 Merge pull request #518 from YuanZhu-apple/master_fix_First_Last_Name_logic_in_consent
Fix Issue #516: Consent required name logic is invalid
2015-10-09 14:56:10 -07:00
Steve Cadwallader 8042df3127 Documentation tweak. 2015-10-09 17:40:50 -04:00
Steve Cadwallader 153726633f Rename conversion methods to be more explicit about JSON strings. 2015-10-09 17:40:10 -04:00
Nidhi Gupta 4040d962a0 Added rules for scale answer format. 2015-10-09 12:07:26 -07:00
Steve Cadwallader 861211fa3b Integrate MKPlacemark JSON serialization. 2015-10-09 10:28:03 -04:00
Steve Cadwallader a8f6be61f3 Copyright updates 2015-10-09 08:38:43 -04:00
Steve Cadwallader 7c01903108 Replace spaces with tabs, to follow convention. 2015-10-09 08:05:25 -04:00
Steve Cadwallader 848800bcd6 Reintroduce Wait Step, resolution of merge conflict. 2015-10-09 07:58:51 -04:00
Steve Cadwallader caa324ec79 Merge branch 'master' into LocationQuestion 2015-10-09 07:56:21 -04:00
Steve Cadwallader 27bf948f6d Merge remote-tracking branch 'ResearchKit/master' 2015-10-09 07:45:26 -04:00
Nidhi Gupta ed60c84a2d Added vertical slider answer format. 2015-10-08 20:01:49 -07:00
Nidhi Gupta e70d56142d Incorporated active task's feedback.
Added ORKNavigableOrderedTask.
2015-10-08 19:40:49 -07:00
Yuan Zhu a4c9286f29 Merge pull request #520 from umerkhan-apple/waitTask
Rearranging ORKTest and ORKCatalog for WaitTask.
2015-10-08 18:26:59 -07:00
Umer Khan 97c5ada28f Rearranging ORKTest and ORKCatalog for WaitTask to comply with alphabetic ordering. 2015-10-08 18:21:11 -07:00
Umer Khan fd0d4af750 Merge pull request #477 from QuintilesRK/WaitTask
Wait Task
2015-10-08 18:11:18 -07:00
Steve Cadwallader dc81d8af3a Remove identifier serialization from ORKPasscodeStep as well. 2015-10-08 21:05:05 -04:00
Steve Cadwallader deac6b5de0 Remove incorrect serialization of identifier for ORKWaitStep (defined in base class). 2015-10-08 21:04:25 -04:00
Steve Cadwallader 2c504f4b01 Merge remote-tracking branch 'ResearchKit/master' 2015-10-08 20:58:39 -04:00
Steve Cadwallader db4b19b229 Add ORKQuestionTypeLocation to section types. 2015-10-08 20:51:57 -04:00
Steve Cadwallader 129d2ac3df Add Apple to copyright headers 2015-10-08 20:37:46 -04:00
Steve Cadwallader 0790e52a5a Replace remaining reference to indicatorType with indicatorMask, resolving unit test issue. 2015-10-08 20:31:09 -04:00
Umer Khan 9784c1425a Merge pull request #476 from QuintilesRK/ValidatedText
Validated Text
2015-10-08 17:26:20 -07:00
Steve Cadwallader df13dca4d9 Update two copyright headers. 2015-10-08 20:20:39 -04:00
Steve Cadwallader acfce230b4 Re-implement the cached percent formatter. 2015-10-08 20:19:10 -04:00
Steve Cadwallader bfac86d706 Merge pull request #1 from umerkhan-apple/waitStep
Wait Step
2015-10-08 20:14:08 -04:00
Steve Cadwallader c2e2951d6f Cache the regular expression. 2015-10-08 19:52:39 -04:00
Steve Cadwallader 36a578549b Refactor common initialization code out into a commonInit method. 2015-10-08 19:34:35 -04:00
Yuan Zhu 165e107ddc Fix Issue #516: Consent required name logic is invalid
#516

Should update this code after we adding in #443 .
2015-10-08 15:43:44 -07:00
Yuan Zhu e32efc4ec2 Merge pull request #515 from YuanZhu-apple/master_fix_unit_test
Clear unexpected exceptions from unit tests.
2015-10-08 14:40:53 -07:00
Yuan Zhu 3479c35fb3 Code refactor 2015-10-08 13:32:07 -07:00
Umer Khan 74fbc9af77 Merge branch 'waitStep' of https://github.com/umerkhan-apple/ResearchKit into waitStep 2015-10-08 12:57:00 -07:00
Yuan Zhu ec91b7b139 Clear unexpected exceptions from unit tests.
- `HTMLForSignature:` would throw exception on a nil `signature.title`
2015-10-08 12:56:46 -07:00
Umer Khan d4403704ce Re-ordering wait task in ORKTest to stay consistent with alphabetic ordering. 2015-10-08 12:52:57 -07:00
Umer Khan 4919e0fc0c Refactoring WaitStep logic and formatting. 2015-10-08 12:48:33 -07:00
Andrew Hill 4c49283504 removed duplicate self.delegate allocation 2015-10-08 19:31:48 +01:00
Brandon McQuilkin 26a094e05f Merge branch 'master' of https://github.com/ResearchKit/ResearchKit into WaitTask
Conflicts:
	samples/ORKCatalog/ORKCatalog/Tasks/TaskListRow.swift
2015-10-08 14:23:27 -04:00
Brandon McQuilkin d6504c68ef Undo deletion of MKPlacemark category. 2015-10-08 14:15:08 -04:00
Brandon McQuilkin f90af1ce01 Added MapKit Framework to ORKTest project. 2015-10-08 14:10:21 -04:00
Steve Cadwallader ae6fcf4ce4 Re-insert ValidatedTextQuestion cases that were incorrectly merged out in 52d5fca 2015-10-08 14:07:33 -04:00
Brandon McQuilkin 8730a26be1 Updated initializer for ORKLocationSelectionView. 2015-10-08 11:57:00 -04:00
Brandon McQuilkin 20d6defb6f Added property to enable/disable automatically retrieving the user's current location. 2015-10-08 11:37:26 -04:00
Brandon McQuilkin cf917dc208 Added serialization tests for location step and result. 2015-10-08 11:12:13 -04:00
Brandon McQuilkin 47ad36d906 Added the location permission request string to ORKTest to enable automatic location retrieval. 2015-10-08 09:40:51 -04:00
Brandon McQuilkin e69228445a Updated ORKCatalog's info.plist with the new location permission request string. 2015-10-08 09:35:52 -04:00
Brandon McQuilkin 90619ac2af Removed unnecessary method that caused the wrong value to be set to the ORKLocationQuestionResult's locationAnswer property. 2015-10-08 09:34:00 -04:00
Brandon McQuilkin 43c4b892b2 Added new lines before and after imports. 2015-10-08 09:05:11 -04:00
Brandon McQuilkin 1c2028ce5d Updated legal headers in MKPlacemark category. 2015-10-08 09:03:06 -04:00
Brandon McQuilkin 29942a01d5 Added address field placeholder to localized strings. 2015-10-08 09:02:01 -04:00
Brandon McQuilkin c159d6db61 Updated cell expansion animation. 2015-10-08 09:00:51 -04:00
Brandon McQuilkin 7635528b2f Removed extra line from localized strings. 2015-10-08 08:56:39 -04:00
Brandon McQuilkin d5b6b0f87a Refactored ORKSurveyAnswerCellDelegate method name to be in line with the ORKFormItemCell. 2015-10-08 08:55:54 -04:00
Brandon McQuilkin 328b8421a3 Switched constants from #define to static const CGFloat 2015-10-08 08:52:35 -04:00
Brandon McQuilkin b4a2cbebd0 Removed prefixes from location selection view constants. 2015-10-08 08:51:27 -04:00
Brandon McQuilkin 9a749c5489 Added non null assumptions. 2015-10-08 08:49:06 -04:00
Brandon McQuilkin 09272a78df Removed second unused method. 2015-10-08 08:47:06 -04:00
Brandon McQuilkin 92ae7cf071 Removed unused method. 2015-10-08 08:46:36 -04:00
Brandon McQuilkin b5568e278b Renamed ORKFormItemLocationCell's constraint set up method. 2015-10-08 08:46:03 -04:00
Brandon McQuilkin 33864f1012 Updated error strings for invalid coordinates. 2015-10-08 08:44:28 -04:00
Brandon McQuilkin 2534e6b20e Fixed syntax error. 2015-10-08 08:21:44 -04:00
Andrew Hill 56b50e9296 Removed a wandering ')' seemed to have slipped the net. 2015-10-08 11:09:44 +01:00
Steve Cadwallader 8eb756b96c Merge conflicts 2015-10-07 22:07:17 -04:00
Steve Cadwallader 52d5fcabe7 Merge branch 'master' into ValidatedText 2015-10-07 22:05:11 -04:00
Steve Cadwallader bf07984430 Merge remote-tracking branch 'ResearchKit/master' 2015-10-07 21:56:53 -04:00
Steve Cadwallader 0554cbd6f1 Implement serialization, copying, and equality logic for regex and invalidMessage. Resolves unit test failures. 2015-10-07 21:55:47 -04:00
Ricardo Sánchez-Sáez b34d1ecd29 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules 2015-10-07 23:23:08 +01:00
Ricardo Sánchez-Sáez f3c7c53e21 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-NavigableOrderedTask 2015-10-07 23:14:38 +01:00
John Earl 59045b27a5 Revert changes from bad merge at c113deb 2015-10-07 14:59:59 -07:00
Umer Khan 14ea5cc282 Updated changes to ORKLoginStep. 2015-10-07 14:05:14 -07:00
Ricardo Sánchez-Sáez ec04a5c633 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-NavigableOrderedTask 2015-10-07 22:03:27 +01:00
Ricardo Sánchez-Sáez f1e4941f3f ORKNavigableOrderedStack: use task results for backwards navigation
This commits removes ORKNavigableOrderedTask's '_stepIdentifierStack' ivar (used for backwards navigation) and uses the managed task results instead. The managed task result will only show results for the steps that have been previously visited, so it can be used to simulate the backwards navigation stack.

The ORKTaskViewController's '_managedStepIdentifiers' ivar has been converted into an 'NSMutableOrderedSet'. When an already visited step is shown (either by going back, or by following a loop in a navigable ordered task), all the managed step identifiers which come later than the step being shown are removed.

This commit also updates the 'ORKTest' to remove the "Save For Later" task archiving (which is no longer needed) and updates the 'Ordered Loop Task' example to be more comprehensive by featuring a branched question.
2015-10-07 22:03:03 +01:00
Steve Cadwallader bb01f0bb4d Utilize string formatting for error messages. Update comments. Change location of ORKTest URL test to in-line beneath e-mail. 2015-10-07 16:53:50 -04:00
Andrew Hill 7ebc03c93f Ensure we set up the delegate. 2015-10-07 21:43:38 +01:00
Andrew Hill 413bc6682a Amended ORKTaskViewController initWithTask to take a nullable restorationData field.
Updated ORKTest to allow us to test this out.
tested with NavigableOrderedTask.
2015-10-07 21:22:26 +01:00
Andrew Hill 9ccf4fb743 Merge branch 'ResearchKit/master' 2015-10-07 21:12:31 +01:00
Andrew Hill 723075a61f Merge branch 'ResearchKit/master' into restorationData 2015-10-07 21:11:53 +01:00
Ricardo Sánchez-Sáez c659539a45 ORKResult: homogenize results 'description' strings
Also: add result description for 'ORKCollectionResult' and 'ORKQuestionResult'.
2015-10-07 20:29:46 +01:00
Ricardo Sánchez-Sáez 48661fe670 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-10-07 19:54:33 +01:00
Ricardo Sánchez-Sáez b9fadc1b87 ORKTest: add 'Navigable Loop Task'
The 'Navigable Loop Task' allows testing of optional 'ORKNavigableOrderedTask' looping (when you loop, all the navigation history after the targeted step is discareded).

Also:
- Improve style and conform to naming conventions in MainViewController.m.
2015-10-07 19:17:08 +01:00
Yuan Zhu 11dc10e66e Merge pull request #509 from YuanZhu-apple/master_fix_save_for_later
If a task in ORKTest has been cancelled and saved, the output directory should be kept.
2015-10-07 10:32:42 -07:00
Yuan Zhu 6911fe614f Update for feedback. 2015-10-07 10:26:10 -07:00
Brandon McQuilkin 452665de14 Merge ResearchKit/master into ResearchKit/LocationQuestion 2015-10-07 10:43:32 -04:00
Brandon McQuilkin 1f352c39d2 Updated ORKWaitStep serialization. 2015-10-07 09:23:34 -04:00
Brandon McQuilkin e42c92004a Fixed syntax error. 2015-10-07 09:18:57 -04:00
Brandon McQuilkin 17ac3f5177 Updated changed method name in ORKTest. 2015-10-07 09:09:53 -04:00
Brandon McQuilkin 400da43f42 Cached the percent formatter. 2015-10-07 09:07:23 -04:00
Brandon McQuilkin c0aed6d641 Merge branch 'master' of https://github.com/ResearchKit/ResearchKit into WaitTask
Conflicts:
	samples/ORKCatalog/ORKCatalog/Tasks/TaskListRow.swift
2015-10-07 09:05:22 -04:00
Brandon McQuilkin f7e9c672e2 Added serialization tests for the wait step. 2015-10-07 08:26:48 -04:00
Yuan Zhu 7f106898e2 Merge pull request #462 from rsanchezsaez/rsanchezsaez-changelog
Add CHANGELOG.md
2015-10-06 15:58:12 -07:00
Yuan Zhu d3da59a4f6 In ORKTest, if a task has been cancelled and saved, the output directory should be kept.
ORKURLFromBookmarkData() fails to return a valid URL, when the resolving directory is not exist.
2015-10-06 14:33:47 -07:00
Umer Khan 8a78e95ebb Added Login step and updated documentation. 2015-10-06 13:55:28 -07:00
Umer Khan c113deb1a3 Merge branch 'master' of https://github.com/ResearchKit/ResearchKit 2015-10-06 13:36:09 -07:00
Brandon McQuilkin 3097232bd5 Converted weakSelf to strongSelf in block. 2015-10-06 15:13:14 -04:00
Brandon McQuilkin 04a55343bc Cleaned up imports. 2015-10-06 15:07:06 -04:00
Brandon McQuilkin 485e6035e0 Updated percent string to use NSNumberFormatter 2015-10-06 14:59:29 -04:00
Brandon McQuilkin 785ea40fc4 Constraint handling updated.
Static constraints now set up in setUpConstraints
Changing constraints now set up in updateConstraints if needed.
2015-10-06 14:55:07 -04:00
Ricardo Sánchez-Sáez 69319a3c5e RELEASE-NOTES.md: fix typo 2015-10-06 20:47:39 +02:00
Brandon McQuilkin c10ab44036 Consolidated indicator mask view creation. 2015-10-06 14:47:01 -04:00
Brandon McQuilkin 3fdbad88b2 Updated framework headers. 2015-10-06 14:27:35 -04:00
Brandon McQuilkin 2287b99b86 Moved wait task creation code in ORKTest 2015-10-06 14:23:02 -04:00
Brandon McQuilkin 3d6a7fa481 Updated accessibility to read out the progress value. 2015-10-06 14:16:03 -04:00
Brandon McQuilkin 0759764889 Added hard line wraps. 2015-10-06 14:07:05 -04:00
Brandon McQuilkin e3ab9d75ef Removed unnecessary tint color management 2015-10-06 14:03:12 -04:00
Brandon McQuilkin f401dcf94d Moved the wait step classes into the common folder. 2015-10-06 13:57:01 -04:00
Brandon McQuilkin b941379779 Refactored the wait step into a normal step. 2015-10-06 13:54:16 -04:00
Steve Cadwallader f2d13d1305 Reordered Validated Text Question between Value Picker and Image Capture per @rsanchezsaez feedback. 2015-10-06 11:59:33 -04:00
Brandon McQuilkin 96e5f26f7d Updated the result to return a placemark 2015-10-06 11:17:36 -04:00
Steve Cadwallader cecef562a9 Update localizedInvalidValueStringWithAnswerString to check both string length and regex validity when building a string. 2015-10-06 10:44:27 -04:00
Steve Cadwallader 7d2d04239f Remove emailAddress from ORKTextAnswerFormat. 2015-10-06 10:28:44 -04:00
Steve Cadwallader 2b649f9e12 Split out method for isTextRegexValidWithString. Update initializers to match recent argument changes. 2015-10-06 10:22:30 -04:00
Steve Cadwallader a9478c3cb0 Remove assignment to local variables per review feedback. 2015-10-06 09:23:11 -04:00
Steve Cadwallader 9b64b9c0f0 Change the argument name for textAnswerFormatWithValidationExpression. Reorder properties to be grouped together. Correct outdated documentation. 2015-10-06 09:18:51 -04:00
Ricardo Sánchez-Sáez ac0f3c542c RELEASE-NOTES.md: take care of internal review feedback
Also:
- Encode '(' and ')' symbols in URL (they interferred with markdown syntax).
- Use Title Capitalization for all section titles.
- Mention "General stability and performance improvements" on each release introducion instead of as a separate section.
2015-10-06 14:36:53 +02:00
Umer Khan 2e356cac03 Added confirm passcode field. 2015-10-05 16:55:51 -07:00
Yuan Zhu 91d4fa7890 Merge pull request #498 from ResearchKit/localizationFix
IOI # 495 - Localization fallback language
2015-10-05 13:37:42 -07:00
Yuan Zhu 18504e9ffe Merge pull request #493 from umerkhan-apple/touchID
Passcode updates
2015-10-05 13:21:46 -07:00
Umer Khan d80ca89094 PR update. 2015-10-05 13:11:32 -07:00
Umer Khan 706900ff07 Updated ORKVerificationStepView controls and constraints. 2015-10-05 13:03:17 -07:00
Brandon McQuilkin 20cfa9f588 Fixed layout constraint errors
Note: The height of the cell separator needs to be accounted for, it is
subtracted from the cell height returned/calculated by the UITableView.
2015-10-05 14:49:08 -04:00
Steve Cadwallader 76aef1a069 Naming tweak from setupConstraints to setUpConstraints for consistency. 2015-10-05 14:18:11 -04:00
Steve Cadwallader 4afe6dcf77 Merge from master 2015-10-05 14:11:07 -04:00
Steve Cadwallader 4d82dcb8f3 Merge branch 'master' into WaitTask 2015-10-05 14:09:58 -04:00
Steve Cadwallader d2c381fefb Merge remote-tracking branch 'ResearchKit/master' 2015-10-05 13:51:34 -04:00
Brandon McQuilkin fbfeb233fa Clearing the text field now resets the map view to its initial state 2015-10-05 09:51:14 -04:00
Brandon McQuilkin 2a4b1b370a Automatically obtain user's location upon presenting the map view 2015-10-05 09:37:28 -04:00
Brandon McQuilkin 52ef002a67 Address now updated immediately after search 2015-10-05 09:34:05 -04:00
Brandon McQuilkin 65e2946cba Keyboard dismissed on search 2015-10-05 09:33:28 -04:00
Brandon McQuilkin 52fbba25b8 Fixed layout issues for the ORKQuestionStep 2015-10-05 09:27:21 -04:00
Brandon McQuilkin 73c59a40b9 Added location question result to the result table view. 2015-10-05 08:09:49 -04:00
Brandon McQuilkin 87c6feceaa Removed current location button 2015-10-05 08:09:15 -04:00
Brandon McQuilkin 4bfc412626 Sorted the location question alphabetically in the catalog 2015-10-02 22:49:27 -04:00
Brandon McQuilkin 8621b38a89 Added array contents to constraints array 2015-10-02 22:33:29 -04:00
Brandon McQuilkin 8517354463 Fixed missing metric values. 2015-10-02 22:29:12 -04:00
Brandon McQuilkin 250d016306 Switch true/false to YES/NO 2015-10-02 22:28:13 -04:00
Steve Cadwallader a2a73b1661 Merge latest ResearchKit/master 2015-10-02 16:57:35 -04:00
Nidhi Gupta 46e61011a2 Active tasks revised. 2015-10-02 13:26:34 -07:00
Steve Cadwallader 13ab769dd8 Add suportsSecureCoding to ORKWaitStep, addressing unit test issue. 2015-10-02 16:10:40 -04:00
Steve Cadwallader 30f3900307 Copyright statement updates 2015-10-02 15:52:42 -04:00
Brandon McQuilkin f85a4c0c06 Moved coordinate translator into a helper method. 2015-10-02 15:51:15 -04:00
Steve Cadwallader 32fc46f896 Remove ORKProgressIndicatorMaskNone option, and add additional documentation. 2015-10-02 15:50:34 -04:00
Umer Khan f15940f83e Modified task view controller and ORKStep to allow for custom class variable. 2015-10-02 11:38:03 -07:00
Steve Cadwallader 310080fc8e Switched ORKEmailAnswerFormat to utilize ORKTextAnswerFormat with EmailValidationRegex. Removed isEmailAddressValidWithString. Disabled spell checking and auto correction. 2015-10-02 14:31:33 -04:00
Pavel Kanzelsberger b41e0be80f More refactoring, weakSelf / strongSelf and others... 2015-10-02 09:26:49 +02:00
Pavel Kanzelsberger c7d1d99b32 Switched from UIActivityIndicator to ORKProgressView 2015-10-02 08:55:07 +02:00
Umer Khan 684dd82c15 Added constraints. 2015-10-01 20:56:00 -07:00
Umer Khan c0ff5bc6e0 Minor update. 2015-10-01 18:14:20 -07:00
Umer Khan d2381657fa Adding ORKVerificationStepView foundation. 2015-10-01 18:09:27 -07:00
Umer Khan 3463f1a16f Added ORKVerificationStepViewController foundation. 2015-10-01 17:26:31 -07:00
Umer Khan 9878b34c2a Added Verification Step. 2015-10-01 17:08:30 -07:00
Umer Khan 81bc7221d1 Nit fix. 2015-10-01 16:45:40 -07:00
Umer Khan a5bb7b5506 PR updates. 2015-10-01 16:38:37 -07:00
Nidhi Gupta 921b280a3b Added all the new task in Active task module. 2015-10-01 16:04:51 -07:00
Yuan Zhu d313ab3a45 Merge pull request #497 from oliverschaefer/issue471
IOI 471
2015-10-01 15:32:59 -07:00
Umer Khan 73657854d4 Adding localization fallback to be U.S. English. 2015-10-01 15:18:05 -07:00
Umer Khan 7dc91f531d Quick fix. 2015-10-01 14:44:04 -07:00
Oliver Sch√§fer 294ec34d47 IOI 471 2015-10-01 23:38:01 +02:00
Umer Khan bcfb0b4dbb Minor keyboard fix. 2015-10-01 13:45:12 -07:00
Umer Khan 82c325d6c7 Updating serialization files. 2015-10-01 10:42:26 -07:00
Yuan Zhu c7bd1f5c41 Merge pull request #490 from YuanZhu-apple/master_fix_section_title_misalignment
Fixed the section header misalignment in form page.
2015-09-30 22:42:39 -07:00
Yuan Zhu bdb6849ab5 Merge pull request #483 from YuanZhu-apple/master_improve_json_unit_test
Make the test for ORKESerialization to catch unregistered classes.
2015-09-30 22:41:45 -07:00
Yuan Zhu 6d1d22d9fa Fixed the section header misalignment in form page.
1. Created `ORKFormSectionHeaderView` to update it constraint when screen rotates.
2. Use `dequeueReusableHeaderFooterViewWithIdentifier:` to cache created header views.
3. Other code refactoring.
2015-09-30 17:56:52 -07:00
Umer Khan 393a2bf404 Updates to Registration Step. 2015-09-30 17:18:48 -07:00
Yuan Zhu f828fbd8c4 Merge pull request #488 from rsanchezsaez/rsanchezsaez-ORKTest
ORKTest: add 'Passcode' section and sort items alphabetically
2015-09-30 16:15:22 -07:00
Ricardo Sánchez-Sáez 27193727e9 ORKTest: add 'Passcode' section and sort items alphabetically 2015-10-01 00:10:10 +01:00
Yuan Zhu a7173cc746 Merge branch 'master' of github.com:ResearchKit/ResearchKit into master_improve_json_unit_test
Conflicts:
	Testing/ORKTest/ORKTest/ORKESerialization.m
2015-09-30 15:15:42 -07:00
Yuan Zhu b0977b55e0 Merge pull request #487 from umerkhan-apple/touchID
Passcode Module Update
2015-09-30 15:06:40 -07:00
Yuan Zhu 6d792cfd83 Merge pull request #486 from YuanZhu-apple/master_fix_audio_UI
Fix audio task layout problem
2015-09-30 14:57:54 -07:00
Umer Khan fb6b1ab2c5 PR updates. 2015-09-30 14:48:38 -07:00
Yuan Zhu ab729432b4 Merge pull request #456 from umerkhan-apple/screening
Screening Module ⎯ Eligibility Answer Format
2015-09-30 14:29:18 -07:00
Umer Khan 5b5e53bdc3 Minor update. 2015-09-30 14:28:25 -07:00
Umer Khan 2b6c69e01d Resolving merge conflicts. 2015-09-30 14:26:08 -07:00
Umer Khan fb1c5e9b9a Resolving merge conflicts 2015-09-30 14:11:59 -07:00
Umer Khan f4b4d2aee1 Minor fixes. 2015-09-30 14:08:06 -07:00
Umer Khan 96478c583d Error handling updates to Passcode. 2015-09-30 14:04:26 -07:00
Yuan Zhu a796e6cc1e Merge pull request #373 from shazino/9hpt-task
Hole Peg Test task
2015-09-30 14:03:51 -07:00
Umer Khan 8599553a79 Updates to passcode 2015-09-30 11:41:10 -07:00
Yuan Zhu 8197c147e1 Fix audio task layout problem. 2015-09-30 11:19:54 -07:00
Umer Khan 8bdb32fc7a Updates 2015-09-30 10:42:43 -07:00
Julien Thérier 16f9b1dbe1 Merge remote-tracking branch 'origin/9hpt-task' into 9hpt-task 2015-09-30 17:00:14 +02:00
Julien Thérier 9459e330d5 Merge branch 'master' of ResearchKit/ResearchKit 2015-09-30 16:42:27 +02:00
Julien Thérier 78be958aea Fix ORKTest issue. 2015-09-30 16:22:23 +02:00
Pavel Kanzelsberger 3c9291ed24 Refactored code as requested 2015-09-30 09:24:38 +02:00
Yuan Zhu 5454cf83e1 Merge branch 'master' of github.com:ResearchKit/ResearchKit into master_improve_json_unit_test
Conflicts:
	ResearchKit.xcodeproj/project.pbxproj
2015-09-29 23:48:54 -07:00
Yuan Zhu b4e8a91474 Merge pull request #444 from umerkhan-apple/touchID
IOI # 88 - Passcode w/TouchID
2015-09-29 23:45:15 -07:00
Pavel Kanzelsberger 829f93523a Refactored code as requested 2015-09-30 08:22:59 +02:00
Umer Khan 98b0acaeb7 Disabling init for ORKPasscodeViewController. 2015-09-29 20:39:43 -07:00
Umer Khan 91a9acb9ef Modifying question text for eligibility task to the generic example question. 2015-09-29 20:31:50 -07:00
Umer Khan 71bdaab7be Updates to registration step. 2015-09-29 20:27:17 -07:00
Umer Khan 3e18a08690 Added registration step. 2015-09-29 18:07:18 -07:00
Yuan Zhu 63b8bea246 Enhance the test for ORKESerialization to catch unregistered classes.
Also add the missing class registrations.
2015-09-29 18:01:23 -07:00
Ricardo Sánchez-Sáez 7a1a1c6cdd Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-changelog 2015-09-30 01:25:19 +01:00
Ricardo Sánchez-Sáez 2b7f05fd96 RELEASE-NOTES.md: minor improvements 2015-09-30 01:25:08 +01:00
Umer Khan 234f40306a Merging master 2015-09-29 14:00:49 -07:00
Umer Khan 66218e4e28 Added serialization. 2015-09-29 13:56:38 -07:00
Umer Khan 130898cafd Added serialization. 2015-09-29 13:47:10 -07:00
Yuan Zhu 7db4bf50c8 Merge pull request #481 from matteocrippa/pdfsignaturenullable
signature.title exception on null
2015-09-29 13:01:45 -07:00
Pavel Kanzelsberger feb26fa506 Refactored code as requested 2015-09-29 18:15:53 +02:00
Umer Khan c317b30e82 Minor documentation update. 2015-09-28 14:41:46 -07:00
Umer Khan af6b027b7c Added Passcode Task into ORKCatalog and minor fixes. 2015-09-28 14:25:21 -07:00
Matteo Crippa 3c715cc211 fixed Signature capitalized 2015-09-28 23:09:32 +02:00
Matteo Crippa c7bddcf4d5 signature.title exception on null 2015-09-27 15:02:06 +02:00
Julien Therier ad9eefb19a Remove spoken instruction. 2015-09-25 21:01:48 +02:00
Julien Thérier 537e67af78 Fix ORKTest issue. 2015-09-25 11:11:14 +02:00
Julien Thérier 1c16398bc7 Change ORKSide to ORKBodySagittal 2015-09-25 10:09:14 +02:00
Umer Khan ca292c1987 Nits 2015-09-24 18:26:15 -07:00
Umer Khan 7a9009759e Minor fix. 2015-09-24 18:22:09 -07:00
Umer Khan 2040bbd095 Updated documentation in answer format and adde eligibility task example in ORKCatalog. 2015-09-24 18:18:53 -07:00
Umer Khan 111ac5627a Minor refactoring fix. 2015-09-24 15:45:29 -07:00
Umer Khan 57f911a4bb Refactoring ORKEligibilityAnswerFormat after PR discussion. 2015-09-24 15:42:50 -07:00
Eric Rolf 17776d04a4 Merge branch 'master' into LocationQuestion
* master: (114 commits)
  ResearchKit Project: add explicit 'ORK_LOG_LEVEL_WARNING=1'
  ORKImageSelectionView: resolve merge conflict
  ORKTest: fix column width not being updated after rotation
  ORKImageCaptureStepViewController: restore 'queue_' method prefix
  ORKTappingContentView: slight constraint refactor
  ORKSkin: hide 'ORKGetMetricForScreenType()' function; use 'ORKGetMetricForWindow()' instead
  Misc: remove extra newlines before 'else'
  Misc: remove additional space after '!' unary operator
  Misc: homegenize whitespace between consecutive closing and opening brackets
  ORKTaskViewController: whitespace
  Misc: homogenize for the more common 'cannot' instead of 'can not' in exception messages
  Misc: whitespace between '==' operator
  Misc: some additional constraint homogeneization of recently merged active tasks
  Misc: remove needless empty class extensions
  Misc: use 'has' instead of 'have' when refering to singular noun
  ORKFormItemCell: use VerticalMargin and HorizontalMargin const names
  Misc: remove space between '!' unary operator and operand
  Misc: use property syntax for accessing 'font', 'ascender', 'descender', and 'window'
  Misc: use property syntax for 'allValues' and 'allKeys'
  ORKDataLogger: use previous configuration file key for backwards compatibility
  ...
2015-09-24 07:19:45 -04:00
Eric Rolf 66b7806bce Merge branch 'master' into ValidatedText
* master: (114 commits)
  ResearchKit Project: add explicit 'ORK_LOG_LEVEL_WARNING=1'
  ORKImageSelectionView: resolve merge conflict
  ORKTest: fix column width not being updated after rotation
  ORKImageCaptureStepViewController: restore 'queue_' method prefix
  ORKTappingContentView: slight constraint refactor
  ORKSkin: hide 'ORKGetMetricForScreenType()' function; use 'ORKGetMetricForWindow()' instead
  Misc: remove extra newlines before 'else'
  Misc: remove additional space after '!' unary operator
  Misc: homegenize whitespace between consecutive closing and opening brackets
  ORKTaskViewController: whitespace
  Misc: homogenize for the more common 'cannot' instead of 'can not' in exception messages
  Misc: whitespace between '==' operator
  Misc: some additional constraint homogeneization of recently merged active tasks
  Misc: remove needless empty class extensions
  Misc: use 'has' instead of 'have' when refering to singular noun
  ORKFormItemCell: use VerticalMargin and HorizontalMargin const names
  Misc: remove space between '!' unary operator and operand
  Misc: use property syntax for accessing 'font', 'ascender', 'descender', and 'window'
  Misc: use property syntax for 'allValues' and 'allKeys'
  ORKDataLogger: use previous configuration file key for backwards compatibility
  ...

Conflicts:
	ResearchKit/Common/ORKAnswerFormat.m
2015-09-24 07:18:44 -04:00
Eric Rolf c79b228fba Merge branch 'master' into WaitTask
* master: (114 commits)
  ResearchKit Project: add explicit 'ORK_LOG_LEVEL_WARNING=1'
  ORKImageSelectionView: resolve merge conflict
  ORKTest: fix column width not being updated after rotation
  ORKImageCaptureStepViewController: restore 'queue_' method prefix
  ORKTappingContentView: slight constraint refactor
  ORKSkin: hide 'ORKGetMetricForScreenType()' function; use 'ORKGetMetricForWindow()' instead
  Misc: remove extra newlines before 'else'
  Misc: remove additional space after '!' unary operator
  Misc: homegenize whitespace between consecutive closing and opening brackets
  ORKTaskViewController: whitespace
  Misc: homogenize for the more common 'cannot' instead of 'can not' in exception messages
  Misc: whitespace between '==' operator
  Misc: some additional constraint homogeneization of recently merged active tasks
  Misc: remove needless empty class extensions
  Misc: use 'has' instead of 'have' when refering to singular noun
  ORKFormItemCell: use VerticalMargin and HorizontalMargin const names
  Misc: remove space between '!' unary operator and operand
  Misc: use property syntax for accessing 'font', 'ascender', 'descender', and 'window'
  Misc: use property syntax for 'allValues' and 'allKeys'
  ORKDataLogger: use previous configuration file key for backwards compatibility
  ...
2015-09-24 07:12:18 -04:00
Julien Thérier 0398fb3767 Add margins using ORKStandardHorizontalMarginForView. 2015-09-24 12:19:41 +02:00
Julien Thérier f168e02e9e Merge master and fix conflicts. 2015-09-24 11:44:43 +02:00
Julien Thérier 5d1ed481e3 Add margin for pegs. 2015-09-24 10:17:22 +02:00
Umer Khan 7cd75c4d40 PR updates. 2015-09-23 18:01:33 -07:00
Umer Khan aa58b643a0 Merge remote-tracking branch 'upstream/master' into screening 2015-09-23 16:53:20 -07:00
Umer Khan 3b0ce6478b PR changes. 2015-09-23 16:53:04 -07:00
Yuan Zhu c545aa8cbb Merge pull request #449 from rsanchezsaez/rsanchezsaez-logging
Revamp logging system
2015-09-23 16:37:24 -07:00
Ricardo Sánchez-Sáez 74ff026b92 ResearchKit Project: add explicit 'ORK_LOG_LEVEL_WARNING=1'
Adds explicit warning log level to 'Debug' and 'Release' 'Preprocessor Macros' setting in Xcode's Build Settings.
2015-09-24 00:07:40 +01:00
Umer Khan 257ee610b7 Added authenticationPasscodeType property for factory view controller support. 2015-09-23 15:29:06 -07:00
Ricardo Sánchez-Sáez 79b9351433 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules 2015-09-23 21:38:23 +01:00
Ricardo Sánchez-Sáez 359f8f3387 ORKImageSelectionView: resolve merge conflict 2015-09-23 21:37:50 +01:00
Ricardo Sánchez-Sáez 1f7c856fdb Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-logging
# Conflicts:
#	ResearchKit/ActiveTasks/ORKHealthQuantityTypeRecorder.m
#	ResearchKit/ActiveTasks/ORKTowerOfHanoiStep.m
#	ResearchKit/Common/ORKImageSelectionView.m
#	ResearchKit/Common/ORKTaskViewController.m
#	ResearchKit/Consent/ORKEAGLMoviePlayerView.m
2015-09-23 21:37:24 +01:00
Yuan Zhu 58a5a2c3b2 Merge pull request #474 from rsanchezsaez/rsanchezsaez-ORKTest
ORKTest: fix column width not being updated after rotation
2015-09-23 12:50:26 -07:00
Yuan Zhu 54f064247e Merge pull request #343 from rsanchezsaez/rsanchezsaez-constraints
Constraint code homogenization
2015-09-23 12:50:17 -07:00
Ricardo Sánchez-Sáez 3f35a49f50 ORKTest: fix column width not being updated after rotation
Also: make scroll view to use 3 columns for view widths equal or greater than the iPhone 6 in landscape (667 points).
2015-09-23 20:24:12 +01:00
Eric Rolf c16c929054 Updated Attributions. 2015-09-23 10:08:58 -04:00
Eric Rolf be6a922554 Updated Attributions. 2015-09-23 10:07:40 -04:00
Ricardo Sánchez-Sáez 3711ab342c Release Notes: split iPad and iPhone Landscape support into two items 2015-09-23 00:36:07 +01:00
Ricardo Sánchez-Sáez 908f7b0f5f ORKImageCaptureStepViewController: restore 'queue_' method prefix 2015-09-23 00:30:49 +01:00
Ricardo Sánchez-Sáez 1be6949c2d Release Notes: added contributions attribution 2015-09-23 00:21:17 +01:00
Umer Khan fc4e8a9915 PR updates. 2015-09-22 16:15:07 -07:00
Umer Khan 413e607258 PR changes. 2015-09-22 16:08:01 -07:00
Eric Rolf 7847c813a5 Added Location Question to ORKTest. 2015-09-22 18:39:23 -04:00
Eric Rolf 956549c320 Initial commit for location question.
Includes:
Location Question
Location Question Answer Format
Location Question Form Cell
Location Survey Answer
2015-09-22 18:16:08 -04:00
Eric Rolf 709e4b818c Merge branch 'master' into WaitTask
* master:
  Fixes #465
2015-09-22 16:44:23 -04:00
Eric Rolf 8a6f0a35bd Merge branch 'master' into ValidatedText
* master:
  Fixes #465
2015-09-22 16:44:12 -04:00
Umer Khan b218db0f63 Merging master 2015-09-22 12:52:33 -07:00
Umer Khan 8fe483a5e0 Merging master 2015-09-22 12:44:31 -07:00
Umer Khan 3a555592ff PR changes. 2015-09-22 12:38:13 -07:00
Ricardo Sánchez-Sáez 4fb39abac9 Release Notes: indent Result Predicates-related paragraph 2015-09-22 19:50:50 +01:00
Ricardo Sánchez-Sáez fbaf85ae9b Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-changelog 2015-09-22 19:48:54 +01:00
Yuan Zhu 11a0427883 Merge pull request #470 from shazino/fix-#465
Increase tapping timestamp precision
2015-09-22 10:55:16 -07:00
Julien Thérier d23e188d64 Fixes #465 2015-09-22 09:39:55 +02:00
Eric Rolf d70ee216c8 Added Validated text to ORKTest App, updated to support validators. 2015-09-21 21:14:26 -04:00
Eric Rolf 0cd42556f5 Initial Validated Text Commit 2015-09-21 21:07:52 -04:00
Eric Rolf 3daec83a7f ORKTest App updated with WaitTask. 2015-09-21 20:41:21 -04:00
Ricardo Sánchez-Sáez ed44fd84d9 ORKTappingContentView: slight constraint refactor 2015-09-22 01:28:30 +01:00
Eric Rolf be9d2e3486 Wait Task Initial Commit 2015-09-21 20:21:01 -04:00
Ricardo Sánchez-Sáez dc78de8fdd ORKSkin: hide 'ORKGetMetricForScreenType()' function; use 'ORKGetMetricForWindow()' instead
This is simpler to understand and easier to maintain. It handles all 'nil' window cases in one place.
2015-09-22 01:14:07 +01:00
Ricardo Sánchez-Sáez 21f1dbb5af Misc: remove extra newlines before 'else' 2015-09-22 00:55:14 +01:00
Ricardo Sánchez-Sáez 7bc31391fa Misc: remove additional space after '!' unary operator 2015-09-22 00:53:22 +01:00
Ricardo Sánchez-Sáez e932d118b9 Misc: homegenize whitespace between consecutive closing and opening brackets 2015-09-22 00:52:36 +01:00
Ricardo Sánchez-Sáez 874386987a ORKTaskViewController: whitespace 2015-09-22 00:49:00 +01:00
Ricardo Sánchez-Sáez 2b27a9d038 Misc: homogenize for the more common 'cannot' instead of 'can not' in exception messages 2015-09-22 00:47:17 +01:00
Ricardo Sánchez-Sáez 293e0ed23c Misc: whitespace between '==' operator 2015-09-22 00:43:04 +01:00
Ricardo Sánchez-Sáez c322e0455d Misc: some additional constraint homogeneization of recently merged active tasks 2015-09-22 00:41:04 +01:00
Ricardo Sánchez-Sáez 9960b4376f Misc: remove needless empty class extensions 2015-09-22 00:29:24 +01:00
Ricardo Sánchez-Sáez 1d3adbba45 Misc: use 'has' instead of 'have' when refering to singular noun 2015-09-22 00:26:46 +01:00
Ricardo Sánchez-Sáez 07d1aba216 ORKFormItemCell: use VerticalMargin and HorizontalMargin const names 2015-09-22 00:09:16 +01:00
Ricardo Sánchez-Sáez b69d40a86b Misc: remove space between '!' unary operator and operand 2015-09-21 23:49:18 +01:00
Ricardo Sánchez-Sáez 633f9eaaef Misc: use property syntax for accessing 'font', 'ascender', 'descender', and 'window' 2015-09-21 23:44:50 +01:00
Ricardo Sánchez-Sáez 2edf7bc481 Misc: use property syntax for 'allValues' and 'allKeys' 2015-09-20 17:30:22 +01:00
Ricardo Sánchez-Sáez 92620b782b ORKDataLogger: use previous configuration file key for backwards compatibility 2015-09-20 17:09:01 +01:00
Ricardo Sánchez-Sáez 06ca255bb1 Misc: remove 'k' prefix from constants (as per the Coding Style Guide) 2015-09-20 16:51:29 +01:00
Ricardo Sánchez-Sáez 5baa3a423a Misc: more binary operator whitespace fixes 2015-09-20 16:37:39 +01:00
Ricardo Sánchez-Sáez b56e622ea0 Misc: use property format for accessing screen 'scale' 2015-09-20 16:34:33 +01:00
Ricardo Sánchez-Sáez 9fad01dd0c Misc: homogenize whitespace around binary operators
Also remove the 'k' prefix on some constants.
2015-09-20 16:32:34 +01:00
Ricardo Sánchez-Sáez f2c751a71f Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints 2015-09-20 16:08:43 +01:00
Ricardo Sánchez-Sáez 06d9244c80 RELEASE-NOTES.md: add notes about 'scale answer format' and 'result predicate' improvements in v1.2
Also use the proper 'Scale Answer Format' name (instead of 'Slider Answer Format').
2015-09-20 15:35:28 +01:00
Ricardo Sánchez-Sáez 6004058c50 RELEASE-NOTES.md: add notes on required Xcode version 2015-09-20 15:13:18 +01:00
Ricardo Sánchez-Sáez cc1e1ae435 RELEASE-NOTES.md: fix indentation of task descriptions 2015-09-18 12:34:42 +01:00
Yuan Zhu be6d351bb3 Merge pull request #459 from YuanZhu-apple/master_fix_consent_animation
Fix consent animation.
2015-09-17 17:58:02 -07:00
Yuan Zhu eac89e0119 Fix typo and rearrange some restoreGLContext code 2015-09-17 17:56:12 -07:00
Ricardo Sánchez-Sáez e035236314 Add 'RELEASE-NOTES.md' 2015-09-18 00:56:10 +01:00
Ricardo Sánchez-Sáez ea0c6a1cf8 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints
# Conflicts:
#	ResearchKit/Consent/ORKConsentReviewController.m
2015-09-17 02:00:00 +01:00
Ricardo Sánchez-Sáez 48cc58f04c Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules 2015-09-17 01:46:03 +01:00
Ricardo SaÃÅnchez-SaÃÅez 6c97c550ed ORKEAGLMoviePlayerView: promote OpenGL failure messages from warning to error 2015-09-17 01:20:03 +01:00
Ricardo SaÃÅnchez-SaÃÅez 50b3f1d170 ORKTaskViewController, ORKStepViewController: replace 'NSLog' by 'ORK_Log_Warning' 2015-09-17 01:19:24 +01:00
Umer Khan 601b16a985 Refactored PasscodeTextField logic. 2015-09-16 14:27:09 -07:00
Julien Thérier ecb0fde9c5 Merge remote-tracking branch 'ResearchKit/master' 2015-09-16 17:40:17 +02:00
Yuan Zhu 81be7627eb Fix consent animaton.
Root cause: old playerView's dealloc happens on the new EAGLContext(wrong) of new playerView.

Save/Restore EAGLContext in each of the methods which do GL drawing.
This make more than one GLContext lives together.
2015-09-15 18:18:56 -07:00
Umer Khan f94929daae Added optional error message property. 2015-09-15 11:03:43 -07:00
Ricardo Sánchez-Sáez 8d7ab7861c Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-logging 2015-09-15 15:03:05 +02:00
Yuan Zhu ce3f17d45f Release 1.2.1 with Fix blank consent html review page. 2015-09-14 15:53:06 -07:00
Yuan Zhu 1354181f84 Merge pull request #457 from YuanZhu-apple/master_fix_blank_consent_review
Fix `blank` consent html review page.
2015-09-14 15:41:17 -07:00
Ricardo Sánchez-Sáez 395d2727c6 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints 2015-09-14 23:49:40 +02:00
Yuan Zhu 7f67d9c4da Merge pull request #440 from rsanchezsaez/rsanchezsaez-master-charts
Charts: add 'graphChartView:drawsVerticalReferenceLineAtPointIndex:' method
2015-09-14 14:20:19 -07:00
Yuan Zhu 2c5b5cda7d Merge pull request #438 from rsanchezsaez/rsanchezsaez-master-ORKTest
ORKTest: add icon and launch xib
2015-09-14 14:19:48 -07:00
Yuan Zhu 4fd95efe57 Merge pull request #450 from rsanchezsaez/rsanchezsaez-documentation
ORKAnswerFormat: fix headerdoc warnings
2015-09-14 14:19:03 -07:00
Yuan Zhu fb223bb1bb Fix blank consent html review page. 2015-09-14 13:58:30 -07:00
Umer Khan 831f136cd1 Added ability to recover answer and changed label type for form item cell. 2015-09-14 13:27:05 -07:00
Umer Khan 6ad9ad52af Minor fix. 2015-09-13 14:47:25 -07:00
Umer Khan b28d5e6456 Minor fixes. 2015-09-13 14:45:15 -07:00
Umer Khan d7f9987ede Added eligibility answer format. 2015-09-13 14:19:14 -07:00
Ricardo Sánchez-Sáez 86aaeae857 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints
# Conflicts:
#	ResearchKit/ActiveTasks/ORKAudioContentView.m
#	ResearchKit/Common/ORKImageCaptureView.m
2015-09-11 00:45:38 +01:00
Ricardo Sánchez-Sáez 642bc3db80 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-09-11 00:36:07 +01:00
Ricardo Sánchez-Sáez af0ca497d5 ORKAnswerFormat: fix headerdoc wanings
Also: hard wrap documentation at line 100.
2015-09-10 23:47:31 +01:00
Yuan Zhu 75f62ee5f7 Merge pull request #448 from YuanZhu-apple/master_add_workspace
Add a single workspace that includes RK,  ORKTest, and ORKCatalog for convenience
2015-09-10 15:26:08 -07:00
Umer Khan bd63d1576b Minor fix. 2015-09-10 15:22:28 -07:00
Yuan Zhu a4c521203c Merge pull request #443 from rsanchezsaez/rsanchezsaez-OptionalFormItems
ORKFormItem: implement 'optional' property
2015-09-10 14:58:17 -07:00
Umer Khan b8aba5459e Refactored keychain wrapper and added unit tests. 2015-09-10 14:51:49 -07:00
Ricardo Sánchez-Sáez f0507b973f ORKHelpers: add my copyright info to the header 2015-09-10 22:44:34 +01:00
Ricardo Sánchez-Sáez 58a9366bf5 Programming Guide: rename logging section to Logging Errors and Warnings 2015-09-10 22:35:23 +01:00
Ricardo Sánchez-Sáez 5b298d17a7 ORKHelpers: fix 'ORK_LOG_LEVEL_NONE' not working 2015-09-10 22:12:37 +01:00
Ricardo Sánchez-Sáez bca3ceae78 Programming Guide: add 'Logging Level' section 2015-09-10 22:06:45 +01:00
Ricardo Sánchez-Sáez d8c0ecbd1d ORKHelpers: revamped logging system
Also:
- Changes some (mildly) serious error messages from the DEBUG to the WARNING level.
- Remove the line number from ORK logging as it's noisy (we already have the function).

---

There are now four logging levels controlled by 4 preprocessor macros and their corresponding logging macros:
- ORK_LOG_LEVEL_NONE
- ORK_LOG_LEVEL_DEBUG, ORK_Log_Debug()
- ORK_LOG_LEVEL_WARNING, ORK_Log_Warning()
- ORK_LOG_LEVEL_ERROR, ORK_Log_Error()

Setting the ORK_LOG_LEVEL_NONE macro to 1 completely silences all RK logs. Setting ORK_LOG_LEVEL_DEBUG, or one of the higher levels, to 1, enables logging at that level and at all the higher levels.

If you do not specify a log level, 'ORK_LOG_LEVEL_WARNING=1' is used by default.

You have to set this preprocessor macros to your ResearchKit subproject, not to your main project. You can do so in Xcode by adding any of them to the 'Preprocessor Macros' list on your ResearchKit target's Build Settings.

See this resources if you are using ResearchKit through CocoaPods and need to change the log level:
- http://www.mokacoding.com/blog/cocoapods-and-custom-build-configurations/
- http://stackoverflow.com/a/30038120/269753
2015-09-10 21:39:15 +01:00
Yuan Zhu 133b154023 Add a single workspace that includes RK, ORKTest, and ORKCatalog for convenience 2015-09-10 13:10:51 -07:00
Yuan Zhu 95baa8b943 Update README.md
Stable branch works with Xcode 7.0 compatible now.
2015-09-09 17:14:52 -07:00
Yuan Zhu 0e433640c4 Merge branch 'stable' 2015-09-09 17:12:21 -07:00
Ricardo Sánchez-Sáez 1ae771ee80 ORKFormStep: rename 'non-optional' to 'required' on headerdocs and ORKTest's visible strings
It's the recommended practice for expressing non-optionality according to RFC 2119 (https://www.ietf.org/rfc/rfc2119.txt).
2015-09-09 10:49:20 +01:00
Julien Thérier c5b14925bd Merge remote-tracking branch 'ResearchKit/master'
Syncing fork
2015-09-09 10:30:36 +02:00
Umer Khan fa40e30ee3 Updated documentation. 2015-09-08 18:37:13 -07:00
Umer Khan 8736dd5165 Merge remote-tracking branch 'upstream/master' into touchID 2015-09-08 17:54:40 -07:00
Ricardo Sánchez-Sáez 4917b34291 ORKFormItem: set 'optional' default value to 'YES'
Also adds headers to the 'Optional Form' example.
2015-09-09 01:51:36 +01:00
Umer Khan 29d3e0da89 Renamed ORKKeychainStore to ORKKeychainWrapper. 2015-09-08 17:49:11 -07:00
Umer Khan 9b68f5188f Enhancements to keychain store. 2015-09-08 17:31:59 -07:00
Ricardo Sánchez-Sáez ed3503370d ORKDiscreteGraphChartView: fix small typo 2015-09-09 01:20:49 +01:00
Ricardo Sánchez-Sáez 43480170aa ORKFormItem: implement 'optional' property
Also add 'ORKCatalog' example.
2015-09-08 23:52:11 +01:00
Umer Khan fdaf18198f Consolidated delegates, updated API, and minor fixes. 2015-09-08 13:57:36 -07:00
Ricardo Sánchez-Sáez aee5c48875 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-master-charts
# Conflicts:
#	ResearchKit/Charts/ORKGraphChartView.h
#	Testing/ORKTest/ORKTest/Charts/ChartDataSources.swift
#	samples/ORKCatalog/ORKCatalog/Charts/ChartDataSources.swift
2015-09-08 20:38:33 +01:00
Umer Khan 521715f7dd Added keychain for passcode storing. 2015-09-08 11:12:06 -07:00
Yuan Zhu 68572aefe2 Merge branch 'convergence' 2015-09-08 10:50:52 -07:00
Ricardo Sánchez-Sáez 731b65d65c ORKCatalog: update graphChartView(graphChartView:, titleForXAxisAtPointIndex:)' method to use new name 2015-09-08 10:00:10 +01:00
Yuan Zhu b584258946 Use ORKLocalizedStringFromNumber()
# Conflicts:
#	Testing/ORKTest/ORKTest/Charts/ChartDataSources.swift
2015-09-08 09:55:28 +01:00
Ricardo Sánchez-Sáez d46ab216f4 ORKGraphChartView: implement 'graphChartView:drawsVerticalReferenceLineAtPointIndex:' method 2015-09-08 01:55:55 +01:00
Ricardo Sánchez-Sáez b6bee7e9de ORKGraphChartView: fix accessibility crash when 'graphChartView:titleForXAxisAtPointIndex:' is not implemented
# Conflicts:
#	ResearchKit/Charts/ORKGraphChartView.h
2015-09-08 01:55:41 +01:00
Ricardo Sánchez-Sáez 7272291eb7 ORKTest: add new icon 2015-09-07 23:08:09 +01:00
Ricardo Sánchez-Sáez 57be36482c ORKTest: nicer LaunchScreen 2015-09-07 00:34:38 +01:00
Ricardo Sánchez-Sáez c7d180b3ad Misc: update '__nullable' annotations to '_Nullable' (Xcode 7 style)
Also remove unneeded nullability annotations from implementation files.
2015-09-07 00:05:42 +01:00
Ricardo Sánchez-Sáez ed6913e2ad ORKHeadlineLabel: access 'windows' using property syntax 2015-09-06 23:29:13 +01:00
Ricardo SaÃÅnchez-SaÃÅez 9f79e144ce ORKScaleAnswerFormat: small whitespace fix 2015-09-06 23:18:39 +01:00
Ricardo Sánchez-Sáez 185789dfb3 ORKScaleSliderView: homogenize text choice slider constraints
Also, related to text choice slider:
 - Move label-creating code to init.
 - Do not create needless views on init.
 - Other small improvements.
2015-09-06 23:08:50 +01:00
Ricardo Sánchez-Sáez 5445b67b41 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints
# Conflicts:
#	ResearchKit/Common/ORKScaleSlider.m
#	ResearchKit/Common/ORKScaleSliderView.m
2015-09-06 22:28:08 +01:00
Yuan Zhu 66286a80c9 Merge pull request #435 from YuanZhu-apple/master_add_text_init
Add another convenient constructor for ORKQuestionStep
2015-09-04 15:42:44 -07:00
Umer Khan d9addcf469 Removing custom keyboard. 2015-09-04 12:32:40 -07:00
Yuan Zhu 7ba00fb853 Remove extra . 2015-09-04 11:29:43 -07:00
Yuan Zhu e4e2626823 Add another convenient constructor for ORKQuestionStep
The `text` attribute is easy missed by developers.
2015-09-04 11:27:56 -07:00
Umer Khan 48178b01c2 Merged master and added accessibility support. 2015-09-04 10:57:35 -07:00
Yuan Zhu 8b847e4de0 Merge pull request #392 from umerkhan-apple/textSlider
IOI # 230 - Text scale slider
2015-09-04 10:54:37 -07:00
Ricardo Sánchez-Sáez 2a76ff2a2e Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints
# Conflicts:
#	ResearchKit/ActiveTasks/ORKTappingContentView.m
#	ResearchKit/ActiveTasks/ORKToneAudiometryContentView.m
#	ResearchKit/ActiveTasks/ORKTowerOfHanoiTowerView.m
#	ResearchKit/Common/ORKFormItemCell.m
#	ResearchKit/Common/ORKHelpers.m
#	ResearchKit/Common/ORKScaleSliderView.m
#	ResearchKit/Common/ORKSkin.h
#	ResearchKit/Common/ORKSkin.m
#	ResearchKit/Common/ORKVerticalContainerView.m
#	ResearchKit/Consent/ORKConsentReviewController.m
#	ResearchKit/Consent/ORKConsentSignatureController.m
#	ResearchKit/Consent/ORKSignatureView.m
#	Testing/ORKTest/ORKTest/MainViewController.m
2015-09-04 18:38:40 +01:00
Julien Thérier caa24b9ae6 Restore Tapping Content View. 2015-09-04 16:45:27 +02:00
Julien Thérier 0a3d938f8a Restore Tapping Content View. 2015-09-04 16:43:08 +02:00
Julien Thérier 1ea4960c29 Merge remote-tracking branch 'ResearchKit/master'
Sync with remote repo.
2015-09-04 15:36:40 +02:00
Julien Thérier 7013e954bc Merge remote-tracking branch 'origin/master' into 9hpt-task
Merge master to fix conflicts.
2015-09-04 15:29:07 +02:00
Julien Thérier ec8c36260c Improve legibility. 2015-09-04 15:17:34 +02:00
Julien Therier cfeb39ef5c Merge pull request #1 from rsanchezsaez/rsanchezsaez-holepegtask
Hole Peg Test Task images
2015-09-04 11:37:28 +02:00
Umer Khan b56bda5aaa Updating constraint merge conflict. 2015-09-03 23:53:30 -07:00
Umer Khan a9857da213 Minor formatting updates. 2015-09-03 23:44:56 -07:00
Umer Khan 3b3ec14acd Merge master 2015-09-03 23:35:26 -07:00
Umer Khan c499309897 Minor formatting updates. 2015-09-03 22:24:59 -07:00
Umer Khan b813690c67 Minor enhancements 2015-09-03 21:29:18 -07:00
Yuan Zhu 714f29e185 Merge pull request #432 from rsanchezsaez/rsanchezsaez-master-ORKTest
ORKTest: project files reorganization
2015-09-03 18:26:58 -07:00
Yuan Zhu d752d4d926 Merge pull request #420 from rsanchezsaez/master-Catalog
Reorganize 'ORKCatalog' into subsections
2015-09-03 18:15:50 -07:00
Umer Khan 050cea0c51 Refactored protocol method name. 2015-09-03 17:55:45 -07:00
Umer Khan 5a20aeab03 Added custom numeric pad keyboard. 2015-09-03 17:54:49 -07:00
Ricardo SaÃÅnchez-SaÃÅez 748d13e56e ORKCatalog: update 'readme.md' to add formatting and information about sections 2015-09-04 00:54:23 +01:00
Ricardo SaÃÅnchez-SaÃÅez e9f3bc919b ResultTableViewProviders: reorder code to match TaskListRow 2015-09-04 00:53:34 +01:00
Ricardo Sánchez-Sáez b17dda9697 ORKCatalog: reorganize project files so they are easier to browse 2015-09-04 00:32:56 +01:00
Ricardo Sánchez-Sáez 729ef4fa58 TaskListRow: reorder 'form task' in front of 'survey task' (alphabetically) 2015-09-04 00:22:57 +01:00
Ricardo Sánchez-Sáez e9cc5ea800 Merge branch 'master' of github.com:ResearchKit/ResearchKit into master-Catalog
# Conflicts:
#	samples/ORKCatalog/ORKCatalog/Tasks/TaskListRow.swift
2015-09-04 00:21:00 +01:00
Ricardo Sánchez-Sáez 090b976083 ResearchKit unit tests: remove needless framework directory
(It caused a warning when running them.)
2015-09-03 22:32:57 +01:00
Ricardo Sánchez-Sáez bd32b0ad24 ORKTest: remove needless framework directory
(It caused a warning when running unit tests.)
2015-09-03 22:32:30 +01:00
Ricardo Sánchez-Sáez d86edbc3f2 ORKTest: file structure reorganization so the project is easier to browse 2015-09-03 22:31:40 +01:00
Umer Khan a7c7aa7466 Adding UI foundation for custom numeric keyboard. 2015-09-03 13:40:43 -07:00
Yuan Zhu 72da218778 Add Accessibility section to CONTRIBUTING.md 2015-09-02 17:44:47 -07:00
Yuan Zhu 89571ef876 Merge pull request #426 from rsanchezsaez/rsanchezsaez-master-ORKTest
Use sectioned 'UICollectionView' for presenting buttons in 'ORKTest'
2015-09-02 17:27:07 -07:00
Yuan Zhu dc6bb27f57 Merge pull request #416 from rsanchezsaez/rsanchezsaez-FormPredicates
Result predicates: add support for form item results and nil results
2015-09-02 17:12:43 -07:00
Ricardo SaÃÅnchez-SaÃÅez 1c200251e8 ORKResultPredicate: update remaining headerdoc comments to reflect the new 'result selector' name 2015-09-03 01:11:50 +01:00
Ricardo SaÃÅnchez-SaÃÅez bdad58b3a7 ORKCatalog: add copyright info and fix leading space omission to the copyright headers 2015-09-03 00:14:53 +01:00
Ricardo SaÃÅnchez-SaÃÅez c79b0eebe9 ORKTest: move 'Mini Form' and 'Selection Survey' to the 'Question Steps' section
Also adds copyright information.
2015-09-03 00:11:43 +01:00
Ricardo SaÃÅnchez-SaÃÅez de05c7a632 ORKTest: use sectioned UICollectionView to organize test buttons 2015-09-02 23:21:54 +01:00
Ricardo SaÃÅnchez-SaÃÅez 0d07828edc ORKTest: fix storyboard warnings 2015-09-02 23:19:19 +01:00
Yuan Zhu 527609982a Merge branch 'convergence' 2015-09-02 14:35:36 -07:00
Umer Khan 01cb0e77be PR updates. 2015-09-02 11:13:50 -07:00
Umer Khan 1fdd29c308 Adding example in main view controller and minor updates. 2015-09-02 10:54:02 -07:00
Umer Khan b6e185284b Minor update to consent. 2015-09-01 17:44:05 -07:00
Umer Khan ade8879d54 Refacted factory methods of ORKPasscodeStepViewController into ORKPasscodeViewController 2015-09-01 17:35:08 -07:00
Ricardo SaÃÅnchez-SaÃÅez 015be2da3a ORKCatalog: replace 'Survey Questions' indentation by a new section 2015-09-02 00:56:20 +01:00
Ricardo SaÃÅnchez-SaÃÅez 2650360476 ORKCatalog: reorganize into alphabetically-sorted sections mirroring the project's readme 2015-09-02 00:02:53 +01:00
Umer Khan d42e7eca38 Adding protocol methods. 2015-09-01 14:42:00 -07:00
Ricardo SaÃÅnchez-SaÃÅez 074a00e2ae ORKResultPredicate: refactor 'ORKResultIdentifier' class by renaming it to 'ORKResultSelector'
Also:
- Improve documentation.
- Update ORKTest example and unit tests.
2015-09-01 22:34:21 +01:00
Yuan Zhu f7b8901fd2 Merge pull request #384 from rsanchezsaez/rsanchezsaez-codingstyleguide
Coding Style Guide: add 'Nullability Annotations' section
2015-09-01 14:04:24 -07:00
Ricardo SaÃÅnchez-SaÃÅez c01d530cde ORKCatalog: use new enum to String conversion for identifiers 2015-09-01 20:53:07 +01:00
Ricardo SaÃÅnchez-SaÃÅez ceec6adf1a ORKResultPredicate: greatly simplified API by introducing the 'ORKResultIdentifier' wrapper class
Also:
- Update tests.
- Update 'Navigable ordered task' example.
2015-09-01 00:56:22 +01:00
Ricardo SaÃÅnchez-SaÃÅez dffbaeee6b ORKResultPredicate: make ORKChoiceQuestionResult predicates to accept any kind of answer object (instead of just strings)
Also:
- Fixed problem in nil answer result predicate methods.
- Updated 'ORKTest' example.
- Updated test cases.
- Removed needless predicate convenience method test cases.
2015-08-31 21:45:54 +01:00
Ricardo SaÃÅnchez-SaÃÅez c45d2cb856 ORKResultPredicate: use '==' instead of 'like' for plain string comparisons
(We don't generally want to match wildcard characters.)
2015-08-31 20:38:41 +01:00
Umer Khan 7e5b5b45ec Minor updates for authentication flow. 2015-08-31 12:34:09 -07:00
Ricardo Sánchez-Sáez 739d22b5d3 ORKResultPredicate: small headerdoc improvement 2015-08-31 05:53:46 +01:00
Umer Khan 070f449c57 Added more passcode flows. 2015-08-30 20:58:25 -07:00
Ricardo SaÃÅnchez-SaÃÅez f76c960846 ORKResultPredicate: add 'predicateForNilQuestionResultWithTaskIdentifier:stepIdentifier:resultIdentifier:' method to match results with a nil answer (skipped steps or unanswered form questions) 2015-08-31 00:31:01 +01:00
Ricardo SaÃÅnchez-SaÃÅez a5640cb4b1 ORKResultPredicate: add optional 'stepIdentifier' argument to all method, to allow matching form item results.
Also: use new methods in newly added form predicate.

Result predicates without a supplied 'stepIdentifier' argument now only match the corresponding question step result, but not any form item result.
2015-08-31 00:03:41 +01:00
Ricardo SaÃÅnchez-SaÃÅez 222c017e0d ORKTaskTests: add some form result predicate tests 2015-08-30 21:14:51 +01:00
Ricardo SaÃÅnchez-SaÃÅez 90c9e1de94 ORKCatalog: fix form step using wrong identifier 2015-08-30 21:13:57 +01:00
Umer Khan e8bd259952 Merge remote-tracking branch 'upstream/master' into textSlider 2015-08-28 16:57:35 -07:00
Umer Khan 07736ac5f3 Fixed secureCoding initializer warning. 2015-08-28 16:54:55 -07:00
Umer Khan 21bb2884b5 Laying foundation for different types of passcode flows. 2015-08-28 16:47:47 -07:00
Umer Khan b323bd8980 Added Touch ID and other minor updates. 2015-08-28 16:07:41 -07:00
Umer Khan f5e2f54979 Removed step progress from navigation item title. 2015-08-28 12:55:01 -07:00
Umer Khan 39ef6a21f0 Overriding vertical class keyboard methods. 2015-08-28 12:17:23 -07:00
Umer Khan 215e4d6008 PR updates. 2015-08-27 21:23:09 -07:00
Umer Khan 674a131060 Added foundation for Passcode Step 2015-08-27 18:54:29 -07:00
Ricardo SaÃÅnchez-SaÃÅez 778e8571d2 ORKStepNavigationRule: make ObjC separate array initializers unavailable in Swift (in favor of the array of tuples initializer) 2015-08-26 21:52:01 +01:00
Ricardo Sánchez-Sáez e71356805c Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-navigationrules
# Conflicts:
#	ResearchKit/Common/ORKStepNavigationRule_Private.h
2015-08-26 21:40:52 +01:00
Ricardo Sánchez-Sáez 25612dc872 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints
# Conflicts:
#	ResearchKit/ActiveTasks/ORKFitnessContentView.m
#	ResearchKit/ActiveTasks/ORKTappingContentView.m
#	ResearchKit/ActiveTasks/ORKToneAudiometryContentView.m
#	ResearchKit/ActiveTasks/ORKTowerOfHanoiTowerView.m
#	ResearchKit/ActiveTasks/ORKWalkingTaskStepViewController.m
#	ResearchKit/Common/ORKContinueButton.m
#	ResearchKit/Common/ORKFormItemCell.m
#	ResearchKit/Common/ORKFormStepViewController.m
#	ResearchKit/Common/ORKHeadlineLabel.m
#	ResearchKit/Common/ORKImageCaptureStepViewController.m
#	ResearchKit/Common/ORKImageCaptureView.m
#	ResearchKit/Common/ORKInstructionStepView.m
#	ResearchKit/Common/ORKQuestionStepViewController.m
#	ResearchKit/Common/ORKResult.m
#	ResearchKit/Common/ORKSkin.m
#	ResearchKit/Common/ORKStepHeaderView.m
#	ResearchKit/Common/ORKSubheadlineLabel.m
#	ResearchKit/Common/ORKVerticalContainerView.m
#	ResearchKit/Common/ORKVerticalContainerView_Internal.h
#	ResearchKit/Consent/ORKConsentSignatureController.m
#	ResearchKit/Consent/ORKVisualConsentStepViewController.m
#	Testing/ORKTest/ORKTest/DynamicTask.m
2015-08-26 00:41:48 +01:00
Ricardo Sánchez-Sáez 8087810ac2 Coding Style Guide: improve 'Spaces in Declarations' subsection 2015-08-25 20:59:13 +01:00
Ricardo Sánchez-Sáez 3e99ad04c7 Coding Style Guide: add 'Lightweight Generics' section 2015-08-25 20:57:15 +01:00
Ricardo Sánchez-Sáez 0a1eb9c8a2 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-codingstyleguide 2015-08-25 20:23:43 +01:00
Umer Khan c11e70585a Minor updates. 2015-08-24 14:35:14 -07:00
Umer Khan 045abdd919 Adding type to textChoices and removing NSArray validation for textChoices. 2015-08-24 14:23:05 -07:00
Umer Khan f9ffd5e5f1 Minor changes. 2015-08-24 12:12:24 -07:00
Umer Khan 407a3da80e Added serialization and secure coding tests, with some minor fixes. 2015-08-24 11:57:54 -07:00
DanKeen c786ed06e1 Merge pull request #389 from rsanchezsaez/rsanchezsaez-readme
README.md improvements
2015-08-23 21:25:51 -07:00
Ricardo Sánchez-Sáez 2765fa5575 README.md: improvements
- Simplify introduction bullet list links.
- Use proper sentences surrounding links to in-depth documentation.
- Replace all instances of 'researchkit.github.io' by 'researchkit.org'.
2015-08-24 02:43:24 +01:00
Ricardo Sánchez-Sáez 835df17c5a README.md: small improvements 2015-08-24 02:23:28 +01:00
Ricardo Sánchez-Sáez 68e0c685db Hole Peg Test Task: improve introduction image 2015-08-24 02:11:55 +01:00
Ricardo Sánchez-Sáez 352fa46668 Hole Peg Test Task: add new instruction images
(Adds pinching fingers to the diagrams.)
2015-08-24 01:41:56 +01:00
Ricardo Sánchez-Sáez 87d8db3218 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-codingstyleguide 2015-08-24 00:15:09 +01:00
Ricardo Sánchez-Sáez 458f290956 Coding Style Guide: fix small grammar issue 2015-08-23 20:13:52 +01:00
Umer Khan f8c492aadd Merge remote-tracking branch 'upstream/master' into textSlider 2015-08-20 11:31:41 -07:00
Umer Khan 22bcc07047 Added ORKTextScaleAnswerFormat 2015-08-20 11:31:20 -07:00
Yuan Zhu ca7479609c Update README.md 2015-08-20 11:31:14 -07:00
Yuan Zhu d1adbf1f50 Merge branch 'convergence' 2015-08-20 11:13:06 -07:00
Ricardo Sánchez-Sáez 321b19adbe Coding Style Guide: add 'Nullability Annotations' section
Also:
- Make new separate section for Header File Example.
- Other very small fixes.
2015-08-19 23:42:28 +01:00
Ricardo Sánchez-Sáez d86fba5c56 ORKPredicateStepNavigationRule: add Swift initializer that takes an array of tuples (result predicate, destination step identifier) instead of two arrays
Add sample code to ORKTest: move Navigable Ordered Task creation to Swift and use the overlay Swift initializer for creating the predicate step navigation rules.
2015-08-19 21:58:24 +01:00
Yuan Zhu 9614d50af9 Merge pull request #377 from chb/feature/consent-signing
Consent section: avoid headers without body
2015-08-18 21:54:27 -07:00
Pascal Pfiffner 42f9f6f03d Merge branch 'master' into feature/consent-signing 2015-08-19 06:47:00 +02:00
Ricardo Sánchez-Sáez 43e4ae11b2 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints
# Conflicts:
#	ResearchKit/ActiveTasks/ORKWalkingTaskStepViewController.m
#	ResearchKit/Common/ORKScaleSliderView.m
#	Testing/ORKTest/ORKTest/CustomRecorder.m
2015-08-18 22:34:31 +01:00
Pascal Pfiffner 848c4dee8b Whitespace fix, thanks Xcode :P 2015-08-18 11:23:22 +02:00
Pascal Pfiffner a750b2718d Add omitFromDocument property to consent section 2015-08-18 11:21:21 +02:00
Pascal Pfiffner 071242f217 Fix whitespace 2015-08-18 00:25:00 +02:00
Pascal Pfiffner 52aed1a5b6 Use section title in “Learn More” screen 2015-08-17 16:58:33 +02:00
Pascal Pfiffner 2e736a7306 Consent section: avoid headers without body 2015-08-17 16:21:43 +02:00
Umer Khan 217f40e6ec Merge remote-tracking branch 'upstream/master' into textSlider 2015-08-14 15:10:24 -07:00
Julien Thérier 3353ff3dd0 Merge remote-tracking branch 'ResearchKit/master' 2015-08-13 16:30:32 +02:00
Julien Thérier 9e45652356 Fix conflict. 2015-08-13 15:52:19 +02:00
Julien Thérier d83e859d84 Fix conflicts. 2015-08-13 15:47:18 +02:00
Julien Thérier 4195dfe755 Fix conflicts. 2015-08-13 14:57:56 +02:00
Julien Thérier 55aa48b544 Merge remote-tracking branch 'ResearchKit/master' into 9hpt-task 2015-08-13 14:45:43 +02:00
Julien Thérier 5d3c846ed7 Add french localisation. 2015-08-13 11:01:11 +02:00
Julien Thérier 17c82175c2 Show time. 2015-08-13 10:50:59 +02:00
Julien Thérier ddeea33a02 Add tests. 2015-08-13 10:45:18 +02:00
Julien Thérier f4d8224164 Add icons. 2015-08-12 14:46:04 +02:00
Julien Thérier aa5e5b8394 Add distance result. 2015-08-11 10:36:28 +02:00
Julien Thérier f914263d0e Improve gesture recognition. 2015-08-11 09:30:21 +02:00
Julien Thérier d3634439af Add results and samples. 2015-08-10 18:18:00 +02:00
Julien Thérier b509908b2a Start at first move. 2015-08-07 14:07:29 +02:00
Julien Thérier 6490a7a8c3 Dominant / Non Dominant. 2015-08-07 13:23:16 +02:00
Julien Thérier 162764e508 Right / Left orientation. 2015-08-07 13:17:58 +02:00
Julien Thérier 5d99a54c58 Update text description when fail. 2015-08-07 12:40:54 +02:00
Julien Thérier 7252b83ef2 Rename to "Place" Step. 2015-08-07 11:40:49 +02:00
Julien Thérier 98b6269f11 Update take with translation/rotation thresholds. 2015-08-06 14:50:19 +02:00
Ricardo Sánchez-Sáez b8ee219a5f Merge branch 'master' of github.com:rsanchezsaez/ResearchKit into rsanchezsaez-constraints 2015-08-06 11:32:16 +02:00
Julien Thérier 01e8c561bb Better UI. 2015-08-05 17:24:36 +02:00
Julien Thérier 71a0646065 Add check success. 2015-08-05 12:23:46 +02:00
Julien Thérier c8f5a1ccb6 Add 3 arrows. 2015-08-05 09:14:39 +02:00
Ricardo Sánchez-Sáez 2d1c697402 ORKESerialization: refactor NSNumber, NSValue and NSString '*value' methods to property syntax 2015-08-04 15:23:03 +02:00
Ricardo Sánchez-Sáez c96a94c164 Refactor NSNumber, NSValue and NSString '*value' methods to property syntax 2015-08-04 15:22:47 +02:00
Ricardo Sánchez-Sáez 41d346853e Refactor 'value' method syntax to property syntax 2015-08-04 14:16:08 +02:00
Ricardo Sánchez-Sáez ad919639c7 Refactor 'bounds' method syntax to property syntax 2015-08-04 14:10:42 +02:00
Ricardo Sánchez-Sáez 5ebcc6d6b5 Refactor 'bytes/mutableBytes/userInfo' method syntax to property syntax 2015-08-04 14:07:30 +02:00
Ricardo Sánchez-Sáez 27c084707e Refactor 'length' method syntax to property syntax 2015-08-04 14:03:50 +02:00
Ricardo Sánchez-Sáez eeae8f3c1d Refactor 'firstObject/lastObject' method syntax to property syntax 2015-08-04 13:58:46 +02:00
Ricardo Sánchez-Sáez 36f86eb607 Refactor '[object description]' method syntax to 'object.description' property syntax 2015-08-04 13:52:23 +02:00
Ricardo Sánchez-Sáez e69460acfe Refactor '[array count]' method syntax to 'array.count' property syntax 2015-08-04 13:50:00 +02:00
Julien Thérier f7be4f6ae2 Add direction indicator. 2015-08-04 13:40:59 +02:00
Julien Thérier d7975ec9f2 Add arrow view. 2015-08-04 09:08:19 +02:00
Umer Khan 0405f813a2 Added ORKAnswerFormat support for ORKTextScaleSlider 2015-08-03 15:46:20 -07:00
Julien Thérier 8492334353 Improve design. 2015-08-03 15:57:49 +02:00
Ricardo Sánchez-Sáez 20e5e6db03 ORKTowerOfHanoiTowerView & ORKTowerOfHanoiStepViewController: homogenize constraint code 2015-07-30 20:56:09 +02:00
Ricardo Sánchez-Sáez ca442e748d Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints
# Conflicts:
#	ResearchKit/Common/ORKContinueButton.m
#	ResearchKit/Common/ORKNavigationContainerView.m
2015-07-30 20:44:23 +02:00
Ricardo Sánchez-Sáez 4e6e3c9ad3 ORKFormItemCell: remove needless screenType property and init method argument 2015-07-30 20:25:12 +02:00
Ricardo Sánchez-Sáez eeee427c97 Remaining minor constraint code refactoring 2015-07-30 20:16:49 +02:00
Ricardo Sánchez-Sáez 2bc714f05f ORKScaleSliderView: add informative NSLayoutFormatOptions cast for empty options 2015-07-30 20:16:25 +02:00
Ricardo Sánchez-Sáez a07aa08fd4 ORKQuestionStepViewController: add informative NSLayoutFormatOptions cast for empty options 2015-07-30 20:15:43 +02:00
Ricardo Sánchez-Sáez 00ca93e14d ORKActiveStepViewController: add informative NSLayoutFormatOptions cast for empty options 2015-07-30 20:15:13 +02:00
Ricardo Sánchez-Sáez a5e641185b ORKTableContainerView: constraint method rename 2015-07-30 20:13:17 +02:00
Ricardo Sánchez-Sáez ba7433dade ORKSurveyAnswerCellForText: remove needless setNeedsUpdateConstraints 2015-07-30 20:12:39 +02:00
Ricardo Sánchez-Sáez 99f4263417 ORKSurveyAnswerCellForScale: constraint code alignment 2015-07-30 19:55:56 +02:00
Ricardo Sánchez-Sáez a5c16f9d0b ORKSurveyAnswerCellForScale: set layoutMargins outside setUpConstraints 2015-07-30 19:53:54 +02:00
Ricardo Sánchez-Sáez 2d82a2a904 ORKImageChoiceLabel: fix error in calculating the intrinsicContentSize 2015-07-30 19:50:57 +02:00
Ricardo Sánchez-Sáez 286366333f ORKSurveyAnswerCellForImageSelection: homogenize constraint code 2015-07-30 19:34:58 +02:00
Ricardo Sánchez-Sáez a90abe74ae ORKSurveyAnswerCell: constraint code alignment 2015-07-30 19:25:29 +02:00
Ricardo Sánchez-Sáez 9e72e3aaeb ORKStepHeaderView: constraint code alignment 2015-07-30 19:24:01 +02:00
Ricardo Sánchez-Sáez 0af4b33056 ORKSpatialSpanMemoryGameView: use ORKScreenMetricMaxDimension instead of magic number 2015-07-30 19:23:44 +02:00
Ricardo Sánchez-Sáez 62fc9cc6ea ORKSignatureView: move width constraint from ORKConsentSignatureWrapperView 2015-07-30 19:17:00 +02:00
Ricardo Sánchez-Sáez 2b54f90b97 ORKSkin: guard against nil window on ORKWidthForSignatureView() 2015-07-30 19:08:03 +02:00
Ricardo Sánchez-Sáez cfd1724cb0 ORKConsentSignatureController: fix unsatisfiable constraint warning 2015-07-30 19:07:38 +02:00
Ricardo Sánchez-Sáez f6d9feda07 ORKScaleSliderView: use ivars instead of internal properties and refactor constraint code. 2015-07-30 18:39:57 +02:00
Ricardo Sánchez-Sáez be44b0c39a ORKReactionTimeContentView: use ivar instead of internal property 2015-07-30 18:38:22 +02:00
Ricardo Sánchez-Sáez 5e3f4acd78 ORKQuestionStepViewController: homogenize constraint code 2015-07-30 18:26:14 +02:00
Ricardo Sánchez-Sáez fd4557a8e6 ORKNavigationContainerView: refactor constraint code
- Make constraint ivar name clearer.
- Rename updateConstraintConstants to 'updateSkipToContinueButtonConstraint' to reflect that the constraint can get activated/deactivated.
- Call 'setNeedsUpdateConstraints' after 'updateContinueAndSkipEnabled'.
2015-07-30 17:48:26 +02:00
Ricardo Sánchez-Sáez 28f4205bcd ORKInstructionStepView: homogenize constraint code 2015-07-30 17:37:29 +02:00
Ricardo Sánchez-Sáez 7b70f5c362 ORKChoiceButtonView & ORKImageSelectionView: refactor constraint code
- Homogenize constraint code.
- Simplify ORKImageSelectionView by dropping _invisibleLabel (_choiceLabel takes its functionality).
- Extract constraint setup to its own method.
2015-07-30 17:30:40 +02:00
Ricardo Sánchez-Sáez 7f25099acd ORKImageChoiceLabel: make intrinsicContentSize not to change the label itself
(Allows to drop ORKImageSelectionView invisible label.)
2015-07-30 17:25:00 +02:00
Ricardo Sánchez-Sáez fd84d8d893 ORKImageCaptureView: align constraints so they are easier to read 2015-07-30 16:32:28 +02:00
Ricardo Sánchez-Sáez 49bee20f8e ORKImageCaptureStepViewController: extract constraint setup to separate method 2015-07-30 16:29:09 +02:00
Ricardo Sánchez-Sáez 49cbb27222 ORKImageCaptureStepViewController: use ivars instead of internal properties
Also, rename some variables and method names by naming conventions.
2015-07-30 16:25:34 +02:00
Ricardo Sánchez-Sáez 90b4c7b1b6 ORKImageCaptureCameraPreviewView: extract constraint setup to separate method 2015-07-30 16:05:47 +02:00
Ricardo Sánchez-Sáez aa57b8223c ORKImageCaptureCameraPreviewView: use ivars instead of internal properties 2015-07-30 16:00:03 +02:00
Ricardo Sánchez-Sáez db93a6ddc8 ORKFormStepViewController: homogenize constraint code 2015-07-30 15:57:00 +02:00
Ricardo Sánchez-Sáez 41457846e2 ORKFormItemTextCell, ORKFormItemImageSelectionCell & ORKFormItemScaleCell: extract constraint setup to separate method 2015-07-30 15:32:28 +02:00
Ricardo Sánchez-Sáez 08f1b8e3d9 ORKFitnessContentView: better constraint onscreen align 2015-07-30 15:31:50 +02:00
Ricardo Sánchez-Sáez dc5460c120 ORKFitnessContentView: homogenize constraint code 2015-07-30 15:21:01 +02:00
Ricardo Sánchez-Sáez 6a6cb929e1 ORKQuestionStepCellHolderView: homogenize constraint code 2015-07-30 15:07:46 +02:00
Ricardo Sánchez-Sáez fb56d6b64b ORKCountdownView: extract constraint setup to its own method 2015-07-30 15:00:45 +02:00
Ricardo Sánchez-Sáez 2ed0111866 ORKConsentReviewController: homogenize constraint code 2015-07-30 14:53:58 +02:00
Ricardo Sánchez-Sáez ccc615cea6 ORKConsentLearnMoreViewController: homogenize constraint code 2015-07-30 14:51:17 +02:00
Ricardo Sánchez-Sáez 97be632ed8 ORKCompletionStepView: use translatesAutoresizingMaskIntoConstraints property syntax instead of method 2015-07-30 14:49:51 +02:00
Ricardo Sánchez-Sáez 588d9b6528 ORKAudioGraphView: extract constraint setup to its own method 2015-07-30 14:48:34 +02:00
Ricardo Sánchez-Sáez 4d791e96e3 ORKActiveStepViewController: homogenize constraint code 2015-07-30 14:40:00 +02:00
Ricardo Sánchez-Sáez deaa85ad09 ORKActiveStepQuantityView: add space between binary operators 2015-07-30 14:36:03 +02:00
Ricardo Sánchez-Sáez 415a937a7e ORKTest's MainViewController: homogenize constraint code 2015-07-30 14:31:51 +02:00
Ricardo Sánchez-Sáez e15906aeb8 CustomRecorder: homogenize constraint code 2015-07-30 14:14:11 +02:00
Ricardo Sánchez-Sáez 853adebbcd ORKVerticalContainerView: rename constraint methods 2015-07-30 12:56:43 +02:00
Julien Thérier 0c39747462 Add first views. 2015-07-30 09:13:30 +02:00
Ricardo Sánchez-Sáez 7d9e48a8a6 ORKVerticalContainerView: refactor constraint code
- Homogenize code.
- Add constraints by activation.
- Enable autolayout only once for container views.
- Extract static constraint setup to its own method
- Use direct constraint variables instead of dictionary for adjustable constraints.
- Extract some constraint activation/deactivation out from updateConstraintConstants method.
2015-07-29 19:23:10 +02:00
Ricardo Sánchez-Sáez e75f76a1e6 ORKVerticalContainerView: first pass at constraint code homogenization 2015-07-29 18:13:40 +02:00
Julien Thérier e5ac86f029 First draft for hpt task. 2015-07-29 09:29:51 +02:00
Ricardo Sánchez-Sáez 1ef8b48d2a ORKWalkingContentView: make constraints static 2015-07-25 14:21:44 +02:00
Ricardo Sánchez-Sáez b19f2e06a8 ORKToneAudiometryContentView: refactor constraint code
- Homogenize code.
- Make constraints update after moving to a new window.
2015-07-25 14:13:04 +02:00
Ricardo Sánchez-Sáez 8912749a75 ORKTextFieldView: make constraints static 2015-07-24 21:16:30 +02:00
Ricardo Sánchez-Sáez 033719036f ORKTappingContentView: make constraints static and homogenize code 2015-07-24 18:10:39 +02:00
Julien Thérier 4bde825ba0 Create task in the list 2015-07-24 09:01:43 +02:00
Ricardo Sánchez-Sáez ad5aa9912b ORKStepHeaderView: use constraint ivars instead of dictionary (clearer and safer) 2015-07-23 20:13:19 +02:00
Ricardo Sánchez-Sáez 43c6e8b72b ORKStepHeaderView: fix issue in which constraints were not correctly updated for the after moving to a new window 2015-07-23 20:02:01 +02:00
Ricardo Sánchez-Sáez 650c9154b5 ORKSurveyAnswerCellForTextField: make constraints static 2015-07-23 19:42:33 +02:00
Ricardo Sánchez-Sáez deeec06e03 ORKTableContainerView: make constraints static 2015-07-23 19:09:46 +02:00
Ricardo Sánchez-Sáez 2737e60305 ORKSurveyAnswerCellForText: make constraints static and homogenize code 2015-07-23 19:02:24 +02:00
Ricardo Sánchez-Sáez 662e2f746b ORKSurveyAnswerCellForPicker: make constraints static 2015-07-23 18:56:45 +02:00
Ricardo Sánchez-Sáez 43488a1145 ORKSurveyAnswerCellForNumber: refactor constraint code
- Homogenize code.
- Make constraints static.
- Add constraints by activation.
2015-07-23 16:29:07 +02:00
Ricardo Sánchez-Sáez 6d0bd6a66d ORKStepHeaderView: refactor constraint code
- Homogenize code.
- Move initial constraint creation to their own method.
- Add constraints by activation.
- Remove unneeded ivars.
2015-07-23 16:17:13 +02:00
Ricardo Sánchez-Sáez 36d57c9419 ORKSpatialSpanMemoryContentView: make constraints static 2015-07-23 14:40:10 +02:00
Ricardo Sánchez-Sáez 43c75d6d76 ORKNavigationContainerView: refactor constraint code
- Make sure [super updateConstraints] runs last.
- Make most constraints static.
- Add constraints by activation.
- Homogenize code.
2015-07-23 14:25:15 +02:00
Ricardo Sánchez-Sáez d146c50cf0 ORKFormItemTextCell, ORKFormItemImageSelectionCell, ORKFormItemScaleCell: refactor constraint code
- Add constraints by activation.
- Homogenize code.
2015-07-16 18:51:09 +02:00
Ricardo Sánchez-Sáez bd6d36fa31 ORKFormItemTextFieldBasedCell: refactor constraint code
- Add constraints by activation
- Homogenize code.
2015-07-16 18:41:11 +02:00
Ricardo Sánchez-Sáez 27a777a3e7 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints 2015-07-15 19:54:08 +02:00
Ricardo Sánchez-Sáez fdedacaa51 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints 2015-07-09 15:46:58 +01:00
Ricardo Sánchez-Sáez 38707d4f67 ORKContinueButton: refactor constraint code
- Make most constraints static and lighten updateConstraints.
- Add constraints by activation.
2015-05-29 00:30:58 +01:00
Ricardo Sánchez-Sáez b5b3c61be0 ORKConsentSignatureController: refactor constraint code
- Make most constraints static and lighten updateConstraints.
- Add constraints by activation.
2015-05-29 00:29:45 +01:00
Ricardo Sánchez-Sáez 64f702b826 ORKActiveStepQuantityView: rename local variable (additionalConstraints -> constraints) 2015-05-28 23:23:18 +01:00
Ricardo Sánchez-Sáez fdef4d29bd Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints
# Conflicts:
#	ResearchKit/Common/ORKVerticalContainerView.m
2015-05-28 23:13:44 +01:00
Ricardo Sánchez-Sáez e6a27ba94a Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints 2015-05-20 20:21:49 +01:00
Ricardo Sánchez-Sáez ad72ce7347 Merge branch 'master' of github.com:ResearchKit/ResearchKit into rsanchezsaez-constraints 2015-05-17 21:51:24 +01:00
Ricardo Sánchez-Sáez 6b0559b13b ORKAudioContentView: make constraints static 2015-05-12 02:10:27 +01:00
Ricardo Sánchez-Sáez 93bb589eb7 ORKActiveStepTimerView: refactor constraint code
- Make most constraints static and lighten updateConstraints
- Add constraints by activatiion
2015-05-12 02:00:22 +01:00
Ricardo Sánchez-Sáez f923bd7fe0 ORKActiveStepQuantityView: avoid a bit of duplicate constraint code; rename 'setupConstraints' to 'setUpConstraints' 2015-05-12 01:55:09 +01:00
Ricardo Sánchez-Sáez af1ed4425c ORKStepHeaderView & ORKVerticalContainerView: drop '_' prefix from constraint keys 2015-05-12 00:49:19 +01:00
636 changed files with 28895 additions and 7084 deletions
+7 -1
View File
@@ -75,13 +75,19 @@ tests, add UI to at least one test application so that the new
features can be reviewed and tested. Consider also whether to add new
code to other existing demo apps to exercise your feature.
When adding UI driven components, make sure that they are accessible.
Follow the steps outlined in the [Best Practices](../../wiki/best-practices)
section under Accessibility. Before submitting the pull request, you should
audit your components with Voice Over (or other relevant assistive technologies)
enabled.
Keep changes that fix different issues separate. For bug fixes,
separate bugs should be submitted as separate pull requests. A good
way to do this is to create a new branch in your fork for each new
bug work on.
Any new user-visible strings should be included in the English
`Localizable.strings` table so that they can be picked up and
`ResearchKit.strings` table so that they can be picked up and
localized in the next release cycle.
+23 -22
View File
@@ -4,19 +4,19 @@ ResearchKit Framework
The ResearchKit™ framework is an open source software framework that makes it easy to
create apps for medical research or for other research projects.
* Getting Started: [Getting Started](#gettingstarted)
* Documentation: ([Programming Guide](http://researchkit.github.io/docs/docs/Overview/GuideOverview.html)) ([API](http://researchkit.github.io/docs/index.html))
* Best practices: [Best Practices](../../wiki/best-practices)
* Contributing to ResearchKit: [Contributing](CONTRIBUTING.md)
* Website and blog: ([researchkit.org](http://researchkit.github.io/index.html)) ([Blog](http://researchkit.github.io/blog.html))
* ResearchKit BSD License: [License](#license)
* [Getting 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)
Getting More Information
========================
* Join [researchkit-users](https://lists.apple.com/mailman/listinfo/researchkit-users) for discussing uses of the ResearchKit framework and related projects.
* Join [researchkit-dev](https://lists.apple.com/mailman/listinfo/researchkit-dev) for discussing ongoing work to improve and expand the framework.
* Or [contact us](https://developer.apple.com/contact/researchkit/)
* Join the [ResearchKit Forum](https://forums.developer.apple.com/community/researchkit) for discussing uses of the ResearchKit framework and related projects.
Use Cases
===========
@@ -29,14 +29,14 @@ Surveys
-------
The ResearchKit framework provides a pre-built user interface for surveys, which can be
presented modally on an iPhone, iPod Touch, or iPad. [Surveys](http://researchkit.github.io/docs/docs/Survey/CreatingSurveys.html)
presented modally on an iPhone, iPod Touch, or iPad. See *[Creating Surveys](http://researchkit.org/docs/docs/Survey/CreatingSurveys.html)* for more information.
Consent
----------------
The ResearchKit framework provides visual consent templates that you can customize to
explain the details of your research study and obtain a signature if needed. [Consent](http://researchkit.github.io/docs/docs/InformedConsent/InformedConsent.html)
explain the details of your research study and obtain a signature if needed. See *[Obtaining Consent](http://researchkit.org/docs/docs/InformedConsent/InformedConsent.html)* for more information.
Active Tasks
@@ -45,7 +45,7 @@ Active Tasks
Some studies may need data beyond survey questions or the passive data collection
capabilities available through use of the HealthKit and CoreMotion APIs if you are
programming for iOS. ResearchKit's active tasks invite users to perform activities
under semi-controlled conditions, while iPhone sensors actively collect data. [Active Tasks](http://researchkit.github.io/docs/docs/ActiveTasks/ActiveTasks.html)
under semi-controlled conditions, while iPhone sensors actively collect data. See *[Active Tasks](http://researchkit.org/docs/docs/ActiveTasks/ActiveTasks.html)* for more information.
Getting Started<a name="gettingstarted"></a>
@@ -56,7 +56,8 @@ Requirements
------------
The primary ResearchKit framework codebase supports iOS and requires Xcode 7.0
or newer. The ResearchKit framework has a Base SDK version of 8.0, meaning that apps
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.
@@ -124,7 +125,7 @@ the step `myStep`.
*Objective-C*
```objc
```objc
ORKInstructionStep *myStep =
[[ORKInstructionStep alloc] initWithIdentifier:@"intro"];
myStep.title = @"Welcome to ResearchKit";
@@ -203,8 +204,8 @@ which you must implement in order to handle the completion of the task:
*Swift*
```swift
func taskViewController(taskViewController: ORKTaskViewController,
didFinishWithReason reason: ORKTaskViewControllerFinishReason,
func taskViewController(taskViewController: ORKTaskViewController,
didFinishWithReason reason: ORKTaskViewControllerFinishReason,
error: NSError?) {
let taskResult = taskViewController.result
// You could do something with the result here.
@@ -214,7 +215,7 @@ func taskViewController(taskViewController: ORKTaskViewController,
}
```
If you now run your app, you should see your first ResearchKit framework
instruction step:
@@ -245,22 +246,22 @@ following license unless another license is explicitly identified:
```
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
+219
View File
@@ -0,0 +1,219 @@
# ResearchKit Release Notes
## ResearchKit 1.3 Release Notes
*ResearchKit 1.3* supports *iOS* and requires *Xcode 7.2* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stability and performance improvements, *ResearchKit 1.3* includes the following new features and enhancements.
- **New Active Tasks**
- **9-Hole Peg Test**
*Contributed by [Julien Therier](https://github.com/julientherier).*
The *[9-Hole Peg Test] task* is used to test upper extremity functionality.
The test involves putting a variable variable number of pegs in a hole, and then removing them.
The test is documented in the scientific literature to measure the *[MSFC score in Multiple Sclerosis](http://www.nationalmssociety.org/For-Professionals/Researchers/Resources-for-Researchers/Clinical-Study-Measures/9-Hole-Peg-Test-(9-HPT))* or *[Parkinson's Disease](http://www.ncbi.nlm.nih.gov/pubmed/22020457)*.
- **Sample App**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *[Sample App]* serves as a template application that combines different modules from the ResearchKit framework.
- **Account Module**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *[Account Module]* provides steps to facilitate account creation and login.
The module includes the following steps:
1. Registration to create a new account.
2. Verification to verify email.
3. Login to allow registered users to login.
- **Passcode with Touch ID**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *[Passcode with Touch ID] module* provides the ability to secure any ResearchKit application with a pin entry.
This module includes a *Keychain Wrapper* that stores the passcode on the device, as well as the option to use Touch ID on compatible devices. The passcode module supports 4-pin and 6-pin entries.
The passcode module can be used in the following scenarios:
1. Passcode creation step which can be used as part of onboarding to create a passcode and store it in the keychain.
2. Passcode authentication view controller which can be presented modally when appropriate.
3. Passcode modification view controller which allows the participant to change their passcode.
- **Other Improvements**
- **Optional Form Items**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
Implements the `ORKFormItem` `optional` property.
The *Continue/Done* button of form steps enables only if:
- At least one form item has an answer.
- All answered form items are valid.
- All the non-optional form items have answers.
- **Location Question**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
A *Location Question* can be used to request details about the participant's current location or a specific address.
The question uses *MapKit* to provides a visual representation for the specified address.
- **Wait Step**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
The *Wait Step* provides a step to be used in-between steps when additional data processing is required.
The step supports both indeterminate and determinate progress views, as well as the ability to show text status updates.
- **Validated Text Answer Format**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
The *Validated Text Answer Format* enhances the existing *Text Answer Format* by providing input validation using a regular expression.
A valid *NSRegularExpression* object and an *error message* string are required to properly use this answer format.
## ResearchKit 1.2 Release Notes
*ResearchKit 1.2* supports *iOS* and requires *Xcode 7.0* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stability and performance improvements, *ResearchKit 1.2* includes the following new features and enhancements.
- **New Active Tasks**
- **Tower of Hanoi Task**
*Contributed by [coxy1989](https://github.com/coxy1989).*
The *[Tower of Hanoi](https://en.wikipedia.org/wiki/Tower_of_Hanoi#Applications) task* is frequently used in psychological research on problem solving.
It is a mathematical puzzle consisting of three rods and a number of disks of different sizes which can slide onto any rod. The puzzle starts with the disks in a stack in ascending order of size on one rod (the smallest at the top).
The objective of the puzzle is to move the entire stack to another rod, obeying the following rules:
1. Only one disk can be moved at a time.
2. Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack.
3. No disk may be placed on top of a smaller disk.
- **Paced Serial Addition Test Task**
*Contributed by [Julien Therier](https://github.com/julientherier).*
The *Paced Serial Addition Test task* provides adaptations of both the *Paced Auditory Serial Addition Test (PASAT)* and the *Paced Visual Serial Addition Test (PVSAT)*.
The *[PASAT](https://en.wikipedia.org/wiki/Paced_Auditory_Serial_Addition_Test)* is a neuropsychological test used to assess capacity and rate of information processing and sustained and divided attention.
Both tests are documented in the scientific literature ([Fos et al., 2000](http://www.ncbi.nlm.nih.gov/pubmed/11125707); [Nagels et al., 2005](http://www.ncbi.nlm.nih.gov/pubmed/15823678)) as a measure of the [*Multiple Sclerosis Functional Score*](http://www.nationalmssociety.org/For-Professionals/Researchers/Resources-for-Researchers/Clinical-Study-Measures/Multiple-Sclerosis-Functional-Composite-%28MSFC%29).
This task generates a series of single digits (for example, 60 of them), at the specific frequency (for example, one new digit every 2 or 3 seconds). The user must add the newly presented digit to the one prior to it.
- **Timed Walk Task**
*Contributed by [Julien Therier](https://github.com/julientherier).*
The *Timed Walk task* measures gait speed and is an adaptation of the [*Timed 25-Foot Walk*](http://www.nationalmssociety.org/For-Professionals/Researchers/Resources-for-Researchers/Clinical-Study-Measures/Timed-25-Foot-Walk-%28T25-FW%29) in the context of *multiple sclerosis*.
Gait speed has been demonstrated to be a useful and reliable functional measure of walking ability. When administering the *Timed Walk Task*, patients are allowed to use assistive devices (canes, crutches, walkers).
- **Charts Module**
*Contributed by [coxy1989](https://github.com/coxy1989) and [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
A *Charts module* has been implemented. It features three chart types: a *pie chart* (`ORKPieChartView`), a *line graph chart* (`ORKLineGraphChartView`), and a *discrete graph chart* (`ORKDiscreteGraphChartView`).
The views in the *Charts module* can be used independently of the rest of *ResearchKit*. It doesn't automatically connect with any other *ResearchKit* module: the developer has to supply the data to be displayed through the views' `dataSources`, which allows for maximum flexibility.
- **Other Improvements**
- **Scale Answer Format**
*Contributed by [Apple Inc](https://github.com/researchkit).*
*Discrete scales* now support *text choice* labels, and all *scales* support images in place of the minimum and maximum range labels.
- **Result Predicates**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
The predicate-building methods in `ORKResultPredicate` now use the new `ORKResultSelector` class for unequivocally identifying a *question step result* or a *form item result*.
This eliminates ambiguity when matching results with the same inner scope identifier. For example, a *form item result* can have the same identifier as a *question step result* or as another *form item result* in a different *form step*, and you can now match them separately.
## ResearchKit 1.1 Release Notes
*ResearchKit 1.1* supports *iOS* and requires *Xcode 6.3* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stability and performance improvements, *ResearchKit 1.1* includes the following new features and enhancements.
- **Navigable Ordered Task**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
A new type of *conditional ordered task* (`ORKNavigableOrderedTask`) has been implemented.
The developer can use the `ORKStepNavigationRule` subclasses to dynamically navigate between the task steps:
- `ORKPredicateStepNavigationRule` allows to make conditional jumps by matching previous results (either those of the the ongoing task, or those of any previously stored task result tree). You typically use the class methods in the `ORKResultPredicate` class to match answers in the most commonly used result types.
- `ORKDirectStepNavigationRule` provides support for unconditional jumps.
- **New Active Tasks**
- **Reaction Time Task**
*Contributed by [coxy1989](https://github.com/coxy1989).*
The *Reaction Time Task* is an adaptation of the [*Simple Reaction Time test (SRT)*](http://www.cambridgecognition.com/tests/simple-reaction-time-srt). *SRT* measures reaction time through delivery of a known stimulus to a known location to elicit a known response.
This test is deployed in a range of research questions across fields including medicine, sports science and psychology.
Although it classically involves pressing the space bar or clicking a mouse in response to an event on screen, the *ResearchKit* implementation relies on the study participant shaking the device when she sees a blue circle on the screen, which we think is more correlatable to a true stimulus reaction test.
- **Tone Audiometry Task**
*Contributed by [Vincent Tourraine](https://github.com/vtourraine).*
The *Tone Audiometry Task* is an adaptation of the [*Pure Tone Audiometry test (PTA)*](https://en.wikipedia.org/wiki/Pure_tone_audiometry). *PTA* is a key hearing test used to identify hearing threshold levels of an individual, enabling determination of the degree, type and configuration of a hearing loss.
The *ResearchKit* implementation generates a series of pure sinusoid sounds, with different frequencies and on different channels (left or right). The test starts at the minimum volume and is gradually increased until the participant perceives it and taps a button. At that time, the current sound amplitude, frequency and channel are recorded.
- **Scale Answer Format Enhancements**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez) and [Bruce Duncan](https://github.com/brucehappy).*
Support for discrete and continuous *vertical scales* has been added. Some questions, like mood measurement or symptom severity measurement queries may be more naturally presented using a *vertical scale*.
The *Scale Answer Format* has also been improved by making it usable within forms.
- **Image Capture Step**
*Contributed by [Bruce Duncan](https://github.com/brucehappy).*
An *Image Capture Step* has been added. The researcher can ask the participant to take pictures of relevant body parts. The researcher can provide a body part image template to facilitate the scale and orientation of the taken pictures.
- **iPad Support**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez) and [Apple Inc](https://github.com/researchkit).*
*iPad support* for all orientations has been implemented.
- **iPhone Landscape Support**
*Contributed by [Apple Inc.](https://github.com/researchkit) and [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
*iPhone landscape orientation support* has been implemented.
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:ResearchKit.xcodeproj">
</FileRef>
<FileRef
location = "group:Testing/ORKTest/ORKTest.xcodeproj">
</FileRef>
<FileRef
location = "group:samples/ORKCatalog/ORKCatalog.xcodeproj">
</FileRef>
<FileRef
location = "group:samples/ORKSample/ORKSample.xcodeproj">
</FileRef>
</Workspace>
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'ResearchKit'
s.version = '1.2'
s.version = '1.3.1'
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/'
File diff suppressed because it is too large Load Diff
@@ -33,13 +33,13 @@
#import "ORKHelpers.h"
static NSString *const kActivityUnknown = @"unknown";
static NSString *const kActivityStationary = @"stationary";
static NSString *const kActivityWalking = @"walking";
static NSString *const kActivityRunning = @"running";
static NSString *const kActivityAutomotive = @"automotive";
static NSString *const kStartDateKey = @"startDate";
static NSString *const kEndDateKey = @"endDate";
static NSString *const ActivityUnknown = @"unknown";
static NSString *const ActivityStationary = @"stationary";
static NSString *const ActivityWalking = @"walking";
static NSString *const ActivityRunning = @"running";
static NSString *const ActivityAutomotive = @"automotive";
static NSString *const StartDateKey = @"startDate";
static NSString *const EndDateKey = @"endDate";
static NSString *stringFromActivityConfidence(CMMotionActivityConfidence confidence) {
NSDictionary *confidences = @{@(CMMotionActivityConfidenceHigh) : @"high",
@@ -51,33 +51,32 @@ static NSString *stringFromActivityConfidence(CMMotionActivityConfidence confide
static NSArray *activityArray(CMMotionActivity *activity) {
NSMutableArray *array = [NSMutableArray array];
if (activity.unknown) {
[array addObject:kActivityUnknown];
[array addObject:ActivityUnknown];
}
if (activity.stationary) {
[array addObject:kActivityStationary];
[array addObject:ActivityStationary];
}
if (activity.walking) {
[array addObject:kActivityWalking];
[array addObject:ActivityWalking];
}
if (activity.running) {
[array addObject:kActivityRunning];
[array addObject:ActivityRunning];
}
if (activity.automotive) {
[array addObject:kActivityAutomotive];
[array addObject:ActivityAutomotive];
}
return array;
}
static NSString *const kActivityKey = @"activity";
static NSString *const kConfidenceKey = @"confidence";
static NSString *const ActivityKey = @"activity";
static NSString *const ConfidenceKey = @"confidence";
@implementation CMMotionActivity (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary {
return @{kConfidenceKey : stringFromActivityConfidence(self.confidence),
kActivityKey : activityArray(self),
kStartDateKey : ORKStringFromDateISO8601(self.startDate)};
return @{ConfidenceKey : stringFromActivityConfidence(self.confidence),
ActivityKey : activityArray(self),
StartDateKey : ORKStringFromDateISO8601(self.startDate)};
}
@end
@@ -33,16 +33,16 @@
#import "ORKHelpers.h"
static NSString *const kHKSampleIdentifierKey = @"type"; // For compatibility with Health XML export
static NSString *const kHKUUIDKey = @"uuid";
static NSString *const kHKSampleStartDateKey = @"startDate";
static NSString *const kHKSampleEndDateKey = @"endDate";
static NSString *const kHKSampleValue = @"value";
static NSString *const kHKMetadataKey = @"metadata";
static NSString *const kHKSourceKey = @"source";
static NSString *const kHKUnitKey = @"unit";
static NSString *const kHKCorrelatedObjectsKey = @"objects";
// static NSString *const kHKSourceIdentifierKey = @"sourceBundleIdentifier";
static NSString *const HKSampleIdentifierKey = @"type"; // For compatibility with Health XML export
static NSString *const HKUUIDKey = @"uuid";
static NSString *const HKSampleStartDateKey = @"startDate";
static NSString *const HKSampleEndDateKey = @"endDate";
static NSString *const HKSampleValue = @"value";
static NSString *const HKMetadataKey = @"metadata";
static NSString *const HKSourceKey = @"source";
static NSString *const HKUnitKey = @"unit";
static NSString *const HKCorrelatedObjectsKey = @"objects";
// static NSString *const HKSourceIdentifierKey = @"sourceBundleIdentifier";
@implementation HKSample (ORKJSONDictionary)
@@ -52,31 +52,31 @@ static NSString *const kHKCorrelatedObjectsKey = @"objects";
// Type identification
HKSampleType *sampleType = [self sampleType];
mutableDictionary[kHKSampleIdentifierKey] = [sampleType identifier];
mutableDictionary[HKSampleIdentifierKey] = [sampleType identifier];
// consider adding @"class" : NSStringFromClass(sampleType) ?
// Start and end dates
NSDate *startDate = [self startDate];
if (startDate) {
mutableDictionary[kHKSampleStartDateKey] = ORKStringFromDateISO8601(startDate);
mutableDictionary[HKSampleStartDateKey] = ORKStringFromDateISO8601(startDate);
}
NSDate *endDate = [self endDate];
if (endDate) {
mutableDictionary[kHKSampleEndDateKey] = ORKStringFromDateISO8601(endDate);
mutableDictionary[HKSampleEndDateKey] = ORKStringFromDateISO8601(endDate);
}
if (unit) {
mutableDictionary[kHKUnitKey] = [unit unitString];
mutableDictionary[HKUnitKey] = [unit unitString];
}
if ((options & ORKSampleIncludeUUID)) {
NSUUID *uuid = [self UUID];
if (uuid) {
mutableDictionary[kHKUUIDKey] = uuid.UUIDString;
mutableDictionary[HKUUIDKey] = uuid.UUIDString;
}
}
if ( (options & ORKSampleIncludeMetadata) && [self.metadata count] > 0) {
if ( (options & ORKSampleIncludeMetadata) && self.metadata.count > 0) {
NSMutableDictionary *metadata = [self.metadata mutableCopy];
for (NSString *k in metadata) {
id obj = metadata[k];
@@ -85,13 +85,13 @@ static NSString *const kHKCorrelatedObjectsKey = @"objects";
}
}
mutableDictionary[kHKMetadataKey] = metadata;
mutableDictionary[HKMetadataKey] = metadata;
}
if (options & ORKSampleIncludeSource) {
HKSource *source = [self source];
if (source.name) {
mutableDictionary[kHKSourceKey] = source.name;
mutableDictionary[HKSourceKey] = source.name;
}
}
@@ -115,8 +115,8 @@ static NSString *const kHKCorrelatedObjectsKey = @"objects";
- (NSDictionary *)ork_JSONDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
NSMutableDictionary *dictionary = [self ork_JSONMutableDictionaryWithOptions:options unit:unit];
NSInteger value = [self value];
dictionary[kHKSampleValue] = @(value);
NSInteger value = self.value;
dictionary[HKSampleValue] = @(value);
return dictionary;
}
@@ -136,7 +136,7 @@ static NSString *const kHKCorrelatedObjectsKey = @"objects";
HKQuantity *quantity = [self quantity];
double value = [quantity doubleValueForUnit:unit];
dictionary[kHKSampleValue] = @(value);
dictionary[HKSampleValue] = @(value);
return dictionary;
@@ -151,7 +151,7 @@ static NSString *const kHKCorrelatedObjectsKey = @"objects";
NSMutableDictionary *mutableDictionary = [self ork_JSONMutableDictionaryWithOptions:options unit:nil];
// The correlated objects
NSMutableArray *correlatedObjects = [NSMutableArray arrayWithCapacity:[sampleTypes count]];
NSMutableArray *correlatedObjects = [NSMutableArray arrayWithCapacity:sampleTypes.count];
for (HKSample *sample in self.objects) {
NSUInteger idx = [sampleTypes indexOfObject:sample.sampleType];
if (idx == NSNotFound) {
@@ -160,7 +160,7 @@ static NSString *const kHKCorrelatedObjectsKey = @"objects";
[correlatedObjects addObject:[sample ork_JSONDictionaryWithOptions:options unit:units[idx]]];
}
mutableDictionary[kHKCorrelatedObjectsKey] = correlatedObjects;
mutableDictionary[HKCorrelatedObjectsKey] = correlatedObjects;
return mutableDictionary;
}
@@ -86,16 +86,16 @@
self.motionManager = [self createMotionManager];
if (! _logger) {
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (! _logger) {
if (!_logger) {
[self finishRecordingWithError:err];
return;
}
}
if (! self.motionManager || ! self.motionManager.accelerometerAvailable) {
if (!self.motionManager || !self.motionManager.accelerometerAvailable) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}];
@@ -103,7 +103,7 @@
return;
}
self.motionManager.accelerometerUpdateInterval = 1.0/_frequency;
self.motionManager.accelerometerUpdateInterval = 1.0 / _frequency;
self.uptime = [NSProcessInfo processInfo].systemUptime;
@@ -172,11 +172,6 @@
@end
@interface ORKAccelerometerRecorderConfiguration ()
@end
@implementation ORKAccelerometerRecorderConfiguration
#pragma clang diagnostic push
@@ -84,15 +84,14 @@
view.isAccessibilityElement = NO;
}
[self setupConstraints];
[self setNeedsUpdateConstraints];
[self setUpConstraints];
}
return self;
}
- (void)setEnabled:(BOOL)enabled {
_enabled = enabled;
self.hidden = ! enabled;
self.hidden = !enabled;
[self setNeedsUpdateConstraints];
}
@@ -111,91 +110,89 @@
_imageView.image = image;
}
- (void)setupConstraints {
- (void)setUpConstraints {
const CGFloat TitleBaselineToValueBaseline = 40;
const CGFloat ValueBaselineToBottom = 36;
NSMutableArray *additionalConstraints = [NSMutableArray array];
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_titleLabel, _valueLabel, _imageView);
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_titleLabel]"
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_titleLabel]"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_titleLabel]|"
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_titleLabel]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[additionalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imageView]-10-[_valueLabel]|"
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imageView]-10-[_valueLabel]|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:views]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_titleLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1.0
constant:TitleBaselineToValueBaseline]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:self
[constraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_valueLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1.0
constant:ValueBaselineToBottom]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:_valueHolder
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:_valueHolder
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0.0]];
[additionalConstraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
[constraints addObject:[NSLayoutConstraint constraintWithItem:_valueHolder
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0.0]];
for (NSLayoutConstraint *constraint in additionalConstraints) {
constraint.priority = UILayoutPriorityRequired-2;
for (NSLayoutConstraint *constraint in constraints) {
constraint.priority = UILayoutPriorityRequired - 2;
}
[NSLayoutConstraint activateConstraints:additionalConstraints];
[NSLayoutConstraint activateConstraints:constraints];
NSLayoutConstraint *zeroWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
zeroWidthConstraint.priority = UILayoutPriorityRequired-1;
_zeroWidthConstraint = zeroWidthConstraint;
_zeroWidthConstraint.active = !_enabled;
_zeroWidthConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
_zeroWidthConstraint.priority = UILayoutPriorityRequired - 1;
[self setNeedsUpdateConstraints];
}
- (void)updateConstraints {
@@ -245,18 +242,18 @@
[self addSubview:_leftView];
[self addSubview:_rightView];
[self addSubview:_metricKeyline];
[self setupConstraints];
[self setUpConstraints];
}
return self;
}
- (void)setupConstraints {
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_leftView, _rightView, _metricKeyline);
// Leave space for the keyline between these views, and then constrain it to be 1px wide and go from top to bottom baseline of metric views.
CGFloat scale = [[UIScreen mainScreen] scale];
CGFloat scale = [UIScreen mainScreen].scale;
NSArray *vertConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_leftView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
@@ -265,10 +262,10 @@
NSArray *horizConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_leftView]-s-[_rightView]-|"
options:NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom|NSLayoutFormatDirectionLeftToRight
metrics:@{ @"s": @(1/scale) }
metrics:@{ @"s": @(1.0 / scale) }
views:views];
for (NSLayoutConstraint *constraint in horizConstraints) {
constraint.priority = UILayoutPriorityDefaultHigh+1;
constraint.priority = UILayoutPriorityDefaultHigh + 1;
}
[constraints addObjectsFromArray:horizConstraints];
@@ -290,7 +287,7 @@
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_leftView][_metricKeyline(==s)]"
options:NSLayoutFormatAlignAllTop|NSLayoutFormatDirectionLeftToRight
metrics:@{ @"s": @(1/scale) }
metrics:@{ @"s": @(1.0 / scale) }
views:views]];
NSLayoutConstraint *keylineBottom = [NSLayoutConstraint constraintWithItem:_metricKeyline
attribute:NSLayoutAttributeBottom
@@ -308,7 +305,7 @@
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
maxWidthConstraint.priority = UILayoutPriorityRequired-2;
maxWidthConstraint.priority = UILayoutPriorityRequired - 2;
[constraints addObject:maxWidthConstraint];
+2 -2
View File
@@ -56,7 +56,7 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
- (instancetype)initWithDuration:(NSTimeInterval)duration interval:(NSTimeInterval)interval runtime:(NSTimeInterval)runtime handler:(ORKActiveStepTimerHandler)handler {
self = [super init];
if (self) {
if (! handler) {
if (!handler) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Handler is required" userInfo:nil];
}
@@ -224,7 +224,7 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
_preExistingRuntime += timeIntervalFromMachTime(now - _startTime);
_startTime = 0;
if (! atFinish) {
if (!atFinish) {
// If we are atFinish, the task will be released after the handler completes
[self queue_releaseBackgroundTask];
}
@@ -45,6 +45,10 @@
@implementation ORKActiveStepTimerView {
BOOL _started;
BOOL _registeredForNotifications;
NSLayoutConstraint *_countDownLabelBottomToStartTimerButtonTopConstraint;
NSLayoutConstraint *_countDownLabelZeroHeightConstraint;
NSLayoutConstraint *_startTimerButtonZeroHeightConstraint;
}
- (instancetype)initWithFrame:(CGRect)frame {
@@ -70,7 +74,8 @@
_countDownLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setUpConstraints];
}
return self;
}
@@ -88,11 +93,11 @@
}
registered = _registeredForNotifications;
NSNotificationCenter *nfc = [NSNotificationCenter defaultCenter];
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
if (registered) {
[nfc addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[notificationCenter addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
} else {
[nfc removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
[notificationCenter removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}
}
@@ -144,56 +149,80 @@
- (void)finishStep:(ORKActiveStepViewController *)viewController {
}
- (void)setNeedsUpdateConstraints {
[NSLayoutConstraint deactivateConstraints:[self constraints]];
[super setNeedsUpdateConstraints];
static const CGFloat CountDownLabelToButtonMargin = 2.0;
- (void)setUpConstraints {
NSDictionary *views = NSDictionaryOfVariableBindings(_countDownLabel, _startTimerButton);
ORKEnableAutoLayoutForViews(views.allValues);
NSMutableArray *constraints = [NSMutableArray new];
for (UIView *view in views.allValues) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
}
[constraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_countDownLabel
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
_countDownLabelBottomToStartTimerButtonTopConstraint = [NSLayoutConstraint constraintWithItem:_startTimerButton
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_countDownLabel
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:CountDownLabelToButtonMargin];
[constraints addObject:_countDownLabelBottomToStartTimerButtonTopConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_startTimerButton
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
[NSLayoutConstraint activateConstraints:constraints];
_countDownLabelZeroHeightConstraint = [NSLayoutConstraint constraintWithItem:_countDownLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
_startTimerButtonZeroHeightConstraint = [NSLayoutConstraint constraintWithItem:_startTimerButton
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
[self setNeedsUpdateConstraints];
}
- (void)updateConstraints {
NSDictionary *dictionary = NSDictionaryOfVariableBindings(_countDownLabel, _startTimerButton);
NSDictionary *metrics = @{@"CS" : @(2)};
ORKEnableAutoLayoutForViews([dictionary allValues]);
for (UIView *view in [dictionary allValues]) {
[self addConstraint:[NSLayoutConstraint
constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
[self addConstraint:[NSLayoutConstraint
constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
}
if (! _countDownLabel.hidden) {
NSMutableString *verticalLayout = [NSMutableString new];
[verticalLayout appendString:@"V:|[_countDownLabel]"];
if (! _startTimerButton.hidden) {
[verticalLayout appendString:@"-CS-[_startTimerButton]"];
}
[verticalLayout appendString:@"|"];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalLayout
options:NSLayoutFormatAlignAllCenterX
metrics:metrics
views:dictionary]];
} else {
[self addConstraint:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:0]];
}
_countDownLabelZeroHeightConstraint.active = _countDownLabel.hidden;
_startTimerButtonZeroHeightConstraint.active = (_countDownLabel.hidden || _startTimerButton.hidden);
_countDownLabelBottomToStartTimerButtonTopConstraint.constant =
(_countDownLabel.hidden || _startTimerButton.hidden) ? 0.0 : CountDownLabelToButtonMargin;
[super updateConstraints];
}
@@ -103,7 +103,7 @@
[super viewDidLoad];
_activeStepView = [[ORKActiveStepView alloc] initWithFrame:self.view.bounds];
[_activeStepView setTranslatesAutoresizingMaskIntoConstraints:NO];
_activeStepView.translatesAutoresizingMaskIntoConstraints = NO;
[_activeStepView setCustomView:_customView];
[self updateContinueButtonItem];
_activeStepView.headerView.learnMoreButtonItem = self.learnMoreButtonItem;
@@ -111,9 +111,17 @@
_activeStepView.continueSkipContainer.continueEnabled = _finished;
[self.view addSubview:_activeStepView];
NSMutableArray *constraints = [NSMutableArray arrayWithArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[s]|" options:0 metrics:nil views:@{@"s":_activeStepView}]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[tg][s]|" options:0 metrics:nil views:@{@"s":_activeStepView,@"tg":self.topLayoutGuide}]];
[self.view addConstraints:constraints];
NSMutableArray *constraints = [NSMutableArray new];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[activeStepView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:@{@"activeStepView": _activeStepView}]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topLayoutGuide][activeStepView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:@{@"activeStepView": _activeStepView,
@"topLayoutGuide": self.topLayoutGuide}]];
[NSLayoutConstraint activateConstraints:constraints];
[self prepareStep];
}
@@ -155,7 +163,10 @@
// Wait for animation complete
dispatch_async(dispatch_get_main_queue(), ^{
if ([[self activeStep] shouldStartTimerAutomatically]) {
if(self.started){
// Should call resume instead of start when the task has been started.
[self resume];
} else if ([[self activeStep] shouldStartTimerAutomatically]) {
[self start];
}
});
@@ -313,7 +324,7 @@
- (void)suspend {
ORK_Log_Debug(@"%@",self);
if (self.finished || ! self.started) {
if (self.finished || !self.started) {
return;
}
@@ -325,7 +336,7 @@
- (void)resume {
ORK_Log_Debug(@"%@",self);
if (self.finished || ! self.started) {
if (self.finished || !self.started) {
return;
}
@@ -351,7 +362,7 @@
if (self.activeStep.shouldVibrateOnFinish) {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
}
if (! self.activeStep.startsFinished) {
if (!self.activeStep.startsFinished) {
if (self.activeStep.shouldContinueOnFinish) {
[self goForward];
}
+47 -42
View File
@@ -56,14 +56,15 @@ static const CGFloat GraphViewRedZoneHeight = 25;
@end
static const CGFloat kValueLineWidth = 4.5;
static const CGFloat kValueLineMargin = 1.5;
static const CGFloat ValueLineWidth = 4.5;
static const CGFloat ValueLineMargin = 1.5;
@implementation ORKAudioGraphView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setUpConstraints];
#if TARGET_IPHONE_SIMULATOR
_values = @[@(0.2),@(0.6),@(0.55), @(0.1), @(0.75), @(0.7)];
@@ -72,6 +73,20 @@ static const CGFloat kValueLineMargin = 1.5;
return self;
}
- (void)setUpConstraints {
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:CGFLOAT_MAX];
heightConstraint.priority = UILayoutPriorityFittingSizeLevel;
[NSLayoutConstraint activateConstraints:@[heightConstraint]];
}
- (void)setValues:(NSArray *)values {
_values = [values copy];
[self setNeedsDisplay];
@@ -99,41 +114,41 @@ static const CGFloat kValueLineMargin = 1.5;
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, bounds);
CGFloat scale = [self.window.screen scale];
CGFloat scale = self.window.screen.scale;
CGFloat midY = CGRectGetMidY(bounds);
CGFloat maxX = CGRectGetMaxX(bounds);
CGFloat halfHeight = bounds.size.height/2;
CGFloat halfHeight = bounds.size.height / 2;
CGContextSaveGState(context);
{
UIBezierPath *centerLine = [UIBezierPath new];
[centerLine moveToPoint:(CGPoint){.x=0,.y=midY}];
[centerLine addLineToPoint:(CGPoint){.x=maxX,.y=midY}];
[centerLine moveToPoint:(CGPoint){.x = 0, .y = midY}];
[centerLine addLineToPoint:(CGPoint){.x = maxX, .y = midY}];
CGContextSetLineWidth(context, 1/scale);
CGContextSetLineWidth(context, 1.0 / scale);
[_keyColor setStroke];
CGFloat lengths[2] = {3,3};
CGFloat lengths[2] = {3, 3};
CGContextSetLineDash(context, 0, lengths, 2);
[centerLine stroke];
}
CGContextRestoreGState(context);
CGFloat lineStep = kValueLineMargin + kValueLineWidth;
CGFloat lineStep = ValueLineMargin + ValueLineWidth;
CGContextSaveGState(context);
{
CGFloat x = maxX - lineStep/2;
CGContextSetLineWidth(context, kValueLineWidth);
CGFloat x = maxX - lineStep / 2;
CGContextSetLineWidth(context, ValueLineWidth);
CGContextSetLineCap(context, kCGLineCapRound);
UIBezierPath *path1 = [UIBezierPath new];
path1.lineCapStyle = kCGLineCapRound;
path1.lineWidth = kValueLineWidth;
path1.lineWidth = ValueLineWidth;
UIBezierPath *path2 = [path1 copy];
for (NSNumber *value in [_values reverseObjectEnumerator]) {
CGFloat floatValue = [value doubleValue];
CGFloat floatValue = value.doubleValue;
UIBezierPath *path = nil;
if (floatValue > _alertThreshold) {
@@ -143,8 +158,8 @@ static const CGFloat kValueLineMargin = 1.5;
path = path2;
[_keyColor setStroke];
}
[path moveToPoint:(CGPoint){.x=x,.y=midY-floatValue*halfHeight}];
[path addLineToPoint:(CGPoint){.x=x,.y=midY+floatValue*halfHeight}];
[path moveToPoint:(CGPoint){.x = x, .y = midY - floatValue*halfHeight}];
[path addLineToPoint:(CGPoint){.x = x, .y = midY + floatValue*halfHeight}];
x -= lineStep;
@@ -177,7 +192,7 @@ static const CGFloat kValueLineMargin = 1.5;
+ (UIFont *)defaultFont {
UIFontDescriptor *descriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline];
UIFontDescriptor *alternativeDescriptor = ORKFontDescriptorForLightStylisticAlternative(descriptor);
return [UIFont fontWithDescriptor:alternativeDescriptor size:[alternativeDescriptor pointSize]+4];
return [UIFont fontWithDescriptor:alternativeDescriptor size:[alternativeDescriptor pointSize] + 4];
}
@end
@@ -193,7 +208,6 @@ static const CGFloat kValueLineMargin = 1.5;
@implementation ORKAudioContentView {
NSArray *_constraints;
NSMutableArray *_samples;
UIColor *_keyColor;
}
@@ -221,11 +235,11 @@ static const CGFloat kValueLineMargin = 1.5;
_timerLabel.text = @"06:00";
_alertLabel.text = ORKLocalizedString(@"AUDIO_TOO_LOUD_LABEL", nil);
self.alertThreshold = GraphViewBlueZoneHeight/(GraphViewRedZoneHeight*2+GraphViewBlueZoneHeight);
self.alertThreshold = GraphViewBlueZoneHeight / ((GraphViewRedZoneHeight * 2) + GraphViewBlueZoneHeight);
[self updateGraphSamples];
[self applyKeyColor];
[self setNeedsUpdateConstraints];
[self setUpConstraints];
}
return self;
}
@@ -266,27 +280,21 @@ static const CGFloat kValueLineMargin = 1.5;
_graphView.alertColor = alertColor;
}
- (void)updateConstraints {
if ([_constraints count]) {
[NSLayoutConstraint deactivateConstraints:_constraints];
_constraints = nil;
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_timerLabel, _alertLabel, _graphView);
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_graphView]-[_alertLabel]|"
options:0
metrics:nil
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_graphView]-[_alertLabel]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_alertLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
multiplier:1.0
constant:0.0]];
const CGFloat sideMargin = self.layoutMargins.left + (2 * ORKStandardLeftMarginForTableViewCell(self));
const CGFloat innerMargin = 2;
@@ -297,18 +305,15 @@ static const CGFloat kValueLineMargin = 1.5;
metrics:@{@"sideMargin": @(sideMargin), @"innerMargin": @(innerMargin)}
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_graphView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:(GraphViewBlueZoneHeight+GraphViewRedZoneHeight*2)]];
multiplier:1.0
constant:(GraphViewBlueZoneHeight + GraphViewRedZoneHeight * 2)]];
_constraints = constraints;
[NSLayoutConstraint activateConstraints:constraints];
[super updateConstraints];
}
- (void)setAlertThreshold:(CGFloat)alertThreshold {
@@ -344,8 +349,8 @@ static const CGFloat kValueLineMargin = 1.5;
}
- (void)updateAlertLabelHidden {
NSNumber *sample = [_samples lastObject];
BOOL show = (! _finished && ([sample doubleValue] > _alertThreshold)) || _failed;
NSNumber *sample = _samples.lastObject;
BOOL show = (!_finished && (sample.doubleValue > _alertThreshold)) || _failed;
_alertLabel.hidden = !show;
}
@@ -356,13 +361,13 @@ static const CGFloat kValueLineMargin = 1.5;
- (void)addSample:(NSNumber *)sample {
NSAssert(sample != nil, @"Sample should be non-nil");
if (! _samples) {
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];
if (_samples.count > 500) {
_samples = [[_samples subarrayWithRange:(NSRange){250, _samples.count - 250}] mutableCopy];
}
[self updateGraphSamples];
}
+2 -3
View File
@@ -103,8 +103,7 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
bufferActive[frame] = bufferValue;
if (audioGenerator->_playsStereo) {
bufferNonActive[frame] = bufferValue;
}
else {
} else {
bufferNonActive[frame] = 0;
}
@@ -113,7 +112,7 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
theta -= 2.0 * M_PI;
}
fadeInFactor += 1/(ORKSineWaveToneGeneratorSampleRateDefault * audioGenerator->_fadeInDuration);
fadeInFactor += 1.0 / (ORKSineWaveToneGeneratorSampleRateDefault * audioGenerator->_fadeInDuration);
if (fadeInFactor >= 1) {
fadeInFactor = 1;
}
+17 -22
View File
@@ -68,10 +68,10 @@
if (self) {
self.continuesInBackground = YES;
if (! recorderSettings) {
if (!recorderSettings) {
recorderSettings = [[self class] defaultRecorderSettings];
}
if (! [recorderSettings isKindOfClass:[NSDictionary class]]) {
if (![recorderSettings isKindOfClass:[NSDictionary class]]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"recorderSettings should be a dictionary" userInfo:recorderSettings];
}
self.recorderSettings = recorderSettings;
@@ -84,18 +84,18 @@
@throw [NSException exceptionWithName:NSDestinationInvalidException reason:@"audioRecorder requires an output directory" userInfo:nil];
}
// Only create the file when we should actually start recording.
if (! _audioRecorder) {
if (!_audioRecorder) {
NSError *error = nil;
NSURL *soundFileURL = [self recordingFileURL];
if (! [self recreateFileWithError:&error]) {
if (![self recreateFileWithError:&error]) {
[self finishRecordingWithError:error];
return;
}
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if (! [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]) {
if (![audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]) {
[self finishRecordingWithError:error];
return;
}
@@ -105,19 +105,19 @@
initWithURL:soundFileURL
settings:self.recorderSettings
error:&error];
if (! _audioRecorder) {
if (!_audioRecorder) {
[self finishRecordingWithError:error];
return;
}
#if ! TARGET_IPHONE_SIMULATOR
#if !TARGET_IPHONE_SIMULATOR
if (!_audioRecorder.recording) {
[_audioRecorder prepareToRecord];
}
#endif
}
#if ! TARGET_IPHONE_SIMULATOR
#if !TARGET_IPHONE_SIMULATOR
if (!_audioRecorder.recording) {
[_audioRecorder prepareToRecord];
[_audioRecorder record];
@@ -128,7 +128,7 @@
}
- (void)stop {
if (! _audioRecorder) {
if (!_audioRecorder) {
// Error has already been returned.
return;
}
@@ -136,7 +136,7 @@
[self doStopRecording];
NSURL *fileUrl = [self recordingFileURL];
if (! [[NSFileManager defaultManager] fileExistsAtPath:[[self recordingFileURL] path]]) {
if (![[NSFileManager defaultManager] fileExistsAtPath:[[self recordingFileURL] path]]) {
fileUrl = nil;
}
@@ -151,12 +151,12 @@
- (NSString *)mimeType {
NSDictionary *recorderSettings = [self recorderSettings];
unsigned int recorderFormat = [recorderSettings[AVFormatIDKey] unsignedIntValue];
unsigned int recorderFormat = ((NSNumber *)recorderSettings[AVFormatIDKey]).unsignedIntValue;
NSString *contentType = @"audio";
switch (recorderFormat) {
case kAudioFormatLinearPCM: {
int numBits = [recorderSettings[AVLinearPCMBitDepthKey] intValue] ? : 16;
int numBits = ((NSNumber *)recorderSettings[AVLinearPCMBitDepthKey]).intValue ? : 16;
contentType = [NSString stringWithFormat:@"audio/L%d", numBits];
break;
}
@@ -202,7 +202,7 @@
- (NSString *)extension {
NSDictionary *recorderSettings = [self recorderSettings];
unsigned int recorderFormat = [recorderSettings[AVFormatIDKey] unsignedIntValue];
unsigned int recorderFormat = ((NSNumber *)recorderSettings[AVFormatIDKey]).unsignedIntValue;
NSString *extension = @"au";
switch (recorderFormat) {
@@ -233,7 +233,7 @@
- (BOOL)recreateFileWithError:(NSError * __autoreleasing *)error {
NSURL *url = [self recordingFileURL];
if (! url) {
if (!url) {
if (error) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteInvalidFileNameError userInfo:@{NSLocalizedDescriptionKey:ORKLocalizedString(@"ERROR_RECORDER_NO_OUTPUT_DIRECTORY", nil)}];
}
@@ -242,12 +242,12 @@
NSFileManager *fileManager = [NSFileManager defaultManager];
if (! [fileManager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:error]) {
if (![fileManager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:error]) {
return NO;
}
if ([fileManager fileExistsAtPath:[url path]]) {
if (! [fileManager removeItemAtPath:[url path] error:error]) {
if (![fileManager removeItemAtPath:[url path] error:error]) {
return NO;
}
}
@@ -266,11 +266,6 @@
@end
@interface ORKAudioRecorderConfiguration ()
@end
@implementation ORKAudioRecorderConfiguration
#pragma clang diagnostic push
@@ -283,7 +278,7 @@
recorderSettings:(NSDictionary *)recorderSettings {
self = [super initWithIdentifier:identifier];
if (self) {
if (recorderSettings && ! [recorderSettings isKindOfClass:[NSDictionary class]]) {
if (recorderSettings && ![recorderSettings isKindOfClass:[NSDictionary class]]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"recorderSettings should be a dictionary" userInfo:recorderSettings];
}
_recorderSettings = recorderSettings;
+1 -1
View File
@@ -55,7 +55,7 @@
NSTimeInterval const ORKAudioTaskMinimumDuration = 5.0;
if ( self.stepDuration < ORKAudioTaskMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKAudioTaskMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKAudioTaskMinimumDuration)] userInfo:nil];
}
}
@@ -107,16 +107,16 @@
[_avAudioRecorder updateMeters];
float value = [_avAudioRecorder averagePowerForChannel:0];
// Assume value is in range roughly -60dB to 0dB
float clampedValue = MAX(value/60.0, -1) + 1;
float clampedValue = MAX(value / 60.0, -1) + 1;
[_audioContentView addSample:@(clampedValue)];
_audioContentView.timeLeft = [_timer duration] - [_timer runtime];
}
- (void)startNewTimerIfNeeded {
if (! _timer) {
if (!_timer) {
NSTimeInterval duration = self.audioStep.stepDuration;
__weak typeof(self) weakSelf = self;
_timer = [[ORKActiveStepTimer alloc] initWithDuration:duration interval:duration/100 runtime:0 handler:^(ORKActiveStepTimer *timer, BOOL finished) {
_timer = [[ORKActiveStepTimer alloc] initWithDuration:duration interval:duration / 100 runtime:0 handler:^(ORKActiveStepTimer *timer, BOOL finished) {
typeof(self) strongSelf = weakSelf;
[strongSelf doSample];
if (finished) {
+1 -1
View File
@@ -57,7 +57,7 @@
NSTimeInterval const ORKCountdownStepMinimumDuration = 3.0;
if ( self.stepDuration < ORKCountdownStepMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKCountdownStepMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKCountdownStepMinimumDuration)] userInfo:nil];
}
}
@@ -69,6 +69,9 @@
CAShapeLayer *_circleLayer;
}
static const CGFloat ProgressIndicatorDiameter = 104.0;
static const CGFloat ProgressIndicatorOuterMargin = 1.0;
- (instancetype)init {
self = [super init];
if (self) {
@@ -88,55 +91,11 @@
[self addSubview:_progressView];
self.translatesAutoresizingMaskIntoConstraints = NO;
static const CGFloat ProgressIndicatorDiameter = 104;
static const CGFloat ProgressIndicatorOuterMargin = 1;
NSDictionary *metrics = @{@"d":@(ProgressIndicatorDiameter+2*ProgressIndicatorOuterMargin)};
NSDictionary *views = NSDictionaryOfVariableBindings(_textLabel, _timeLabel, _progressView);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_textLabel]-(>=0)-[_progressView(==d)]|"
options:NSLayoutFormatDirectionLeadingToTrailing|NSLayoutFormatAlignAllCenterX
metrics:metrics
views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_textLabel]-(>=0)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_progressView(==d)]-(>=0)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:views]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0 constant:0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:_timeLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_progressView
attribute:NSLayoutAttributeCenterX
multiplier:1.0 constant:0]];
// Constant required in order to give appearance of vertical centering (compensating for leading on font)
[self addConstraint:[NSLayoutConstraint constraintWithItem:_timeLabel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:_progressView
attribute:NSLayoutAttributeCenterY
multiplier:1.0 constant:-3]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_textLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1 constant:16-ProgressIndicatorOuterMargin]];
[self setUpConstraints];
_circleLayer = [CAShapeLayer layer];
static const CGFloat ProgressIndicatorRadius = ProgressIndicatorDiameter/2;
_circleLayer.path = [[UIBezierPath bezierPathWithArcCenter:CGPointMake(ProgressIndicatorRadius+ProgressIndicatorOuterMargin, ProgressIndicatorRadius+ProgressIndicatorOuterMargin)
static const CGFloat ProgressIndicatorRadius = ProgressIndicatorDiameter / 2;
_circleLayer.path = [[UIBezierPath bezierPathWithArcCenter:CGPointMake(ProgressIndicatorRadius + ProgressIndicatorOuterMargin, ProgressIndicatorRadius + ProgressIndicatorOuterMargin)
radius:ProgressIndicatorRadius
startAngle:M_PI + M_PI_2
endAngle:-M_PI_2
@@ -154,13 +113,65 @@
return self;
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray new];
NSDictionary *metrics = @{@"d": @(ProgressIndicatorDiameter + 2 * ProgressIndicatorOuterMargin)};
NSDictionary *views = NSDictionaryOfVariableBindings(_textLabel, _timeLabel, _progressView);
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_textLabel]-(>=0)-[_progressView(==d)]|"
options:NSLayoutFormatDirectionLeadingToTrailing | NSLayoutFormatAlignAllCenterX
metrics:metrics
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_textLabel]-(>=0)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[_progressView(==d)]-(>=0)-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timeLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_progressView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
// Constant required in order to give appearance of vertical centering (compensating for leading on font)
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timeLabel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:_progressView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:-3.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_textLabel
attribute:NSLayoutAttributeLastBaseline
multiplier:1.0
constant:16.0 - ProgressIndicatorOuterMargin]];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)tintColorDidChange {
_circleLayer.strokeColor = self.tintColor.CGColor;
}
- (void)startAnimateWithDuration:(NSTimeInterval)duration {
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = duration*2;
animation.duration = duration * 2;
animation.removedOnCompletion = YES;
animation.values = @[@(1.0), @(0.0), @(0.0)];
animation.keyTimes = @[@(0.0), @(0.5), @(1.0)];
@@ -224,7 +235,7 @@
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, [@(_countDown) stringValue]);
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @(_countDown).stringValue);
[_countdownView startAnimateWithDuration:[(ORKActiveStep *)self.step stepDuration]];
}
@@ -233,7 +244,7 @@
}
- (void)countDownTimerFired:(ORKActiveStepTimer *)timer finished:(BOOL)finished {
_countDown = MAX((_countDown-1), 0);
_countDown = MAX((_countDown - 1), 0);
[self updateCountdownLabel];
if (UIAccessibilityIsVoiceOverRunning()) {
@@ -247,7 +258,7 @@
}];
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, ORKLocalizedString(@"AX_ANNOUNCE_BEGIN_TASK", nil));
} else {
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, [@(_countDown) stringValue]);
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @(_countDown).stringValue);
[super countDownTimerFired:timer finished:finished];
}
} else {
+10 -10
View File
@@ -225,7 +225,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if appending succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * __nullable __autoreleasing *)error;
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * _Nullable __autoreleasing *)error;
/**
Checks whether a file has been marked as uploaded.
@@ -251,7 +251,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if adding or removing the attribute succeeded; otherwise, `NO`.
*/
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * __nullable __autoreleasing *)error;
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * _Nullable __autoreleasing *)error;
/**
Removes files if they are marked uploaded.
@@ -265,7 +265,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if removing the files succeeded; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * __nullable __autoreleasing *)error;
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * _Nullable __autoreleasing *)error;
/**
Removes all files managed by this logger (files that have the `logName` prefix).
@@ -274,7 +274,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if removing the files succeeded.; otherwise, `NO`.
*/
- (BOOL)removeAllFilesWithError:(NSError *__nullable __autoreleasing *)error;
- (BOOL)removeAllFilesWithError:(NSError *_Nullable __autoreleasing *)error;
@end
@@ -320,7 +320,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * __nullable __autoreleasing *)error;
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
/**
Appends the specified object to the log file.
@@ -331,7 +331,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * __nullable __autoreleasing *)error;
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
/**
Appends the specified objects to the log file.
@@ -342,7 +342,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * __nullable __autoreleasing *)error;
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
@end
@@ -518,7 +518,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * __nullable __autoreleasing *)error;
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable __autoreleasing *)error;
/**
Removes a set of uploaded files.
@@ -532,7 +532,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * __nullable __autoreleasing *)error;
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable __autoreleasing *)error;
/**
Removes old and uploaded logs to bring total bytes down to a threshold.
@@ -545,7 +545,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError * __nullable __autoreleasing *)error;
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError * _Nullable __autoreleasing *)error;
@end
+71 -67
View File
@@ -39,13 +39,13 @@
#import "ORKDefines_Private.h"
static const char * kORKDataLoggerUploadedAttr = "com.apple.ResearchKit.uploaded";
static const char *ORKDataLoggerUploadedAttr = "com.apple.ResearchKit.uploaded";
// Default per-logfile settings when a data logger is used in an ORKDataLoggerManager
static const NSTimeInterval kORKDataLoggerManagerDefaultLogFileLifetime = 60*60*24*3; // 3 days
static const unsigned long long kORKDataLoggerManagerDefaultLogFileSize = 1024*1024; // 1 MB
static const NSTimeInterval ORKDataLoggerManagerDefaultLogFileLifetime = 60 * 60 * 24 * 3; // 3 days
static const unsigned long long ORKDataLoggerManagerDefaultLogFileSize = 1024 * 1024; // 1 MB
static NSString *const kORKDataLoggerManagerConfigurationFilename = @".ORKDataLoggerManagerConfiguration";
static NSString *const ORKDataLoggerManagerConfigurationFilename = @".ORKDataLoggerManagerConfiguration";
@interface ORKDataLogger ()
@@ -80,7 +80,7 @@ static NSString *const kORKDataLoggerManagerConfigurationFilename = @".ORKDataLo
- (NSString *)ork_logName {
NSString *lastComponent = [self lastPathComponent];
NSRange idx = [lastComponent rangeOfString:@"-"];
if (! idx.length) {
if (!idx.length) {
@throw [NSException exceptionWithName:NSGenericException reason:@"URL is not a completed log file" userInfo:@{@"url":self}];
}
@@ -91,28 +91,28 @@ static NSString *const kORKDataLoggerManagerConfigurationFilename = @".ORKDataLo
- (NSString *)ork_logDateComponent {
NSString *lastComponent = [self lastPathComponent];
NSRange idx = [lastComponent rangeOfString:@"-"];
if (! idx.length) {
if (!idx.length) {
@throw [NSException exceptionWithName:NSGenericException reason:@"URL is not a completed log file" userInfo:@{@"url":self}];
}
NSString *logDateComponent = [lastComponent substringFromIndex:idx.location+1];
NSString *logDateComponent = [lastComponent substringFromIndex:idx.location + 1];
return logDateComponent;
}
- (BOOL)ork_isUploaded {
NSData *data = [self ork_dataForAttr:kORKDataLoggerUploadedAttr];
NSData *data = [self ork_dataForAttr:ORKDataLoggerUploadedAttr];
if (!data) {
return NO;
}
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return ([string integerValue] != 0);
return (string.integerValue != 0);
}
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError * __autoreleasing *)error {
NSString *value = (uploaded ? @"1" : @"0");
NSData *encodedString = [value dataUsingEncoding:NSUTF8StringEncoding];
return [self ork_setData:encodedString forAttr:kORKDataLoggerUploadedAttr error:error];
return [self ork_setData:encodedString forAttr:ORKDataLoggerUploadedAttr error:error];
}
- (NSData *)ork_dataForAttr:(const char *)attr {
@@ -125,7 +125,7 @@ static NSString *const kORKDataLoggerManagerConfigurationFilename = @".ORKDataLo
}
NSMutableData *data = [NSMutableData dataWithLength:length];
length = getxattr(path, attr, [data mutableBytes], length, 0, 0);
length = getxattr(path, attr, data.mutableBytes, length, 0, 0);
if (length <= 0) {
return nil;
}
@@ -135,7 +135,7 @@ static NSString *const kORKDataLoggerManagerConfigurationFilename = @".ORKDataLo
- (BOOL)ork_setData:(NSData *)data forAttr:(const char *)attr error:(NSError * __autoreleasing *)error {
const char *path = [self fileSystemRepresentation];
int rc = setxattr(path, attr, [data bytes], [data length], 0, 0);
int rc = setxattr(path, attr, data.bytes, data.length, 0, 0);
if (rc != 0) {
if (error) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:rc userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_SET_ATTRIBUTE", nil)}];
@@ -145,13 +145,13 @@ static NSString *const kORKDataLoggerManagerConfigurationFilename = @".ORKDataLo
}
- (NSString *)ork_logNameInDirectory:(NSURL *)directory {
if (! [self isFileURL]) {
if (![self isFileURL]) {
@throw [NSException exceptionWithName:NSGenericException reason:@"URL is not a fileURL" userInfo:@{@"url":self}];
}
NSString *lastComponent = [self lastPathComponent];
NSRange idx = [lastComponent rangeOfString:@"-"];
if (! idx.length) {
if (!idx.length) {
@throw [NSException exceptionWithName:NSGenericException reason:@"URL is not a completed log file" userInfo:@{@"url":self}];
}
@@ -267,7 +267,7 @@ static void *ORKObjectObserverContext = &ORKObjectObserverContext;
}
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
if (! [self canAcceptLogObject:object]) {
if (![self canAcceptLogObject:object]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"ORKLogFormatter accepts NSData only" userInfo:nil];
}
return [self writeData:(NSData *)object fileHandle:fileHandle error:error];
@@ -285,7 +285,7 @@ static void *ORKObjectObserverContext = &ORKObjectObserverContext;
}
}
if (! success) {
if (!success) {
[self rollbackToCheckpoint:checkpoint fileHandle:fileHandle];
if (error) {
*error = errorOut;
@@ -312,8 +312,8 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (self) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_ORKJSON_emptyLogLength = [[kJSONLogEmptyLogString dataUsingEncoding:NSUTF8StringEncoding] length];
_ORKJSON_terminatorLength = [[kJSONLogFooterString dataUsingEncoding:NSUTF8StringEncoding] length];
_ORKJSON_emptyLogLength = [kJSONLogEmptyLogString dataUsingEncoding:NSUTF8StringEncoding].length;
_ORKJSON_terminatorLength = [kJSONLogFooterString dataUsingEncoding:NSUTF8StringEncoding].length;
});
}
return self;
@@ -361,15 +361,15 @@ static NSInteger _ORKJSON_terminatorLength = 0;
* object being appended, and the footer bytes.
*/
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
if (! fileHandle) {
if (!fileHandle) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Filehandle is nil" userInfo:nil];
}
NSInteger numObjects = [objects count];
NSInteger numObjects = objects.count;
if (numObjects == 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"No objects" userInfo:nil];
}
for (NSObject *object in objects) {
if (! [self canAcceptLogObject:object]) {
if (![self canAcceptLogObject:object]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"ORKLogFormatter accepts JSON serializable objects only" userInfo:nil];
}
}
@@ -406,7 +406,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
}
}];
if (! success) {
if (!success) {
return success;
}
@@ -417,7 +417,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
success = [self writeData:outputData fileHandle:fileHandle error:error];
if (! success) {
if (!success) {
[self rollbackToCheckpoint:checkpoint fileHandle:fileHandle];
}
@@ -456,13 +456,13 @@ static NSInteger _ORKJSON_terminatorLength = 0;
self = [super init];
if (self) {
_url = [url copy];
if (! [[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
if (![[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"directory does not exist" userInfo:nil];
}
if ([logName hasSuffix:@"-"]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"logName should not terminate with '-'" userInfo:nil];
}
if (! [logName length]) {
if (!logName.length) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"logName must be non-empty" userInfo:nil];
}
@@ -486,7 +486,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
- (instancetype)initWithDirectory:(NSURL *)url configuration:(NSDictionary *)configuration delegate:(id<ORKDataLoggerDelegate>)delegate {
Class formatterClass = NSClassFromString(configuration[@"formatterClass"]);
if (! formatterClass) {
if (!formatterClass) {
@throw [NSException exceptionWithName:NSGenericException reason:[NSString stringWithFormat:@"%@ is not a class", configuration[@"formatterClass"]] userInfo:nil];
}
@@ -494,8 +494,8 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (self) {
// Don't notify about initial setup
[_observer pause];
self.maximumCurrentLogFileSize = [configuration[@"maximumCurrentLogFileSize"] unsignedLongValue];
self.maximumCurrentLogFileLifetime = [configuration[@"maximumCurrentLogFileLifetime"] doubleValue];
self.maximumCurrentLogFileSize = ((NSNumber *)configuration[@"maximumCurrentLogFileSize"]).unsignedLongValue;
self.maximumCurrentLogFileLifetime = ((NSNumber *)configuration[@"maximumCurrentLogFileLifetime"]).doubleValue;
[_observer resume];
}
return self;
@@ -515,7 +515,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
- (void)setupDirectorySource {
int dirFD = open([_url fileSystemRepresentation], O_EVTONLY);
if (dirFD < 0) {
ORK_Log_Oops(@"Could not track directory %s (%d)", [_url fileSystemRepresentation], [[NSFileManager defaultManager] fileExistsAtPath:[_url path]]);
ORK_Log_Warning(@"Could not track directory %s (%d)", [_url fileSystemRepresentation], [[NSFileManager defaultManager] fileExistsAtPath:[_url path]]);
} else {
// Dispatch to a concurrent queue, so we don't store up blocks while our
// queue is working.
@@ -614,7 +614,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * __autoreleasing *)error {
if (![objects count]) {
if (!objects.count) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Empty array" userInfo:nil];
}
__block BOOL success = NO;
@@ -664,7 +664,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
- (void)queue_setNeedsUpdateBytes {
if (! _directoryDirty) {
if (!_directoryDirty) {
_directoryDirty = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), _queue, ^{
@@ -704,7 +704,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
NSError *errorOut = nil;
NSMutableArray *urls = [NSMutableArray array];
for (NSURL *url in enumerator) {
if (! [self urlMatchesLogName:url]) {
if (![self urlMatchesLogName:url]) {
continue;
}
if ( [[url lastPathComponent] isEqualToString:_logName]) {
@@ -716,13 +716,13 @@ static NSInteger _ORKJSON_terminatorLength = 0;
// If there's been an error getting the resource values, give up
break;
}
if (! [resources[NSURLIsRegularFileKey] boolValue]) {
if (!((NSNumber *)resources[NSURLIsRegularFileKey]).boolValue) {
continue;
}
[urls addObject:url];
}
if (! errorOut) {
if (!errorOut) {
// Sort the URLs before beginning enumeration for the caller
[urls sortUsingComparator:^NSComparisonResult(NSURL *obj1, NSURL *obj2) {
// We can assume all relate to files in the same directory
@@ -766,12 +766,12 @@ static NSInteger _ORKJSON_terminatorLength = 0;
NSNumber *fileExists = nil;
[url getResourceValue:&fileExists forKey:NSURLIsRegularFileKey error:nil];
BOOL createNewFile = ! [fileExists boolValue];
BOOL createNewFile = !fileExists.boolValue;
NSFileHandle *fileHandle = nil;
if (!createNewFile) {
fileHandle = [NSFileHandle fileHandleForWritingToURL:url error:error];
if (! fileHandle) {
if (!fileHandle) {
// Assume it's because we can't open the file, perhaps for security reasons.
// Close and rename the log.
[self queue_closeAndRenameLog];
@@ -858,19 +858,19 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
// Check if a non-empty file exists, and create the file handle if so
NSDictionary *params = [url resourceValuesForKeys:@[NSURLIsRegularFileKey,NSURLFileSizeKey] error:nil];
NSDictionary *parameters = [url resourceValuesForKeys:@[NSURLIsRegularFileKey,NSURLFileSizeKey] error:nil];
if ( [params[NSURLIsRegularFileKey] boolValue]) {
if ([params[NSURLFileSizeKey] intValue] > 0) {
if (((NSNumber *)parameters[NSURLIsRegularFileKey]).boolValue) {
if (((NSNumber *)parameters[NSURLFileSizeKey]).intValue > 0) {
NSURL *destinationUrl = [ORKDataLogger nextUrlForDirectoryUrl:_url logName:_logName];
ORK_Log_Debug(@"Rollover: %@ to %@", [url lastPathComponent], [destinationUrl lastPathComponent]);
[fileManager moveItemAtURL:url toURL:destinationUrl error:nil];
if (self.fileProtectionMode == ORKFileProtectionCompleteUnlessOpen) {
// Upgrade to complete file protection after roll-over
NSError *error = nil;
if (! [fileManager setAttributes:@{NSFileProtectionKey : NSFileProtectionComplete}
if (![fileManager setAttributes:@{NSFileProtectionKey : NSFileProtectionComplete}
ofItemAtPath:[destinationUrl path] error:&error]) {
ORK_Log_Debug(@"Error setting NSFileProtectionComplete on %@: %@", destinationUrl, error);
ORK_Log_Warning(@"Error setting NSFileProtectionComplete on %@: %@", destinationUrl, error);
}
}
@@ -889,7 +889,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
NSURL *url = [self currentLogFileURL];
NSDictionary *parameters = [url resourceValuesForKeys:@[NSURLIsRegularFileKey, NSURLFileSizeKey, NSURLCreationDateKey] error:nil];
NSInteger fileSize = [parameters[NSURLFileSizeKey] integerValue];
NSInteger fileSize = ((NSNumber *)parameters[NSURLFileSizeKey]).integerValue;
NSDate *creationDate = parameters[NSURLCreationDateKey];
BOOL exceededSizeThreshold = ( (self.maximumCurrentLogFileSize > 0) && (fileSize >= self.maximumCurrentLogFileSize));
@@ -968,7 +968,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
} error:error];
// Reporting multiple errors
if ([errors count]) {
if (errors.count) {
if (!success && error && *error) {
[errors addObject:*error];
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorMultipleErrors userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_MULTIPLE", nil), @"errors" : errors}];
@@ -1052,7 +1052,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
self = [super init];
if (self) {
_directory = directory;
if (! [[NSFileManager defaultManager] fileExistsAtPath:[_directory path]]) {
if (![[NSFileManager defaultManager] fileExistsAtPath:[_directory path]]) {
@throw [NSException exceptionWithName:NSGenericException reason:@"directory does not exist" userInfo:nil];
}
_delegate = delegate;
@@ -1065,39 +1065,43 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return nil;
}
NSDictionary *configuration = [NSDictionary dictionaryWithContentsOfURL:[_directory URLByAppendingPathComponent:kORKDataLoggerManagerConfigurationFilename]];
NSDictionary *configuration = [NSDictionary dictionaryWithContentsOfURL:[_directory URLByAppendingPathComponent:ORKDataLoggerManagerConfigurationFilename]];
[self loadConfiguration:configuration];
_observer = [[ORKObjectObserver alloc] initWithObject:self keys:@[@"pendingUploadBytesThreshold",@"totalBytesThreshold"] selector:@selector(configurationDidChange)];
_observer = [[ORKObjectObserver alloc] initWithObject:self keys:@[@"pendingUploadBytesThreshold", @"totalBytesThreshold"] selector:@selector(configurationDidChange)];
[self setNeedsUpdateBytes];
}
return self;
}
static NSString *const PendingUploadBytesThresholdKey = @"pendingUploadBytesThreshold";
static NSString *const TotalBytesThresholdKey = @"totalBytesThreshold";
static NSString *const LoggerConfigurationsKey = @"loggers";
- (void)loadConfiguration:(NSDictionary *)configuration {
self.pendingUploadBytesThreshold = [configuration[@"pendingUploadBytesThreshold"] unsignedLongLongValue];
self.totalBytesThreshold = [configuration[@"totalBytesThreshold"] unsignedLongLongValue];
self.pendingUploadBytesThreshold = ((NSNumber *)configuration[PendingUploadBytesThresholdKey]).unsignedLongLongValue;
self.totalBytesThreshold = ((NSNumber *)configuration[TotalBytesThresholdKey]).unsignedLongLongValue;
NSMutableDictionary *records = [NSMutableDictionary dictionary];
for (NSDictionary *loggerConfig in configuration[@"loggers"]) {
ORKDataLogger *logger = [[ORKDataLogger alloc] initWithDirectory:_directory configuration:loggerConfig delegate:self];
for (NSDictionary *loggerConfiguration in configuration[LoggerConfigurationsKey]) {
ORKDataLogger *logger = [[ORKDataLogger alloc] initWithDirectory:_directory configuration:loggerConfiguration delegate:self];
records[logger.logName] = logger;
}
_records = records;
}
- (NSDictionary *)queue_configuration {
NSMutableArray *loggerConfigurations = [[_records allValues] valueForKey:@"configuration"];
NSMutableArray *loggerConfigurations = [_records.allValues valueForKey:@"configuration"];
return @{@"pendingUploadBytesThreshold" : @(self.pendingUploadBytesThreshold),
@"totalBytesThreshold" : @(self.totalBytesThreshold),
@"loggers" : loggerConfigurations };
return @{PendingUploadBytesThresholdKey : @(self.pendingUploadBytesThreshold),
TotalBytesThresholdKey : @(self.totalBytesThreshold),
LoggerConfigurationsKey : loggerConfigurations };
}
- (void)queue_synchronizeConfiguration {
NSDictionary *configuration = [self queue_configuration];
[configuration writeToURL:[_directory URLByAppendingPathComponent:kORKDataLoggerManagerConfigurationFilename] atomically:YES];
[configuration writeToURL:[_directory URLByAppendingPathComponent:ORKDataLoggerManagerConfigurationFilename] atomically:YES];
}
- (void)configurationDidChange {
@@ -1114,8 +1118,8 @@ static NSInteger _ORKJSON_terminatorLength = 0;
ORKDataLogger *dataLogger = [[ORKDataLogger alloc] initWithDirectory:_directory logName:logName formatter:formatter delegate:self];
dataLogger.delegate = nil;
// Pick suitable defaults for a typical use pattern
dataLogger.maximumCurrentLogFileLifetime = kORKDataLoggerManagerDefaultLogFileLifetime;
dataLogger.maximumCurrentLogFileSize = kORKDataLoggerManagerDefaultLogFileSize;
dataLogger.maximumCurrentLogFileLifetime = ORKDataLoggerManagerDefaultLogFileLifetime;
dataLogger.maximumCurrentLogFileSize = ORKDataLoggerManagerDefaultLogFileSize;
dataLogger.delegate = self;
_records[logName] = dataLogger;
@@ -1166,7 +1170,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
- (NSArray<NSString *> *)logNames {
__block NSArray<NSString *> *logNames = nil;
dispatch_sync(_queue, ^{
logNames = [_records allKeys];
logNames = _records.allKeys;
});
return logNames;
}
@@ -1175,7 +1179,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
BOOL success = YES;
NSMutableArray *allFiles = [NSMutableArray array];
// Collect all the log file URLs so we can sort them by date rather than enumerating by logger.
for (ORKDataLogger *logger in [_records allValues]) {
for (ORKDataLogger *logger in _records.allValues) {
success = [logger enumerateLogsNeedingUpload:^(NSURL *logFileUrl, BOOL *stop) {
[allFiles addObject:logFileUrl];
} error:error];
@@ -1228,7 +1232,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
for (NSURL *url in fileURLs) {
NSString *logName = [url ork_logNameInDirectory:_directory];
if (! _records[logName]) {
if (!_records[logName]) {
@throw [NSException exceptionWithName:NSGenericException reason:@"URL is not from a known logger" userInfo:@{@"url":url}];
}
@@ -1239,7 +1243,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
success = NO;
}
}
if (error && [notRemoved count]) {
if (error && notRemoved.count) {
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorMultipleErrors userInfo:@{@"notRemoved":notRemoved}];
}
return success;
@@ -1260,7 +1264,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
for (NSURL *url in fileURLs) {
NSString *logName = [url ork_logNameInDirectory:_directory];
ORKDataLogger *logger = _records[logName];
if (! logger) {
if (!logger) {
@throw [NSException exceptionWithName:NSGenericException reason:@"URL is not from a known logger" userInfo:@{@"url":url}];
}
@@ -1271,7 +1275,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
success = NO;
}
}
if (error && [notRemoved count]) {
if (error && notRemoved.count) {
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorMultipleErrors userInfo:@{@"notRemoved":notRemoved}];
}
return success;
@@ -1300,7 +1304,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (totalBytes > bytes) {
for (ORKDataLogger *logger in [_records allValues]) {
for (ORKDataLogger *logger in _records.allValues) {
[logger enumerateLogsAlreadyUploaded:^(NSURL *logFileUrl, BOOL *stop) {
unsigned long long fileSize = [[fileManager attributesOfItemAtPath:[logFileUrl path] error:nil] fileSize];
if (fileSize > 0) {
@@ -1353,7 +1357,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
- (void)queue_updateBytes {
unsigned long long pending = 0;
unsigned long long uploaded = 0;
for (ORKDataLogger *logger in [_records allValues]) {
for (ORKDataLogger *logger in _records.allValues) {
pending += logger.pendingBytes;
uploaded += logger.uploadedBytes;
}
@@ -1367,14 +1371,14 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (exceededPendingThreshold && !_pendingUploadDelegateSent) {
[self.delegate dataLoggerManager:self pendingUploadBytesReachedThreshold:pending];
_pendingUploadDelegateSent = YES;
} else if (! exceededPendingThreshold) {
} else if (!exceededPendingThreshold) {
_pendingUploadDelegateSent = NO;
}
if (exceededTotalThreshold && !_totalBytesDelegateSent) {
[self.delegate dataLoggerManager:self totalBytesReachedThreshold:(pending + uploaded)];
_totalBytesDelegateSent = YES;
} else if (! exceededTotalThreshold) {
} else if (!exceededTotalThreshold) {
_totalBytesDelegateSent = NO;
}
}
@@ -84,17 +84,17 @@
- (void)start {
[super start];
if (! _logger) {
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (! _logger) {
if (!_logger) {
[self finishRecordingWithError:err];
return;
}
}
self.motionManager = [self createMotionManager];
self.motionManager.deviceMotionUpdateInterval = 1.0/_frequency;
self.motionManager.deviceMotionUpdateInterval = 1.0 / _frequency;
self.uptime = [NSProcessInfo processInfo].systemUptime;
@@ -165,11 +165,6 @@
@end
@interface ORKDeviceMotionRecorderConfiguration ()
@end
@implementation ORKDeviceMotionRecorderConfiguration
#pragma clang diagnostic push
+70 -64
View File
@@ -48,8 +48,6 @@
ORKTintedImageView *_imageView;
NSLengthFormatter *_lengthFormatter;
NSLayoutConstraint *_imageRatioConstraint;
ORKScreenType _screenType;
NSArray *_constraints;
NSLayoutConstraint *_topConstraint;
}
@@ -69,13 +67,12 @@
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_screenType = ORKScreenTypeiPhone4;
_timerLabel = [ORKQuantityLabel new];
_quantityPairView = [ORKQuantityPairView new];
_imageSpacer1 = [UIView new];
[_imageSpacer1 setTranslatesAutoresizingMaskIntoConstraints:NO];
_imageSpacer1.translatesAutoresizingMaskIntoConstraints = NO;
_imageSpacer2 = [UIView new];
[_imageSpacer2 setTranslatesAutoresizingMaskIntoConstraints:NO];
_imageSpacer2.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_imageSpacer1];
[self addSubview:_imageSpacer2];
[self heartRateView].image = [UIImage imageNamed:@"heart-fitness" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
@@ -96,7 +93,7 @@
self.hasDistance = _hasDistance;
#if LAYOUT_TEST
self.timeLeft = 60*5;
self.timeLeft = 60 * 5;
self.hasHeartRate = YES;
self.hasDistance = YES;
self.distanceInMeters = 100;
@@ -113,7 +110,7 @@
[self addSubview:_quantityPairView];
[self addSubview:_imageView];
[self addSubview:_timerLabel];
[self setupConstraints];
[self setUpConstraints];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localeDidChange:) name:NSCurrentLocaleDidChangeNotification object:nil];
@@ -139,105 +136,114 @@
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
_screenType = ORKGetVerticalScreenTypeForWindow(newWindow);
[self updateConstraintConstants];
[self updateConstraintConstantsForWindow:newWindow];
}
- (void)updateConstraintConstants {
ORKScreenType screenType = _screenType;
const CGFloat CaptionBaselineToTimerTop = ORKGetMetricForScreenType(ORKScreenMetricCaptionBaselineToFitnessTimerTop, screenType);
const CGFloat CaptionBaselineToStepViewTop = ORKGetMetricForScreenType(ORKScreenMetricLearnMoreBaselineToStepViewTop, screenType);
- (void)updateConstraintConstantsForWindow:(UIWindow *)window {
const CGFloat CaptionBaselineToTimerTop = ORKGetMetricForWindow(ORKScreenMetricCaptionBaselineToFitnessTimerTop, window);
const CGFloat CaptionBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window);
_topConstraint.constant = (CaptionBaselineToTimerTop - CaptionBaselineToStepViewTop);
}
- (void)setupConstraints {
- (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]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_timerLabel][_imageSpacer1(>=0)][_imageView]"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
_topConstraint = [NSLayoutConstraint constraintWithItem:_timerLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:0];
[self updateConstraintConstants];
multiplier:1.0
constant:0.0];
[constraints addObject:_topConstraint];
[constraints addObject:[NSLayoutConstraint
constraintWithItem:_timerLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_timerLabel
attribute: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
constant:0]];
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
multiplier:1.0
constant:0.0]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_imageView][_imageSpacer2(>=0)][_quantityPairView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_imageView][_imageSpacer2(>=0)][_quantityPairView]|"
options:0
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:0]];
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:0]];
multiplier:1.0
constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_imageSpacer2
attribute:NSLayoutAttributeHeight
multiplier:1
constant:0]];
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_imageSpacer1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:1000];
constraint1.priority = UILayoutPriorityDefaultLow-1;
[constraints addObject:constraint1];
multiplier:1.0
constant:0.0]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_quantityPairView]|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
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];
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:self
[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
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
maxWidthConstraint.priority = UILayoutPriorityRequired-1;
maxWidthConstraint.priority = UILayoutPriorityRequired - 1;
[constraints addObject:maxWidthConstraint];
[self addConstraints:constraints];
[NSLayoutConstraint activateConstraints:constraints];
[self updateConstraintConstantsForWindow:self.window];
}
- (void)setImage:(UIImage *)image {
@@ -253,8 +259,8 @@
relatedBy:NSLayoutRelationEqual
toItem:_imageView
attribute:NSLayoutAttributeWidth
multiplier:size
.height/size.width constant:0];
multiplier:size.height / size.width
constant:0.0];
_imageRatioConstraint.active = YES;
}
}
@@ -277,7 +283,7 @@
}
- (void)updateKeylineVisible {
[_quantityPairView setKeylineHidden:! (_hasDistance && _hasHeartRate)];
[_quantityPairView setKeylineHidden:!(_hasDistance && _hasHeartRate)];
}
- (void)setDistanceInMeters:(double)distanceInMeters {
@@ -304,7 +310,7 @@
double conversionFactor = 1.0;
if ([hkUnit isNull] && (unit == NSLengthFormatterUnitYard)) {
hkUnit = [HKUnit footUnit];
conversionFactor = 1/3.0;
conversionFactor = 1.0 / 3.0;
}
HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit meterUnit] doubleValue:displayDistance];
distanceString = [_lengthFormatter.numberFormatter stringFromNumber:@([quantity doubleValueForUnit:hkUnit]*conversionFactor)];
+2 -2
View File
@@ -52,8 +52,8 @@
NSTimeInterval const ORKFitnessStepMinimumDuration = 5.0;
if ( self.stepDuration < ORKFitnessStepMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"rest duration can not be shorter than %@ seconds.", @(ORKFitnessStepMinimumDuration)] userInfo:nil];
if (self.stepDuration < ORKFitnessStepMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"rest duration cannot be shorter than %@ seconds.", @(ORKFitnessStepMinimumDuration)] userInfo:nil];
}
}
@@ -91,7 +91,7 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
- (void)query_logResults:(NSArray *)results withAnchor:(NSUInteger)newAnchor {
NSUInteger resultCount = [results count];
NSUInteger resultCount = results.count;
if (resultCount == 0) {
return;
}
@@ -103,10 +103,10 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateMostRecentSample:[results lastObject]];
[self updateMostRecentSample:results.lastObject];
NSError *error = nil;
if (! [_logger appendObjects:dictionaries error:&error]) {
if (![_logger appendObjects:dictionaries error:&error]) {
// Logger writes are unrecoverable
[self finishRecordingWithError:error];
return;
@@ -122,7 +122,7 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
- (void)doFetchNewData {
if (! _healthStore || ! _isRecording) {
if (!_healthStore || !_isRecording) {
return;
}
NSAssert(_samplePredicate != nil, @"Sample predicate should be non-nil if recording");
@@ -137,7 +137,7 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
{
if (error) {
// An error in the query's not the end of the world: we'll probably get another chance. Just log it.
ORK_Log_Debug(@"Anchored query error: %@", error);
ORK_Log_Warning(@"Anchored query error: %@", error);
return;
}
@@ -151,16 +151,16 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
- (void)start {
[super start];
if (! _logger) {
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (! _logger) {
if (!_logger) {
[self finishRecordingWithError:err];
return;
}
}
if (! [HKHealthStore isHealthDataAvailable]) {
if (![HKHealthStore isHealthDataAvailable]) {
[self finishRecordingWithError:[NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}]];
@@ -178,16 +178,6 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
}
[_healthStore enableBackgroundDeliveryForType:_quantityType
frequency:HKUpdateFrequencyImmediate
withCompletion:^(BOOL success, NSError *error) {
// Doesn't really matter if this succeeds, but nice if it does.
if (! success) {
ORK_Log_Debug(@"Failed to enable background delivery: %@", error);
}
}];
_lastSample = nil;
_samplePredicate = [HKQuery predicateForSamplesWithStartDate:[NSDate date] endDate:nil options:HKQueryOptionStrictStartDate];
@@ -222,7 +212,7 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
- (void)stop {
if (! _isRecording) {
if (!_isRecording) {
return;
}
@@ -275,11 +265,6 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
@end
@interface ORKHealthQuantityTypeRecorderConfiguration ()
@end
@implementation ORKHealthQuantityTypeRecorderConfiguration
#pragma clang diagnostic push
@@ -0,0 +1,64 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@protocol ORKHolePegTestPlaceContentViewDelegate;
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceContentView : ORKActiveStepCustomView
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE;
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
- (instancetype)initWithMovingDirection:(ORKBodySagittal)movingDirection rotated:(BOOL)rotated NS_DESIGNATED_INITIALIZER;
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign) double threshold;
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@property (nonatomic, weak) id<ORKHolePegTestPlaceContentViewDelegate> delegate;
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated;
@end
@protocol ORKHolePegTestPlaceContentViewDelegate <NSObject>
- (void)holePegTestPlaceDidProgress:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView;
- (void)holePegTestPlaceDidSucceed:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView withDistance:(CGFloat)distance;
- (void)holePegTestPlaceDidFail:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,397 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKHolePegTestPlacePegView.h"
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKDirectionView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
static const CGFloat ORKOrientationThreshold = 12.0f;
static const CGFloat ORKHolePegViewDiameter = 88.0f;
#define degreesToRadians(degrees) ((degrees) / 180.0 * M_PI)
@interface ORKHolePegTestPlaceContentView () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) ORKHolePegTestPlacePegView *pegView;
@property (nonatomic, strong) ORKHolePegTestPlaceHoleView *holeView;
@property (nonatomic, strong) ORKDirectionView *directionView;
@property (nonatomic, copy) NSArray *constraints;
@property (nonatomic, strong) UIPinchGestureRecognizer *pinchRecognizer;
@property (nonatomic, strong) UIPanGestureRecognizer *panRecognizer;
@property (nonatomic, strong) UIRotationGestureRecognizer *rotationRecognizer;
@property (nonatomic, assign, getter = isMovable) BOOL movable;
@property (nonatomic, assign, getter = hasMoveEnded) BOOL moveEnded;
@property (nonatomic, assign) CGFloat rotation;
@property (nonatomic, assign) CGFloat rotationOffset;
@property (nonatomic, assign) CGPoint translation;
@property (nonatomic, assign) CGPoint translationOffset;
@property (nonatomic, assign) CGPoint startPoint;
@end
@implementation ORKHolePegTestPlaceContentView
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithFrame:(CGRect)frame {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithMovingDirection:(ORKBodySagittal)movingDirection rotated:(BOOL)rotated {
self = [super initWithFrame:CGRectZero];
if (self) {
self.movingDirection = movingDirection;
self.rotated = rotated;
self.progressView = [UIProgressView new];
self.progressView.progressTintColor = self.tintColor;
[self.progressView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.progressView setAlpha:0];
[self addSubview:self.progressView];
self.holeView = [[ORKHolePegTestPlaceHoleView alloc] initWithFrame:CGRectMake(0, 0, ORKHolePegViewDiameter, ORKHolePegViewDiameter)];
self.holeView.rotated = self.isRotated;
[self.holeView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.holeView];
self.pegView = [[ORKHolePegTestPlacePegView alloc] initWithFrame:CGRectMake(0, 0, ORKHolePegViewDiameter, ORKHolePegViewDiameter)];
self.pegView.rotated = self.isRotated;
[self.pegView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.pegView];
self.directionView = [[ORKDirectionView alloc] initWithOrientation:(self.movingDirection == ORKBodySagittalLeft) ? ORKBodySagittalRight : ORKBodySagittalLeft];
[self.directionView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.directionView];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
[self setNeedsUpdateConstraints];
self.movable = NO;
self.moveEnded = NO;
self.startPoint = CGPointZero;
self.pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePinch:)];
self.pinchRecognizer.delegate = self;
[self addGestureRecognizer:self.pinchRecognizer];
self.panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePan:)];
self.panRecognizer.delegate = self;
[self addGestureRecognizer:self.panRecognizer];
if (rotated) {
self.rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self
action:@selector(handleRotate:)];
self.rotationRecognizer.delegate = self;
[self addGestureRecognizer:self.rotationRecognizer];
}
}
return self;
}
- (void)tintColorDidChange {
[super tintColorDidChange];
self.progressView.progressTintColor = self.tintColor;
}
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated {
[self.progressView setProgress:progress animated:animated];
[UIView animateWithDuration:animated ? 0.2 : 0 animations:^{
[self.progressView setAlpha:(progress == 0) ? 0 : 1];
}];
}
- (void)updateLayoutMargins {
CGFloat margin = ORKStandardHorizontalMarginForView(self);
self.layoutMargins = (UIEdgeInsets){.left = margin * 2, .right = margin * 2};
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self updateLayoutMargins];
}
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
[self updateLayoutMargins];
}
- (void)updateConstraints {
if ([self.constraints count]) {
[NSLayoutConstraint deactivateConstraints:self.constraints];
self.constraints = nil;
}
NSMutableArray *constraintsArray = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _pegView, _holeView, _directionView);
NSDictionary *metrics = @{@"diameter" : @(ORKHolePegViewDiameter)};
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:(self.movingDirection == ORKBodySagittalLeft) ? @"H:|-[_pegView]->=0-[_holeView]-|" : @"H:|-[_holeView]->=0-[_pegView]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_progressView]"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|->=0-[_pegView(diameter)]->=0-|"
options:(NSLayoutFormatOptions)0
metrics:metrics views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|->=0-[_holeView]->=0-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.pegView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.directionView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.directionView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0]];
self.constraints = constraintsArray;
[self addConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:self.constraints];
[super updateConstraints];
}
#pragma mark - gesture recognizer methods
- (void)pickupPegWithGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
CGPoint touch = [gestureRecognizer locationInView:self];
CGPoint touch1 = [gestureRecognizer locationOfTouch:0 inView:self];
CGPoint touch2 = [gestureRecognizer locationOfTouch:1 inView:self];
double distance = hypot(touch1.x - touch2.x, touch1.y - touch2.y);
if (distance < 3 * CGRectGetWidth(self.pegView.frame) &&
CGRectContainsPoint(self.pegView.frame, touch)) {
self.movable = YES;
} else {
self.movable = NO;
}
}
- (void)handlePinch:(UIPinchGestureRecognizer *)pinchGestureRecognizer {
if ([pinchGestureRecognizer numberOfTouches] == 2) {
[self pickupPegWithGestureRecognizer:pinchGestureRecognizer];
}
}
- (void)handlePan:(UIPanGestureRecognizer *)panGestureRecognizer {
if ([panGestureRecognizer numberOfTouches] != 2 ||
panGestureRecognizer.state == UIGestureRecognizerStateEnded ||
panGestureRecognizer.state == UIGestureRecognizerStateCancelled ||
panGestureRecognizer.state == UIGestureRecognizerStateFailed) {
[self resetTransformAtPoint:[panGestureRecognizer locationInView:self]];
} else {
if (self.isMovable) {
self.translation = CGPointMake([panGestureRecognizer translationInView:self].x - self.translationOffset.x,
[panGestureRecognizer translationInView:self].y - self.translationOffset.y);
[self updateTransformAtPoint:[panGestureRecognizer locationInView:self]];
} else {
self.translationOffset = CGPointMake([panGestureRecognizer translationInView:self].x - self.translation.x,
[panGestureRecognizer translationInView:self].y - self.translation.y);
if (CGPointEqualToPoint(self.startPoint, CGPointZero)) {
[self pickupPegWithGestureRecognizer:panGestureRecognizer];
}
}
}
}
- (void)handleRotate:(UIRotationGestureRecognizer *)rotationGestureRecognizer {
if ([rotationGestureRecognizer numberOfTouches] != 2 ||
rotationGestureRecognizer.state == UIGestureRecognizerStateEnded ||
rotationGestureRecognizer.state == UIGestureRecognizerStateCancelled ||
rotationGestureRecognizer.state == UIGestureRecognizerStateFailed) {
[self resetTransformAtPoint:[rotationGestureRecognizer locationInView:self]];
} else {
if (self.isMovable) {
self.rotation = rotationGestureRecognizer.rotation - self.rotationOffset;
[self updateTransformAtPoint:[rotationGestureRecognizer locationInView:self]];
} else {
self.rotationOffset = rotationGestureRecognizer.rotation - self.rotation;
}
}
}
- (void)updateTransformAtPoint:(CGPoint)point {
self.pegView.transform = CGAffineTransformMakeTranslation(self.translation.x, self.translation.y);
self.pegView.transform = CGAffineTransformRotate(self.pegView.transform, self.rotation);
[self pegViewDidMoveAtPoint:point];
}
- (void)resetTransformAtPoint:(CGPoint)point {
if (!self.hasMoveEnded) {
self.movable = NO;
self.moveEnded = YES;
self.pinchRecognizer.enabled = NO;
self.panRecognizer.enabled = NO;
self.rotationRecognizer.enabled = NO;
BOOL animated = ![self pegViewMoveDidEndAtPoint:point];
self.pegView.hidden = !animated;
[UIView animateWithDuration:animated ? 0.15f : 0.0f
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^(){
self.pegView.transform = CGAffineTransformIdentity;
self.pegView.alpha = 1.0f;
}
completion:^(BOOL finished){
self.rotation = 0.0f;
self.rotationOffset = 0.0f;
self.translation = CGPointZero;
self.translationOffset = CGPointZero;
self.pinchRecognizer.enabled = YES;
self.panRecognizer.enabled = YES;
self.rotationRecognizer.enabled = YES;
self.moveEnded = NO;
self.pegView.hidden = NO;
}];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
#pragma mark - peg view delegate
- (void)pegViewDidMoveAtPoint:(CGPoint)point {
self.directionView.hidden = YES;
if (CGPointEqualToPoint(self.startPoint, CGPointZero)) {
self.startPoint = point;
}
if ([self.delegate respondsToSelector:@selector(holePegTestPlaceDidProgress:)]) {
[self.delegate holePegTestPlaceDidProgress:self];
}
if (self.holeView.isSuccess) {
self.holeView.success = NO;
}
if ([self holeViewContainsPegView]) {
self.pegView.alpha = 1.0f;
} else {
self.pegView.alpha = 0.2f;
}
}
- (BOOL)pegViewMoveDidEndAtPoint:(CGPoint)point {
self.directionView.hidden = NO;
BOOL succeeded = NO;
if ([self holeViewContainsPegView]) {
if ([self.delegate respondsToSelector:@selector(holePegTestPlaceDidSucceed:withDistance:)]) {
CGFloat distance = hypotf(point.x - self.startPoint.x, point.y - self.startPoint.y);
[self.delegate holePegTestPlaceDidSucceed:self withDistance:distance];
}
self.holeView.success = YES;
succeeded = YES;
} else {
if ([self.delegate respondsToSelector:@selector(holePegTestPlaceDidFail:)]) {
[self.delegate holePegTestPlaceDidFail:self];
}
self.holeView.success = NO;
}
self.startPoint = CGPointZero;
return succeeded;
}
- (BOOL)holeViewContainsPegView {
CGRect detectionFrame = CGRectMake(CGRectGetMidX(self.holeView.frame) - (self.threshold * CGRectGetWidth(self.holeView.frame) / 2),
CGRectGetMidY(self.holeView.frame) - (self.threshold * CGRectGetHeight(self.holeView.frame) / 2),
self.threshold * CGRectGetWidth(self.holeView.frame),
self.threshold * CGRectGetHeight(self.holeView.frame));
CGPoint pegCenter = CGPointMake(CGRectGetMaxX(self.pegView.frame) - CGRectGetWidth(self.pegView.frame) / 2,
CGRectGetMaxY(self.pegView.frame) - CGRectGetHeight(self.pegView.frame) / 2);
if (CGRectContainsPoint(detectionFrame, pegCenter)) {
if (self.isRotated) {
double rotation = atan2(self.pegView.transform.b, self.pegView.transform.a);
double angle = fmod(fabs(rotation), M_PI_2);
if (angle > M_PI_4 - degreesToRadians(ORKOrientationThreshold) &&
angle < M_PI_4 + degreesToRadians(ORKOrientationThreshold)) {
return YES;
}
} else {
return YES;
}
}
return NO;
}
@end
@@ -0,0 +1,45 @@
/*
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 <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceHoleView : UIView
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@property (nonatomic, assign, getter = isSuccess) BOOL success;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,171 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlaceHoleView.h"
static const CGFloat ORKPlaceHoleViewRotation = 45.0f;
@interface ORKHolePegTestPlaceHoleView ()
@property (nonatomic, strong) CAShapeLayer *checkLayer;
@property (nonatomic, strong) CAShapeLayer *crossLayer;
@end
@implementation ORKHolePegTestPlaceHoleView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(27.7f, 46.9f)];
[path addLineToPoint:CGPointMake(36.1f, 56.3f)];
[path addLineToPoint:CGPointMake(62.8f, 30.3f)];
path.lineCapStyle = kCGLineCapRound;
path.lineWidth = 3.6f;
CAShapeLayer *checkLayer = [CAShapeLayer new];
checkLayer.path = path.CGPath;
checkLayer.lineWidth = 3.6f;
checkLayer.lineCap = kCALineCapRound;
checkLayer.lineJoin = kCALineJoinRound;
checkLayer.frame = self.layer.bounds;
checkLayer.strokeColor = self.tintColor.CGColor;
checkLayer.backgroundColor = [UIColor clearColor].CGColor;
checkLayer.fillColor = nil;
self.checkLayer = checkLayer;
self.opaque = NO;
self.success = NO;
}
return self;
}
- (CGSize)intrinsicContentSize {
return CGSizeMake(self.frame.size.width, self.frame.size.height);
}
#pragma mark - drawing method
- (void)tintColorDidChange {
[super tintColorDidChange];
self.checkLayer.strokeColor = self.tintColor.CGColor;
[self setNeedsDisplay];
}
- (void)setSuccess:(BOOL)success
{
_success = success;
[self.checkLayer removeFromSuperlayer];
[self.crossLayer removeFromSuperlayer];
[self setNeedsDisplay];
}
- (void)setRotated:(BOOL)rotated
{
_rotated = rotated;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGRect bounds = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(bounds, 1.0f, 1.0f)];
path.lineWidth = 2.0f;
[self.tintColor setStroke];
[path stroke];
if (self.isSuccess) {
[self.layer addSublayer:self.checkLayer];
CAMediaTimingFunction *timing = [[CAMediaTimingFunction alloc] initWithControlPoints:0.180739998817444
:0
:0.577960014343262
:0.918200016021729];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[animation setTimingFunction:timing];
[animation setFillMode:kCAFillModeBoth];
animation.fromValue = @(0);
animation.toValue = @(1);
animation.duration = 0.3f;
animation.delegate = self;
[self.checkLayer addAnimation:animation forKey:@"strokeEnd"];
} else if (self.isRotated) {
UIBezierPath *crossPath = [[UIBezierPath alloc] init];
[crossPath moveToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 1/4)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 7/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 1/4, CGRectGetHeight(bounds) * 7/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 1/4, CGRectGetHeight(bounds) * 9/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 9/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 3/4)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 3/4)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 9/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 3/4, CGRectGetHeight(bounds) * 9/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 3/4, CGRectGetHeight(bounds) * 7/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 7/16)];
[crossPath addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 1/4)];
[crossPath closePath];
CAShapeLayer *crossLayer = [[CAShapeLayer alloc] init];
crossLayer.path = crossPath.CGPath;
crossLayer.bounds = CGPathGetBoundingBox(crossLayer.path);
crossLayer.anchorPoint = CGPointMake(0.5, 0.5);
crossLayer.fillColor = self.tintColor.CGColor;
CATransform3D transform = CATransform3DMakeTranslation(CGRectGetMidX(bounds), CGRectGetMidY(bounds), 1);
transform = CATransform3DRotate(transform, ORKPlaceHoleViewRotation * (M_PI / 180), 0, 0, 1);
crossLayer.transform = transform;
self.crossLayer = crossLayer;
[self.layer addSublayer:self.crossLayer];
}
CGContextRestoreGState(context);
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
typeof(self) strongSelf = weakSelf;
strongSelf.success = NO;
});
}
@end
@@ -0,0 +1,44 @@
/*
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 <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlacePegView : UIView
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,93 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlacePegView.h"
@implementation ORKHolePegTestPlacePegView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.opaque = NO;
}
return self;
}
- (CGSize)intrinsicContentSize {
return CGSizeMake(self.frame.size.width, self.frame.size.height);
}
#pragma mark - drawing method
- (void)tintColorDidChange {
[super tintColorDidChange];
[self setNeedsDisplay];
}
- (void)setRotated:(BOOL)rotated
{
_rotated = rotated;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGRect bounds = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:bounds];
if (self.isRotated) {
[path moveToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 1/4)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 7/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 1/4, CGRectGetHeight(bounds) * 7/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 1/4, CGRectGetHeight(bounds) * 9/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 9/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 7/16, CGRectGetHeight(bounds) * 3/4)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 3/4)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 9/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 3/4, CGRectGetHeight(bounds) * 9/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 3/4, CGRectGetHeight(bounds) * 7/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 7/16)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(bounds) * 9/16, CGRectGetHeight(bounds) * 1/4)];
[path closePath];
}
[self.tintColor setFill];
[path fill];
CGContextRestoreGState(context);
}
@end
@@ -0,0 +1,48 @@
/*
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 <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceStep : ORKActiveStep
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign, getter = isDominantHandTested) BOOL dominantHandTested;
@property (nonatomic, assign) int numberOfPegs;
@property (nonatomic, assign) double threshold;
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,84 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlaceStep.h"
#import "ORKHolePegTestPlaceStepViewController.h"
@implementation ORKHolePegTestPlaceStep
+ (Class)stepViewControllerClass {
return [ORKHolePegTestPlaceStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
self.shouldContinueOnFinish = YES;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
int const ORKHolePegTestMinimumNumberOfPegs = 1;
double const ORKHolePegTestMinimumThreshold = 0.0f;
double const ORKHolePegTestMaximumThreshold = 1.0f;
NSTimeInterval const ORKHolePegTestMinimumDuration = 1.0f;
if (self.movingDirection != ORKBodySagittalLeft &&
self.movingDirection != ORKBodySagittalRight) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"moving direction should be left or right."] userInfo:nil];
}
if (self.numberOfPegs < ORKHolePegTestMinimumNumberOfPegs) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"number of pegs must be greater than or equal to %@.", @(ORKHolePegTestMinimumNumberOfPegs)] userInfo:nil];
}
if (self.threshold < ORKHolePegTestMinimumThreshold ||
self.threshold > ORKHolePegTestMaximumThreshold) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"threshold must be greater than or equal to %@ and lower or equal to %@.", @(ORKHolePegTestMinimumThreshold), @(ORKHolePegTestMaximumThreshold)] userInfo:nil];
}
if (self.stepDuration < ORKHolePegTestMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
}
}
- (BOOL)allowsBackNavigation {
return NO;
}
@end
@@ -0,0 +1,42 @@
/*
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 <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,173 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestPlaceStepViewController.h"
#import "ORKHolePegTestPlaceStep.h"
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKActiveStepViewController_internal.h"
#import "ORKStepViewController_internal.h"
#import "ORKActiveStepView.h"
@interface ORKHolePegTestPlaceStepViewController () <ORKHolePegTestPlaceContentViewDelegate>
@property (nonatomic, strong) NSMutableArray *samples;
@property (nonatomic, strong) ORKHolePegTestPlaceContentView *holePegTestPlaceContentView;
@property (nonatomic, assign) NSTimeInterval sampleStart;
@property (nonatomic, assign) NSUInteger successes;
@property (nonatomic, assign) NSUInteger failures;
@end
@implementation ORKHolePegTestPlaceStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = YES;
}
return self;
}
- (ORKHolePegTestPlaceStep *)holePegTestPlaceStep {
return (ORKHolePegTestPlaceStep *)self.step;
}
- (void)initializeInternalButtonItems {
[super initializeInternalButtonItems];
// Don't show next button
self.internalContinueButtonItem = nil;
self.internalDoneButtonItem = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.holePegTestPlaceContentView = [[ORKHolePegTestPlaceContentView alloc] initWithMovingDirection:[self holePegTestPlaceStep].movingDirection
rotated:[self holePegTestPlaceStep].rotated];
self.holePegTestPlaceContentView.threshold = [self holePegTestPlaceStep].threshold;
self.holePegTestPlaceContentView.delegate = self;
self.activeStepView.activeCustomView = self.holePegTestPlaceContentView;
self.activeStepView.stepViewFillsAvailableSpace = YES;
}
#pragma mark - step life cycle methods
- (void)start {
self.successes = 0;
self.failures = 0;
self.samples = [NSMutableArray array];
[self.holePegTestPlaceContentView setProgress:0.001f animated:NO];
[super start];
}
#pragma mark - result methods
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKHolePegTestResult *holePegTestResult = [[ORKHolePegTestResult alloc] initWithIdentifier:self.step.identifier];
holePegTestResult.movingDirection = [self holePegTestPlaceStep].movingDirection;
holePegTestResult.dominantHandTested = [self holePegTestPlaceStep].isDominantHandTested;
holePegTestResult.numberOfPegs = [self holePegTestPlaceStep].numberOfPegs;
holePegTestResult.threshold = [self holePegTestPlaceStep].threshold;
holePegTestResult.rotated = [self holePegTestPlaceStep].isRotated;
holePegTestResult.totalSuccesses = self.successes;
holePegTestResult.totalFailures = self.failures;
holePegTestResult.totalTime = [self holePegTestPlaceStep].stepDuration - self.timeRemaining;
double totalDistance = 0.0;
for (ORKHolePegTestSample *sample in self.samples) {
totalDistance += sample.distance;
}
holePegTestResult.totalDistance = totalDistance;
holePegTestResult.samples = self.samples;
[results addObject:holePegTestResult];
sResult.results = [results copy];
return sResult;
}
- (void)saveSampleWithDistance:(CGFloat)distance {
ORKHolePegTestSample *sample = [[ORKHolePegTestSample alloc] init];
sample.time = CACurrentMediaTime() - self.sampleStart;
sample.distance = distance;
self.sampleStart = CACurrentMediaTime();
[self.samples addObject:sample];
}
#pragma mark - hole peg test content view delegate
- (NSString *)stepTitle {
NSString *title = ([self holePegTestPlaceStep].movingDirection == ORKBodySagittalLeft) ? ORKLocalizedString(@"HOLE_PEG_TEST_PLACE_INSTRUCTION_LEFT_HAND", nil) : ORKLocalizedString(@"HOLE_PEG_TEST_PLACE_INSTRUCTION_RIGHT_HAND", nil);
return title;
}
- (void)holePegTestPlaceDidProgress:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView {
if (!self.isStarted) {
self.sampleStart = CACurrentMediaTime();
[self start];
}
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT_2", nil)];
}
- (void)holePegTestPlaceDidSucceed:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView withDistance:(CGFloat)distance {
self.successes++;
[self saveSampleWithDistance:distance];
[holePegTestPlaceContentView setProgress:((CGFloat)self.successes / [self holePegTestPlaceStep].numberOfPegs) animated:YES];
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)];
if (self.successes >= [self holePegTestPlaceStep].numberOfPegs) {
[((ORKNavigableOrderedTask *)self.taskViewController.task) removeNavigationRuleForTriggerStepIdentifier:[self holePegTestPlaceStep].identifier];
[self finish];
}
}
- (void)holePegTestPlaceDidFail:(ORKHolePegTestPlaceContentView *)holePegTestPlaceContentView {
self.failures++;
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)];
}
@end
@@ -0,0 +1,63 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@protocol ORKHolePegTestRemoveContentViewDelegate;
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemoveContentView : ORKActiveStepCustomView
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE;
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
- (instancetype)initWithMovingDirection:(ORKBodySagittal)movingDirection NS_DESIGNATED_INITIALIZER;
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign) double threshold;
@property (nonatomic, weak) id<ORKHolePegTestRemoveContentViewDelegate> delegate;
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated;
@end
@protocol ORKHolePegTestRemoveContentViewDelegate <NSObject>
- (void)holePegTestRemoveDidProgress:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView;
- (void)holePegTestRemoveDidSucceed:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView withDistance:(CGFloat)distance;
- (void)holePegTestRemoveDidFail:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,356 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKHolePegTestRemovePegView.h"
#import "ORKSeparatorView.h"
#import "ORKDirectionView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
static const CGFloat PegViewDiameter = 88.0f;
static const CGFloat PegViewSeparatorWidth = 2.0f;
@interface ORKHolePegTestRemoveContentView () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) ORKHolePegTestRemovePegView *pegView;
@property (nonatomic, strong) ORKSeparatorView *separatorView;
@property (nonatomic, strong) ORKDirectionView *directionView;
@property (nonatomic, strong) UIView *container;
@property (nonatomic, copy) NSArray *constraints;
@property (nonatomic, strong) UIPinchGestureRecognizer *pinchRecognizer;
@property (nonatomic, strong) UIPanGestureRecognizer *panRecognizer;
@property (nonatomic, assign, getter = isMovable) BOOL movable;
@property (nonatomic, assign, getter = hasMoveEnded) BOOL moveEnded;
@property (nonatomic, assign) CGPoint translation;
@property (nonatomic, assign) CGPoint translationOffset;
@property (nonatomic, assign) CGPoint startPoint;
@end
@implementation ORKHolePegTestRemoveContentView
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithFrame:(CGRect)frame {
ORKThrowMethodUnavailableException();
}
- (instancetype)initWithMovingDirection:(ORKBodySagittal)movingDirection {
self = [super initWithFrame:CGRectZero];
if (self) {
self.movingDirection = movingDirection;
self.opaque = NO;
self.container = [UIView new];
self.container.translatesAutoresizingMaskIntoConstraints = NO;
self.progressView = [UIProgressView new];
self.progressView.progressTintColor = self.tintColor;
[self.progressView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.progressView setAlpha:0];
[self addSubview:self.progressView];
self.pegView = [[ORKHolePegTestRemovePegView alloc] initWithFrame:CGRectMake(0, 0, PegViewDiameter, PegViewDiameter)];
[self.pegView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.container addSubview:self.pegView];
self.separatorView = [[ORKSeparatorView alloc] init];
[self.separatorView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.container addSubview:self.separatorView];
self.directionView = [[ORKDirectionView alloc] initWithOrientation:(self.movingDirection == ORKBodySagittalLeft) ? ORKBodySagittalRight : ORKBodySagittalLeft];
[self.directionView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.directionView];
[self addSubview:self.container];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
[self setNeedsUpdateConstraints];
self.movable = NO;
self.moveEnded = NO;
self.startPoint = CGPointZero;
self.pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePinch:)];
self.pinchRecognizer.delegate = self;
[self addGestureRecognizer:self.pinchRecognizer];
self.panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePan:)];
self.panRecognizer.delegate = self;
[self addGestureRecognizer:self.panRecognizer];
}
return self;
}
- (void)tintColorDidChange {
[super tintColorDidChange];
self.progressView.progressTintColor = self.tintColor;
}
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated {
[self.progressView setProgress:progress animated:animated];
[UIView animateWithDuration:animated ? 0.2 : 0 animations:^{
[self.progressView setAlpha:(progress == 0) ? 0 : 1];
}];
}
- (void)updateLayoutMargins {
CGFloat margin = ORKStandardHorizontalMarginForView(self);
self.layoutMargins = (UIEdgeInsets){.left = margin * 2, .right = margin * 2};
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self updateLayoutMargins];
}
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
[self updateLayoutMargins];
}
- (void)updateConstraints {
if ([self.constraints count]) {
[NSLayoutConstraint deactivateConstraints:self.constraints];
self.constraints = nil;
}
NSMutableArray *constraintsArray = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _container, _pegView, _separatorView, _directionView);
NSDictionary *metrics = @{@"diameter" : @(PegViewDiameter), @"separator" : @(PegViewSeparatorWidth), @"margin" : @((1 + self.threshold) * PegViewDiameter)};
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:(self.movingDirection == ORKBodySagittalLeft) ? @"H:|-[_pegView(diameter)]->=0-[_separatorView(separator)]-(margin)-|" : @"H:|-(margin)-[_separatorView(separator)]->=0-[_pegView(diameter)]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:metrics views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_container]|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=0)-[_pegView(diameter)]-(>=0)-|"
options:(NSLayoutFormatOptions)0
metrics:metrics views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_separatorView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_progressView][_container]|"
options:(NSLayoutFormatOptions)0
metrics:metrics views:views]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.directionView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:self.directionView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0]];
self.constraints = constraintsArray;
[self addConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:self.constraints];
[super updateConstraints];
}
#pragma mark - gesture recognizer methods
- (void)pickupPegWithGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
CGPoint touch = [gestureRecognizer locationInView:self];
CGPoint touch1 = [gestureRecognizer locationOfTouch:0 inView:self];
CGPoint touch2 = [gestureRecognizer locationOfTouch:1 inView:self];
double distance = hypot(touch1.x - touch2.x, touch1.y - touch2.y);
if (distance < 3 * CGRectGetWidth(self.pegView.frame) &&
CGRectContainsPoint(self.pegView.frame, touch)) {
self.movable = YES;
} else {
self.movable = NO;
}
}
- (void)handlePinch:(UIPinchGestureRecognizer *)pinchGestureRecognizer {
if ([pinchGestureRecognizer numberOfTouches] == 2) {
[self pickupPegWithGestureRecognizer:pinchGestureRecognizer];
}
}
- (void)handlePan:(UIPanGestureRecognizer *)panGestureRecognizer {
if ([panGestureRecognizer numberOfTouches] != 2 ||
panGestureRecognizer.state == UIGestureRecognizerStateEnded ||
panGestureRecognizer.state == UIGestureRecognizerStateCancelled ||
panGestureRecognizer.state == UIGestureRecognizerStateFailed) {
[self resetTransformAtPoint:[panGestureRecognizer locationInView:self]];
} else {
if (self.isMovable) {
self.translation = CGPointMake([panGestureRecognizer translationInView:self].x - self.translationOffset.x,
[panGestureRecognizer translationInView:self].y - self.translationOffset.y);
[self updateTransformAtPoint:[panGestureRecognizer locationInView:self]];
} else {
self.translationOffset = CGPointMake([panGestureRecognizer translationInView:self].x - self.translation.x,
[panGestureRecognizer translationInView:self].y - self.translation.y);
if (CGPointEqualToPoint(self.startPoint, CGPointZero)) {
[self pickupPegWithGestureRecognizer:panGestureRecognizer];
}
}
}
}
- (void)updateTransformAtPoint:(CGPoint)point {
self.pegView.transform = CGAffineTransformMakeTranslation(self.translation.x, self.translation.y);
[self pegViewDidMoveAtPoint:point];
}
- (void)resetTransformAtPoint:(CGPoint)point {
if (!self.hasMoveEnded) {
self.movable = NO;
self.moveEnded = YES;
self.pinchRecognizer.enabled = NO;
self.panRecognizer.enabled = NO;
BOOL animated = ![self pegViewMoveDidEndAtPoint:point];
[UIView animateWithDuration:animated ? 0.15f : 0.0f
delay:animated ? 0.0f : 0.30f
options:UIViewAnimationOptionCurveEaseOut
animations:^(){
self.pegView.transform = CGAffineTransformIdentity;
self.pegView.alpha = 1.0f;
}
completion:^(BOOL finished){
self.translation = CGPointZero;
self.translationOffset = CGPointZero;
self.pinchRecognizer.enabled = YES;
self.panRecognizer.enabled = YES;
self.moveEnded = NO;
self.pegView.hidden = NO;
}];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
#pragma mark - peg view delegate
- (void)pegViewDidMoveAtPoint:(CGPoint)point {
self.directionView.hidden = YES;
if (CGPointEqualToPoint(self.startPoint, CGPointZero)) {
self.startPoint = point;
}
if ([self.delegate respondsToSelector:@selector(holePegTestRemoveDidProgress:)]) {
[self.delegate holePegTestRemoveDidProgress:self];
}
if (self.pegView.isSuccess) {
self.pegView.success = NO;
}
if ([self pegViewBehindLine]) {
self.pegView.alpha = 1.0f;
} else {
self.pegView.alpha = 0.2f;
}
}
- (BOOL)pegViewMoveDidEndAtPoint:(CGPoint)point {
self.directionView.hidden = NO;
BOOL succeeded = NO;
if ([self pegViewBehindLine]) {
if ([self.delegate respondsToSelector:@selector(holePegTestRemoveDidSucceed:withDistance:)]) {
CGFloat distance = hypotf(point.x - self.startPoint.x, point.y - self.startPoint.y);
[self.delegate holePegTestRemoveDidSucceed:self withDistance:distance];
}
self.pegView.success = YES;
succeeded = YES;
} else {
if ([self.delegate respondsToSelector:@selector(holePegTestRemoveDidFail:)]) {
[self.delegate holePegTestRemoveDidFail:self];
}
self.pegView.success = NO;
}
self.startPoint = CGPointZero;
return succeeded;
}
- (BOOL)pegViewBehindLine {
if (self.movingDirection == ORKBodySagittalLeft) {
if (CGRectGetMinX(self.pegView.frame) > CGRectGetMaxX(self.separatorView.frame)) {
return YES;
} else {
return NO;
}
} else {
if (CGRectGetMaxX(self.pegView.frame) < CGRectGetMinX(self.separatorView.frame)) {
return YES;
} else {
return NO;
}
}
}
@end
@@ -0,0 +1,44 @@
/*
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 <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemovePegView : UIView
@property (nonatomic, assign, getter = isSuccess) BOOL success;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,122 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestRemovePegView.h"
@interface ORKHolePegTestRemovePegView ()
@property (nonatomic, strong) CAShapeLayer *checkLayer;
@end
@implementation ORKHolePegTestRemovePegView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(27.7f, 46.9f)];
[path addLineToPoint:CGPointMake(36.1f, 56.3f)];
[path addLineToPoint:CGPointMake(62.8f, 30.3f)];
path.lineCapStyle = kCGLineCapRound;
path.lineWidth = 3.6f;
CAShapeLayer *checkLayer = [CAShapeLayer new];
checkLayer.path = path.CGPath;
checkLayer.lineWidth = 3.6f;
checkLayer.lineCap = kCALineCapRound;
checkLayer.lineJoin = kCALineJoinRound;
checkLayer.frame = self.layer.bounds;
checkLayer.strokeColor = [UIColor whiteColor].CGColor;
checkLayer.backgroundColor = [UIColor clearColor].CGColor;
checkLayer.fillColor = nil;
self.checkLayer = checkLayer;
self.opaque = NO;
self.success = NO;
}
return self;
}
- (void)tintColorDidChange {
[super tintColorDidChange];
[self setNeedsDisplay];
}
#pragma mark - drawing method
- (void)setSuccess:(BOOL)success
{
_success = success;
[self.checkLayer removeFromSuperlayer];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGRect bounds = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:bounds];
path.lineWidth = 2.0f;
[self.tintColor setFill];
[path fill];
if (self.isSuccess) {
[self.layer addSublayer:self.checkLayer];
CAMediaTimingFunction *timing = [[CAMediaTimingFunction alloc] initWithControlPoints:0.180739998817444
:0
:0.577960014343262
:0.918200016021729];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[animation setTimingFunction:timing];
[animation setFillMode:kCAFillModeBoth];
animation.fromValue = @(0);
animation.toValue = @(1);
animation.duration = 0.25f;
animation.delegate = self;
[self.checkLayer addAnimation:animation forKey:@"strokeEnd"];
}
CGContextRestoreGState(context);
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
self.success = NO;
}
@end
@@ -0,0 +1,47 @@
/*
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 <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemoveStep : ORKActiveStep
@property (nonatomic, assign) ORKBodySagittal movingDirection;
@property (nonatomic, assign, getter = isDominantHandTested) BOOL dominantHandTested;
@property (nonatomic, assign) int numberOfPegs;
@property (nonatomic, assign) double threshold;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,84 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestRemoveStep.h"
#import "ORKHolePegTestRemoveStepViewController.h"
@implementation ORKHolePegTestRemoveStep
+ (Class)stepViewControllerClass {
return [ORKHolePegTestRemoveStepViewController class];
}
- (instancetype)initWithIdentifier:(NSString *)identifier {
self = [super initWithIdentifier:identifier];
if (self) {
self.shouldShowDefaultTimer = NO;
self.shouldContinueOnFinish = YES;
}
return self;
}
- (void)validateParameters {
[super validateParameters];
int const ORKHolePegTestMinimumNumberOfPegs = 1;
double const ORKHolePegTestMinimumThreshold = 0.0f;
double const ORKHolePegTestMaximumThreshold = 1.0f;
NSTimeInterval const ORKHolePegTestMinimumDuration = 1.0f;
if (self.movingDirection != ORKBodySagittalLeft &&
self.movingDirection != ORKBodySagittalRight) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"moving direction should be left or right."] userInfo:nil];
}
if (self.numberOfPegs < ORKHolePegTestMinimumNumberOfPegs) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"number of pegs must be greater than or equal to %@.", @(ORKHolePegTestMinimumNumberOfPegs)] userInfo:nil];
}
if (self.threshold < ORKHolePegTestMinimumThreshold ||
self.threshold > ORKHolePegTestMaximumThreshold) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"threshold must be greater than or equal to %@ and lower or equal to %@.", @(ORKHolePegTestMinimumThreshold), @(ORKHolePegTestMaximumThreshold)] userInfo:nil];
}
if (self.stepDuration < ORKHolePegTestMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
}
}
- (BOOL)allowsBackNavigation {
return NO;
}
@end
@@ -0,0 +1,42 @@
/*
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 <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemoveStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,173 @@
/*
Copyright (c) 2015, Shazino SAS. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHolePegTestRemoveStepViewController.h"
#import "ORKHolePegTestRemoveStep.h"
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKActiveStepViewController_internal.h"
#import "ORKStepViewController_internal.h"
#import "ORKActiveStepView.h"
@interface ORKHolePegTestRemoveStepViewController () <ORKHolePegTestRemoveContentViewDelegate>
@property (nonatomic, strong) NSMutableArray *samples;
@property (nonatomic, strong) ORKHolePegTestRemoveContentView *holePegTestRemoveContentView;
@property (nonatomic, assign) NSTimeInterval sampleStart;
@property (nonatomic, assign) NSUInteger successes;
@property (nonatomic, assign) NSUInteger failures;
@end
@implementation ORKHolePegTestRemoveStepViewController
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
self.suspendIfInactive = YES;
}
return self;
}
- (ORKHolePegTestRemoveStep *)holePegTestRemoveStep {
return (ORKHolePegTestRemoveStep *)self.step;
}
- (void)initializeInternalButtonItems {
[super initializeInternalButtonItems];
// Don't show next button
self.internalContinueButtonItem = nil;
self.internalDoneButtonItem = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.holePegTestRemoveContentView = [[ORKHolePegTestRemoveContentView alloc] initWithMovingDirection:[self holePegTestRemoveStep].movingDirection];
self.holePegTestRemoveContentView.threshold = [self holePegTestRemoveStep].threshold;
self.holePegTestRemoveContentView.delegate = self;
self.activeStepView.activeCustomView = self.holePegTestRemoveContentView;
self.activeStepView.stepViewFillsAvailableSpace = YES;
NSString *identifier = [[self holePegTestRemoveStep].identifier stringByReplacingOccurrencesOfString:@"remove" withString:@"place"];
NSTimeInterval placeStepDuration = ((ORKHolePegTestResult *)[[self.taskViewController.result stepResultForStepIdentifier:identifier].results firstObject]).totalTime;
[self holePegTestRemoveStep].stepDuration -= placeStepDuration;
[self start];
}
#pragma mark - step life cycle methods
- (void)start {
self.sampleStart = CACurrentMediaTime();
self.successes = 0;
self.failures = 0;
self.samples = [NSMutableArray array];
[self.holePegTestRemoveContentView setProgress:0.001f animated:NO];
[super start];
}
#pragma mark - result methods
- (ORKStepResult *)result {
ORKStepResult *sResult = [super result];
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKHolePegTestResult *holePegTestResult = [[ORKHolePegTestResult alloc] initWithIdentifier:self.step.identifier];
holePegTestResult.movingDirection = [self holePegTestRemoveStep].movingDirection;
holePegTestResult.dominantHandTested = [self holePegTestRemoveStep].isDominantHandTested;
holePegTestResult.numberOfPegs = [self holePegTestRemoveStep].numberOfPegs;
holePegTestResult.threshold = [self holePegTestRemoveStep].threshold;
holePegTestResult.rotated = NO;
holePegTestResult.totalSuccesses = self.successes;
holePegTestResult.totalFailures = self.failures;
holePegTestResult.totalTime = [self holePegTestRemoveStep].stepDuration - self.timeRemaining;
double totalDistance = 0.0;
for (ORKHolePegTestSample *sample in self.samples) {
totalDistance += sample.distance;
}
holePegTestResult.totalDistance = totalDistance;
holePegTestResult.samples = self.samples;
[results addObject:holePegTestResult];
sResult.results = [results copy];
return sResult;
}
- (void)saveSampleWithDistance:(CGFloat)distance {
ORKHolePegTestSample *sample = [[ORKHolePegTestSample alloc] init];
sample.time = CACurrentMediaTime() - self.sampleStart;
sample.distance = distance;
self.sampleStart = CACurrentMediaTime();
[self.samples addObject:sample];
}
#pragma mark - hole peg test content view delegate
- (NSString *)stepTitle {
NSString *title = ([self holePegTestRemoveStep].movingDirection == ORKBodySagittalLeft) ? ORKLocalizedString(@"HOLE_PEG_TEST_REMOVE_INSTRUCTION_RIGHT_HAND", nil) : ORKLocalizedString(@"HOLE_PEG_TEST_REMOVE_INSTRUCTION_LEFT_HAND", nil);
return title;
}
- (void)holePegTestRemoveDidProgress:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView {
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT_2", nil)];
}
- (void)holePegTestRemoveDidSucceed:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView withDistance:(CGFloat)distance {
self.successes++;
[self saveSampleWithDistance:distance];
[holePegTestRemoveContentView setProgress:((CGFloat)self.successes / [self holePegTestRemoveStep].numberOfPegs) animated:YES];
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)];
if (self.successes >= [self holePegTestRemoveStep].numberOfPegs) {
[self finish];
}
}
- (void)holePegTestRemoveDidFail:(ORKHolePegTestRemoveContentView *)holePegTestRemoveContentView {
self.failures++;
[self.activeStepView updateTitle:[self stepTitle]
text:ORKLocalizedString(@"HOLE_PEG_TEST_TEXT", nil)];
}
@end
+5 -10
View File
@@ -75,10 +75,10 @@
- (void)start {
[super start];
if (! _logger) {
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (! _logger) {
if (!_logger) {
[self finishRecordingWithError:err];
return;
}
@@ -91,7 +91,7 @@
self.locationManager.pausesLocationUpdatesAutomatically = NO;
self.locationManager.delegate = self;
if (! self.locationManager) {
if (!self.locationManager) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}];
@@ -128,10 +128,10 @@
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
BOOL success = YES;
NSParameterAssert([locations count] >= 0);
NSParameterAssert(locations.count >= 0);
NSError *error = nil;
if (locations) {
NSMutableArray *dictionaries = [NSMutableArray arrayWithCapacity:[locations count]];
NSMutableArray *dictionaries = [NSMutableArray arrayWithCapacity:locations.count];
[locations enumerateObjectsUsingBlock:^(CLLocation *obj, NSUInteger idx, BOOL *stop) {
NSDictionary *d = [obj ork_JSONDictionary];
[dictionaries addObject:d];
@@ -169,11 +169,6 @@
@end
@interface ORKLocationRecorderConfiguration ()
@end
@implementation ORKLocationRecorderConfiguration
- (instancetype)initWithIdentifier:(NSString *)identifier {
+24 -25
View File
@@ -43,8 +43,6 @@
@property (nonatomic, assign, getter = isAuditory) BOOL auditory;
@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) ORKTapCountLabel *digitLabel;
@property (nonatomic, assign) ORKScreenType screenType;
@property (nonatomic, strong) NSArray *constraints;
@end
@@ -65,8 +63,6 @@
if (self) {
_screenType = ORKGetVerticalScreenTypeForWindow(self.window);
_digitLabel = [ORKTapCountLabel new];
_digitLabel.textAlignment = NSTextAlignmentCenter;
_digitLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -113,6 +109,11 @@
}
}
- (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:^{
@@ -121,42 +122,40 @@
}
- (void)updateConstraints {
if ([self.constraints count]) {
[NSLayoutConstraint deactivateConstraints:self.constraints];
self.constraints = nil;
}
[NSLayoutConstraint deactivateConstraints:self.constraints];
const CGFloat ORKPSATKeyboardWidth = ORKGetMetricForScreenType(ORKScreenMetricPSATKeyboardViewWidth, self.screenType);
const CGFloat ORKPSATKeyboardHeight = ORKGetMetricForScreenType(ORKScreenMetricPSATKeyboardViewHeight, self.screenType);
const CGFloat ORKPSATKeyboardWidth = ORKGetMetricForWindow(ORKScreenMetricPSATKeyboardViewWidth, self.window);
const CGFloat ORKPSATKeyboardHeight = ORKGetMetricForWindow(ORKScreenMetricPSATKeyboardViewHeight, self.window);
NSMutableArray *constraintsArray = [NSMutableArray array];
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _digitLabel, _keyboardView);
[constraintsArray addObjectsFromArray:
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
metrics:nil
views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-[_keyboardView(==%f)]-|", ORKPSATKeyboardWidth]
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_keyboardView(==keyboardWidth)]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
metrics:@{ @"keyboardWidth": @(ORKPSATKeyboardWidth) }
views:views]];
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[_keyboardView(==%f)]", ORKPSATKeyboardHeight]
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_keyboardView(==keyboardHeight)]"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
metrics:@{ @"keyboardHeight": @(ORKPSATKeyboardHeight) }
views:views]];
[constraintsArray addObjectsFromArray:
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_progressView]-[_digitLabel]-(>=10)-[_keyboardView]-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil views:views]];
metrics:nil
views:views]];
self.constraints = constraintsArray;
[self addConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:constraints];
[super updateConstraints];
}
+7 -13
View File
@@ -83,12 +83,9 @@ NSUInteger const ORKPSATMaximumAnswer = 17;
}
- (void)updateConstraints {
if ([self.constraints count]) {
[NSLayoutConstraint deactivateConstraints:self.constraints];
self.constraints = nil;
}
[NSLayoutConstraint deactivateConstraints:self.constraints];
NSMutableArray *constraintsArray = [NSMutableArray array];
NSMutableArray *constraints = [NSMutableArray array];
ORKBorderedButton *answer3Button = self.answerButtons[0];
ORKBorderedButton *answer4Button = self.answerButtons[1];
@@ -110,33 +107,30 @@ NSUInteger const ORKPSATMaximumAnswer = 17;
NSDictionary *views = NSDictionaryOfVariableBindings(answer3Button, answer4Button, answer5Button, answer6Button, answer7Button, answer8Button, answer9Button, answer10Button, answer11Button, answer12Button, answer13Button, answer14Button, answer15Button, answer16Button, answer17Button);
// First line of answer buttons
[constraintsArray addObjectsFromArray:
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[answer3Button]-[answer4Button(==answer3Button)]-[answer5Button(==answer3Button)]-[answer6Button(==answer3Button)]-[answer7Button(==answer3Button)]-|"
options:NSLayoutFormatAlignAllCenterY|NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom
metrics:nil views:views]];
// Second line of answer buttons
[constraintsArray addObjectsFromArray:
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[answer8Button]-[answer9Button(==answer8Button)]-[answer10Button(==answer8Button)]-[answer11Button(==answer8Button)]-[answer12Button(==answer8Button)]-|"
options:NSLayoutFormatAlignAllCenterY|NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom
metrics:nil views:views]];
// Third line of answer buttons
[constraintsArray addObjectsFromArray:
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[answer13Button]-[answer14Button(==answer13Button)]-[answer15Button(==answer13Button)]-[answer16Button(==answer13Button)]-[answer17Button(==answer13Button)]-|"
options:NSLayoutFormatAlignAllCenterY|NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom
metrics:nil views:views]];
// Align vertically
[constraintsArray addObjectsFromArray:
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[answer3Button]-[answer8Button(==answer3Button)]-[answer13Button(==answer3Button)]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
self.constraints = constraintsArray;
[self addConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:constraints];
[super updateConstraints];
}
@@ -43,7 +43,7 @@
@property (nonatomic, strong) NSMutableArray *samples;
@property (nonatomic, strong) ORKPSATContentView *psatContentView;
@property (nonatomic, strong) NSArray *digits;
@property (nonatomic, strong) NSArray<NSNumber *> *digits;
@property (nonatomic, assign) NSUInteger currentDigitIndex;
@property (nonatomic, assign) NSInteger currentAnswer;
@property (nonatomic, strong) ORKActiveStepTimer *clearDigitsTimer;
@@ -107,7 +107,7 @@
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKPSATResult *PSATResult = [[ORKPSATResult alloc] initWithIdentifier:(NSString *__nonnull)self.step.identifier];
ORKPSATResult *PSATResult = [[ORKPSATResult alloc] initWithIdentifier:self.step.identifier];
PSATResult.presentationMode = [self psatStep].presentationMode;
PSATResult.interStimulusInterval = [self psatStep].interStimulusInterval;
if ([self psatStep].presentationMode & ORKPSATPresentationModeVisual) {
@@ -116,7 +116,7 @@
PSATResult.stimulusDuration = 0.0;
}
PSATResult.length = [self psatStep].seriesLength;
PSATResult.initialDigit = [(NSNumber *)[self.digits objectAtIndex:0] integerValue];
PSATResult.initialDigit = self.digits[0].integerValue;
NSInteger totalCorrect = 0;
BOOL previousAnswerCorrect = NO;
NSInteger totalDyad = 0;
@@ -146,7 +146,7 @@
- (void)start {
self.digits = [self arrayWithPSATDigits];
self.currentDigitIndex = 0;
[self.psatContentView setAddition:self.currentDigitIndex forTotal:[self psatStep].seriesLength withDigit:[self.digits objectAtIndex:self.currentDigitIndex]];
[self.psatContentView setAddition:self.currentDigitIndex forTotal:[self psatStep].seriesLength withDigit:self.digits[self.currentDigitIndex]];
[self.psatContentView setProgress:0.001 animated:NO];
self.currentAnswer = -1;
self.samples = [NSMutableArray array];
@@ -198,7 +198,7 @@
self.answerEnd = 0;
if (self.currentDigitIndex <= [self psatStep].seriesLength) {
[self.psatContentView setAddition:self.currentDigitIndex forTotal:[self psatStep].seriesLength withDigit:[self.digits objectAtIndex:self.currentDigitIndex]];
[self.psatContentView setAddition:self.currentDigitIndex forTotal:[self psatStep].seriesLength withDigit:self.digits[self.currentDigitIndex]];
}
self.currentAnswer = -1;
@@ -215,8 +215,8 @@
- (void)saveSample {
ORKPSATSample *sample = [[ORKPSATSample alloc] init];
NSInteger previousDigit = [(NSNumber *)[self.digits objectAtIndex:self.currentDigitIndex - 1] integerValue];
NSInteger currentDigit = [(NSNumber *)[self.digits objectAtIndex:self.currentDigitIndex] integerValue];
NSInteger previousDigit = self.digits[self.currentDigitIndex - 1].integerValue;
NSInteger currentDigit = self.digits[self.currentDigitIndex].integerValue;;
sample.correct = previousDigit + currentDigit == self.currentAnswer ? YES : NO;
sample.digit = currentDigit;
sample.answer = self.currentAnswer;
+5 -10
View File
@@ -66,9 +66,9 @@
- (void)updateStatisticsWithData:(CMPedometerData *)pedometerData {
_lastUpdateDate = pedometerData.endDate;
_totalNumberOfSteps = [pedometerData.numberOfSteps integerValue];
_totalNumberOfSteps = pedometerData.numberOfSteps.integerValue;
if (pedometerData.distance) {
_totalDistance = [pedometerData.distance doubleValue];
_totalDistance = pedometerData.distance.doubleValue;
} else {
_totalDistance = -1;
}
@@ -90,10 +90,10 @@
_totalNumberOfSteps = 0;
_totalDistance = -1;
if (! _logger) {
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (! _logger) {
if (!_logger) {
[self finishRecordingWithError:err];
return;
}
@@ -101,7 +101,7 @@
self.pedometer = [self createPedometer];
if (! [[self.pedometer class] isStepCountingAvailable]) {
if (![[self.pedometer class] isStepCountingAvailable]) {
[self finishRecordingWithError:[NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder" : self}]];
@@ -179,11 +179,6 @@
@end
@interface ORKPedometerRecorderConfiguration ()
@end
@implementation ORKPedometerRecorderConfiguration
- (instancetype)initWithIdentifier:(NSString *)identifier {
@@ -34,14 +34,9 @@
#import "ORKNavigationContainerView.h"
@interface ORKReactionTimeContentView ()
@property (nonatomic, strong) ORKReactionTimeStimulusView *stimulusView;
@end
@implementation ORKReactionTimeContentView
@implementation ORKReactionTimeContentView {
ORKReactionTimeStimulusView *_stimulusView;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
@@ -69,7 +69,7 @@
}
if (self.maximumStimulusInterval < self.minimumStimulusInterval) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:@"maximumStimulusInterval can not be less than minimumStimulusInterval"
reason:@"maximumStimulusInterval cannot be less than minimumStimulusInterval"
userInfo:nil];
}
if (self.thresholdAcceleration <= 0) {
@@ -151,7 +151,7 @@ static const NSTimeInterval OutcomeAnimationDuration = 0.3;
- (void)attemptDidFinish {
void (^completion)(void) = ^{
if ([_results count] == [self reactionTimeStep].numberOfAttempts) {
if (_results.count == [self reactionTimeStep].numberOfAttempts) {
[self finish];
} else {
[self resetAfterDelay:2];
+5 -5
View File
@@ -169,7 +169,7 @@
}
- (NSURL *)recordingDirectoryURL {
if (! _outputDirectory) {
if (!_outputDirectory) {
return nil;
}
return [NSURL fileURLWithPath:[_outputDirectory.path stringByAppendingPathComponent:[NSString stringWithFormat:@"recorder-%@", _recorderUUID.UUIDString]]];
@@ -185,7 +185,7 @@
- (ORKDataLogger *)makeJSONDataLoggerWithError:(NSError * __autoreleasing *)error {
NSURL *workingDir = [self recordingDirectoryURL];
if (! workingDir) {
if (!workingDir) {
if (error) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteInvalidFileNameError userInfo:@{NSLocalizedDescriptionKey:ORKLocalizedString(@"ERROR_RECORDER_NO_OUTPUT_DIRECTORY", nil)}];
}
@@ -221,7 +221,7 @@
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
if (! [fileManager setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(fileProtection)} ofItemAtPath:[url path] error:&error]) {
ORK_Log_Debug(@"Error setting %@ on %@: %@", ORKFileProtectionFromMode(fileProtection), url, error);
ORK_Log_Warning(@"Error setting %@ on %@: %@", ORKFileProtectionFromMode(fileProtection), url, error);
}
}
@@ -233,7 +233,7 @@
ORKFileResult *result = [[ORKFileResult alloc] initWithIdentifier:self.identifier];
result.contentType = [self mimeType];
result.fileURL = fileUrl;
result.userInfo = [self userInfo];
result.userInfo = self.userInfo;
result.startDate = self.startDate;
[localDelegate recorder:self didCompleteWithResult:result];
@@ -242,7 +242,7 @@
[self reset];
}
} else {
if (! error) {
if (!error) {
error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFileReadNoSuchFileError
userInfo:@{NSLocalizedDescriptionKey:ORKLocalizedString(@"ERROR_RECORDER_NO_DATA", nil)}];
@@ -36,11 +36,6 @@ NS_ASSUME_NONNULL_BEGIN
@class ORKDataLogger;
@interface ORKRecorderConfiguration ()
@end
@interface ORKRecorder ()
@property (nonatomic, strong, nullable) ORKStep *step;
+1 -1
View File
@@ -35,7 +35,7 @@
/**
The `ORKSpatialSpanGame` class represents a model object that represents one game-like experience in a spatial span memory task.
A game consists of a subset of a permutation of the integers [0 .. gameSize-1],
A game consists of a subset of a permutation of the integers [0 .. gameSize - 1],
which represent the sequence of targets that should be tapped.
*/
@interface ORKSpatialSpanGame : NSObject
@@ -89,13 +89,13 @@
return ORKSpatialSpanResultIgnore;
}
NSInteger sequencePosition = [_plays count];
NSInteger sequencePosition = _plays.count;
BOOL correct = ([_game tileIndexForStep:sequencePosition] == tileIndex);
_states[tileIndex] = correct ? ORKSpatialSpanTargetStateCorrect : ORKSpatialSpanTargetStateIncorrect;
if (correct) {
[_plays addObject:@(tileIndex)];
}
if ([_plays count] >= [_game sequenceLength]) {
if (_plays.count >= [_game sequenceLength]) {
_complete = YES;
}
@@ -103,14 +103,14 @@
}
- (NSInteger)currentStepIndex {
return [_plays count];
return _plays.count;
}
- (NSInteger)lastSuccessfulTileIndex {
if (! [_plays count]) {
if (!_plays.count) {
return NSNotFound;
}
return [[_plays lastObject] integerValue];
return ((NSNumber *)_plays.lastObject).integerValue;
}
@end
@@ -63,8 +63,8 @@
- (void)resetTilesAnimated:(BOOL)animated {
NSArray *currentViews = _tileViews;
NSInteger numberOfTilesOld = [_tileViews count];
NSInteger numberOfTilesNew = _gridSize.width*_gridSize.height;
NSInteger numberOfTilesOld = _tileViews.count;
NSInteger numberOfTilesNew = _gridSize.width * _gridSize.height;
NSMutableArray *newViews = [NSMutableArray arrayWithCapacity:numberOfTilesNew];
NSArray *viewsToRemove = nil;
if (numberOfTilesOld <= numberOfTilesNew) {
@@ -123,15 +123,15 @@
- (void)layoutSubviews {
[super layoutSubviews];
CGRect bounds = [self bounds];
CGRect bounds = self.bounds;
CGFloat gridItemEdgeLength = ORKFloorToViewScale(MIN(bounds.size.width / _gridSize.width, bounds.size.height / _gridSize.height), self);
gridItemEdgeLength = MIN(gridItemEdgeLength, 114);
CGSize gridItemSize = (CGSize){gridItemEdgeLength, gridItemEdgeLength};
CGPoint centeringOffset = CGPointZero;
centeringOffset.x = 0.5*(bounds.size.width - (gridItemSize.width * _gridSize.width));
centeringOffset.y = 0.5*(bounds.size.height - (gridItemSize.height * _gridSize.height));
centeringOffset.x = 0.5 * (bounds.size.width - (gridItemSize.width * _gridSize.width));
centeringOffset.y = 0.5 * (bounds.size.height - (gridItemSize.height * _gridSize.height));
NSInteger tileIndex = 0;
for (NSInteger x = 0; x < _gridSize.width; x++) {
@@ -168,8 +168,6 @@
@implementation ORKSpatialSpanMemoryContentView {
ORKQuantityPairView *_quantityPairView;
ORKNavigationContainerView *_continueView;
NSArray *_constraints;
NSLayoutConstraint *_topConstraint;
}
- (ORKActiveStepQuantityView *)countView {
@@ -221,7 +219,7 @@
[self countView].backgroundColor = [[UIColor purpleColor] colorWithAlphaComponent:0.2];
#endif
[self setNeedsUpdateConstraints];
[self setUpConstraints];
}
return self;
}
@@ -274,29 +272,25 @@
[self updateMargins];
}
- (void)updateConstraints {
if (_constraints) {
[NSLayoutConstraint deactivateConstraints:_constraints];
_constraints = nil;
}
NSMutableArray *constraints = [NSMutableArray array];
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray new];
NSDictionary *views = NSDictionaryOfVariableBindings(_gameView, _quantityPairView, _continueView);
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=0)-[_gameView][_quantityPairView]|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_gameView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:1000.0];
constraint1.priority = UILayoutPriorityDefaultLow-1;
[constraints addObject:constraint1];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=0)-[_gameView][_quantityPairView]|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
NSLayoutConstraint *gameViewHeightConstraint = [NSLayoutConstraint constraintWithItem:_gameView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
gameViewHeightConstraint.priority = UILayoutPriorityDefaultLow - 1;
[constraints addObject:gameViewHeightConstraint];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_gameView]-|"
options:(NSLayoutFormatOptions)0
@@ -333,13 +327,10 @@
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
maxWidthConstraint.priority = UILayoutPriorityRequired-1;
maxWidthConstraint.priority = UILayoutPriorityRequired - 1;
[constraints addObject:maxWidthConstraint];
[NSLayoutConstraint activateConstraints:constraints];
_constraints = constraints;
[super updateConstraints];
}
@end
@@ -76,45 +76,45 @@
if ( self.initialSpan < ORKSpatialSpanMemoryTaskMinimumInitialSpan) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"initialSpan can not be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumInitialSpan)]
reason:[NSString stringWithFormat:@"initialSpan cannot be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumInitialSpan)]
userInfo:nil];
}
if ( self.minimumSpan > self.initialSpan) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"initialSpan can not be less than minimumSpan." userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"initialSpan cannot be less than minimumSpan." userInfo:nil];
}
if ( self.initialSpan > self.maximumSpan) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"maximumSpan can not be less than initialSpan." userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"maximumSpan cannot be less than initialSpan." userInfo:nil];
}
if ( self.maximumSpan > ORKSpatialSpanMemoryTaskMaximumSpan) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"maximumSpan can not be more than %@.", @(ORKSpatialSpanMemoryTaskMaximumSpan)]
reason:[NSString stringWithFormat:@"maximumSpan cannot be more than %@.", @(ORKSpatialSpanMemoryTaskMaximumSpan)]
userInfo:nil];
}
if (self.playSpeed < ORKSpatialSpanMemoryTaskMinimumPlaySpeed) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"playSpeed can not be shorter than %@ seconds.", @(ORKSpatialSpanMemoryTaskMinimumPlaySpeed)]
reason:[NSString stringWithFormat:@"playSpeed cannot be shorter than %@ seconds.", @(ORKSpatialSpanMemoryTaskMinimumPlaySpeed)]
userInfo:nil];
}
if (self.playSpeed > ORKSpatialSpanMemoryTaskMaximumPlaySpeed) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"playSpeed can not be longer than %@ seconds.", @(ORKSpatialSpanMemoryTaskMaximumPlaySpeed)]
reason:[NSString stringWithFormat:@"playSpeed cannot be longer than %@ seconds.", @(ORKSpatialSpanMemoryTaskMaximumPlaySpeed)]
userInfo:nil];
}
if (self.maxTests < ORKSpatialSpanMemoryTaskMinimumMaxTests) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"maxTests can not be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumMaxTests)]
reason:[NSString stringWithFormat:@"maxTests cannot be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumMaxTests)]
userInfo:nil];
}
if (self.maxConsecutiveFailures < ORKSpatialSpanMemoryTaskMinimumMaxConsecutiveFailures) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"maxConsecutiveFailures can not be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumMaxConsecutiveFailures)]
reason:[NSString stringWithFormat:@"maxConsecutiveFailures cannot be less than %@.", @(ORKSpatialSpanMemoryTaskMinimumMaxConsecutiveFailures)]
userInfo:nil];
}
}
@@ -47,7 +47,7 @@
#import "ORKActiveStepView.h"
static const NSTimeInterval kMemoryGameActivityTimeout = 20;
static const NSTimeInterval MemoryGameActivityTimeout = 20;
typedef NS_ENUM(NSInteger, ORKSpatialSpanStepState) {
ORKSpatialSpanStepStateInitial,
@@ -172,7 +172,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
- (void)start {
[super start];
if (! _state) {
if (!_state) {
[self transitionToState:ORKSpatialSpanStepStateInitial];
}
@@ -245,7 +245,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
#pragma mark UpdateGameRecord
- (ORKSpatialSpanMemoryGameRecord *)currentGameRecord {
return _gameRecords? [_gameRecords lastObject] : nil;
return _gameRecords? _gameRecords.lastObject : nil;
}
- (void)createGameRecord {
@@ -341,7 +341,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
#pragma mark ORKSpatialSpanStepStateInitial
- (ORKGridSize)gridSizeForSpan:(NSInteger)span {
NSInteger numberOfGridEntriesDesired = span*2;
NSInteger numberOfGridEntriesDesired = span * 2;
NSInteger value = (NSInteger)ceil(sqrt(numberOfGridEntriesDesired));
value = MAX(value, 2);
value = MIN(value, 6);
@@ -377,7 +377,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
NSInteger sequenceLength = _nextGameSequenceLength;
_gridSize = [self gridSizeForSpan:sequenceLength];
ORKSpatialSpanGame *game = [[ORKSpatialSpanGame alloc] initWithGameSize:_gridSize.width*_gridSize.height sequenceLength:sequenceLength seed:0];
ORKSpatialSpanGame *game = [[ORKSpatialSpanGame alloc] initWithGameSize:_gridSize.width * _gridSize.height sequenceLength:sequenceLength seed:0];
ORKSpatialSpanGameState *gameState = [[ORKSpatialSpanGameState alloc] initWithGame:game];
_currentGameState = gameState;
@@ -413,7 +413,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
ORKSpatialSpanMemoryStep *step = [self spatialSpanStep];
NSInteger index = _playbackIndex;
NSInteger previousIndex = index-1;
NSInteger previousIndex = index - 1;
if (step.requireReversal) {
// Play the indexes in reverse order when we require reversal. The participant
// is then required to tap the sequence in the forward direction, which
@@ -426,7 +426,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
[self applyTargetState:ORKSpatialSpanTargetStateQuiescent toSequenceIndex:previousIndex duration:0];
// The active display should be visible for half the timer interval
[self applyTargetState:ORKSpatialSpanTargetStateActive toSequenceIndex:index duration:step.playSpeed/2];
[self applyTargetState:ORKSpatialSpanTargetStateActive toSequenceIndex:index duration:(step.playSpeed / 2)];
}
_playbackIndex++;
}
@@ -471,7 +471,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
[_activityTimer invalidate];
_activityTimer = nil;
_activityTimer = [NSTimer scheduledTimerWithTimeInterval:kMemoryGameActivityTimeout target:self selector:@selector(activityTimeout) userInfo:nil repeats:NO];
_activityTimer = [NSTimer scheduledTimerWithTimeInterval:MemoryGameActivityTimeout target:self selector:@selector(activityTimeout) userInfo:nil repeats:NO];
}
- (void)startGameplay {
@@ -522,8 +522,8 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
[gameView setState:ORKSpatialSpanTargetStateCorrect forTileIndex:tileIndex animated:YES];
NSInteger stepIndex = [_currentGameState currentStepIndex];
[self setNumberOfItems:_numberOfItems+1];
[self setScore:_score + (round(log2(stepIndex))+1)*5];
[self setNumberOfItems:_numberOfItems + 1];
[self setScore:_score + (round(log2(stepIndex)) + 1) * 5];
[self resetActivityTimer];
if ([_currentGameState isComplete]) {
@@ -544,7 +544,7 @@ typedef void (^_ORKStateHandler)(ORKState *fromState, ORKState *_toState, id con
ORKSpatialSpanMemoryStep *step = [self spatialSpanStep];
if (success) {
NSInteger sequenceLength = [_currentGameState.game sequenceLength];
[self setScore:_score + (round(log2(sequenceLength))+1)*5];
[self setScore:_score + (round(log2(sequenceLength)) + 1) * 5];
_gamesCounter++;
_consecutiveGamesFailed = 0;
_nextGameSequenceLength = MIN(_nextGameSequenceLength + 1, step.maximumSpan);
@@ -144,7 +144,7 @@ static UIBezierPath *ORKErrorBezierPath() {
}
- (void)drawRect:(CGRect)rect {
CGRect bounds = [self bounds];
CGRect bounds = self.bounds;
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor clearColor] setFill];
@@ -284,7 +284,7 @@ static UIBezierPath *ORKErrorBezierPath() {
case ORKSpatialSpanTargetStateIncorrect:
_flowerView.tintColor = [UIColor ork_redColor];
newTransform = CGAffineTransformMakeScale(0.9*_flowerScaleFactor, 0.9*_flowerScaleFactor);
newTransform = CGAffineTransformMakeScale(0.9 * _flowerScaleFactor, 0.9 * _flowerScaleFactor);
oldCircleAlpha = 0;
newCircleAlpha = 1;
oldCircleTransform = CGAffineTransformMakeScale(0.2, 0.2);
@@ -296,7 +296,7 @@ static UIBezierPath *ORKErrorBezierPath() {
case ORKSpatialSpanTargetStateCorrect:
_flowerView.tintColor = [self tintColor];
newTransform = CGAffineTransformMakeScale(1.1*_flowerScaleFactor, 1.1*_flowerScaleFactor);
newTransform = CGAffineTransformMakeScale(1.1 * _flowerScaleFactor, 1.1 * _flowerScaleFactor);
oldCircleAlpha = 0;
newCircleAlpha = 1;
oldCircleTransform = CGAffineTransformMakeScale(0.2, 0.2);
@@ -336,14 +336,14 @@ static UIBezierPath *ORKErrorBezierPath() {
CGFloat designWidth = ORKFlowerBezierPathSize.width + _ORKFlowerMargins.left + _ORKFlowerMargins.right;
CGFloat scaleFactor = bounds.size.width / designWidth;
CGAffineTransform tfm = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
CGAffineTransform transform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
CGRect checkRect = CGRectApplyAffineTransform((CGRect){CGPointZero,ORKCheckBezierPathSize}, tfm);
CGRect checkRect = CGRectApplyAffineTransform((CGRect){CGPointZero, ORKCheckBezierPathSize}, transform);
[_checkView setBounds:checkRect];
_checkView.layer.cornerRadius = checkRect.size.width/2;
CGRect errorRect = CGRectApplyAffineTransform((CGRect){CGPointZero,ORKErrorBezierPathSize}, tfm);
_checkView.layer.cornerRadius = checkRect.size.width / 2;
CGRect errorRect = CGRectApplyAffineTransform((CGRect){CGPointZero, ORKErrorBezierPathSize}, transform);
[_errorView setBounds:errorRect];
_errorView.layer.cornerRadius = errorRect.size.width/2;
_errorView.layer.cornerRadius = errorRect.size.width / 2;
_errorView.center = _flowerView.center;
_checkView.center = _flowerView.center;
}
+98 -77
View File
@@ -51,17 +51,17 @@
@implementation ORKTappingContentView {
NSArray *_constraints;
ORKScreenType _screenType;
UIView *_buttonContainer;
NSNumberFormatter *_formatter;
NSLayoutConstraint *_topToProgressViewConstraint;
NSLayoutConstraint *_topToCaptionLabelConstraint;
NSLayoutConstraint *_captionLabelToTapCountLabelConstraint;
NSLayoutConstraint *_tapButtonToBottomConstraint;
}
- (instancetype)init {
self = [super init];
if (self) {
_screenType = ORKScreenTypeiPhone4;
_tapCaptionLabel = [ORKSubheadlineLabel new];
_tapCaptionLabel.textAlignment = NSTextAlignmentCenter;
_tapCaptionLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -97,7 +97,8 @@
_tapCaptionLabel.text = ORKLocalizedString(@"TOTAL_TAPS_LABEL", nil);
[self setTapCount:0];
[self setNeedsUpdateConstraints];
[self setUpConstraints];
[self updateConstraintConstantsForWindow:self.window];
_tapCountLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
@@ -147,13 +148,12 @@
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
_screenType = ORKGetVerticalScreenTypeForWindow(newWindow);
[self setNeedsUpdateConstraints];
[self updateConstraintConstantsForWindow:newWindow];
}
- (void)updateLayoutMargins {
CGFloat margin = ORKStandardHorizontalMarginForView(self);
self.layoutMargins = (UIEdgeInsets) { .left=margin*2, .right=margin*2 };
self.layoutMargins = (UIEdgeInsets){.left = margin * 2, .right=margin * 2};
}
- (void)setFrame:(CGRect)frame {
@@ -166,104 +166,96 @@
[self updateLayoutMargins];
}
- (void)updateConstraints {
if ([_constraints count]) {
[NSLayoutConstraint deactivateConstraints:_constraints];
_constraints = nil;
}
ORKScreenType screenType = _screenType;
const CGFloat HeaderBaselineToCaptionTop = ORKGetMetricForScreenType(ORKScreenMetricCaptionBaselineToTappingLabelTop, screenType);
const CGFloat AssumedHeaderBaselineToStepViewTop = ORKGetMetricForScreenType(ORKScreenMetricLearnMoreBaselineToStepViewTop, screenType);
static const CGFloat CaptionBaselineToTapCountBaseline = 56;
static const CGFloat TapButtonBottomToBottom = 36;
// On the iPhone, _progressView is positioned outside the bounds of this view, to be in-between the header and this view.
// On the iPad, we want to stretch this out a bit so it feels less compressed.
CGFloat progressViewOffset, topCaptionLabelOffset;
if (screenType == ORKScreenTypeiPad) {
progressViewOffset = 0;
topCaptionLabelOffset = AssumedHeaderBaselineToStepViewTop;
} else {
progressViewOffset = (HeaderBaselineToCaptionTop/3) - AssumedHeaderBaselineToStepViewTop;
topCaptionLabelOffset = HeaderBaselineToCaptionTop - AssumedHeaderBaselineToStepViewTop;
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_buttonContainer, _tapCaptionLabel, _tapCountLabel, _progressView, _tapButton1, _tapButton2);
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1 constant:progressViewOffset]];
_topToProgressViewConstraint = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]; // constant set in updateConstraintConstantsForWindow:
[constraints addObject:_topToProgressViewConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_tapCaptionLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1 constant:topCaptionLabelOffset]];
_topToCaptionLabelConstraint = [NSLayoutConstraint constraintWithItem:_tapCaptionLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]; // constant set in updateConstraintConstantsForWindow:
[constraints addObject:_topToCaptionLabelConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_tapCountLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_tapCaptionLabel
attribute:NSLayoutAttributeFirstBaseline
multiplier:1 constant:CaptionBaselineToTapCountBaseline]];
_captionLabelToTapCountLabelConstraint = [NSLayoutConstraint constraintWithItem:_tapCountLabel
attribute:NSLayoutAttributeFirstBaseline
relatedBy:NSLayoutRelationEqual
toItem:_tapCaptionLabel
attribute:NSLayoutAttributeFirstBaseline
multiplier:1.0
constant:0.0]; // constant set in updateConstraintConstantsForWindow:
[constraints addObject:_captionLabelToTapCountLabelConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_buttonContainer
attribute:NSLayoutAttributeBottom
multiplier:1 constant:TapButtonBottomToBottom]];
_tapButtonToBottomConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_buttonContainer
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]; // constant set in updateConstraintConstantsForWindow:
[constraints addObject:_tapButtonToBottomConstraint];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_tapCountLabel]-(>=10)-[_buttonContainer]"
options:NSLayoutFormatAlignAllCenterX
metrics:nil views:views]];
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
NSLayoutConstraint *wideProgress = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:2000];
wideProgress.priority = UILayoutPriorityRequired-1;
[constraints addObject:wideProgress];
metrics:nil
views:views]];
NSLayoutConstraint *progressViewWidthConstraint = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:ORKScreenMetricMaxDimension];
progressViewWidthConstraint.priority = UILayoutPriorityRequired - 1;
[constraints addObject:progressViewWidthConstraint];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_tapCaptionLabel]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_tapCountLabel]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_tapButton1]|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_tapButton2]|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_tapButton1]-(>=24)-[_tapButton2(==_tapButton1)]|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_tapButton1
@@ -271,13 +263,42 @@
relatedBy:NSLayoutRelationEqual
toItem:_tapButton2
attribute:NSLayoutAttributeCenterY
multiplier:1 constant:0]];
_constraints = constraints;
[self addConstraints:_constraints];
multiplier:1.0
constant:0.0]];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)updateConstraintConstantsForWindow:(UIWindow *)window {
const CGFloat HeaderBaselineToCaptionTop = ORKGetMetricForWindow(ORKScreenMetricCaptionBaselineToTappingLabelTop, window);
const CGFloat AssumedHeaderBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window);
CGFloat margin = ORKStandardHorizontalMarginForView(self);
self.layoutMargins = (UIEdgeInsets){.left = margin * 2, .right = margin * 2};
static const CGFloat CaptionBaselineToTapCountBaseline = 56;
static const CGFloat TapButtonBottomToBottom = 36;
// On the iPhone, _progressView is positioned outside the bounds of this view, to be in-between the header and this view.
// On the iPad, we want to stretch this out a bit so it feels less compressed.
CGFloat topToProgressViewOffset = 0.0;
CGFloat topToCaptionLabelOffset = 0.0;
ORKScreenType screenType = ORKGetVerticalScreenTypeForWindow(window);
if (screenType == ORKScreenTypeiPad) {
topToProgressViewOffset = 0;
topToCaptionLabelOffset = AssumedHeaderBaselineToStepViewTop;
} else {
topToProgressViewOffset = (HeaderBaselineToCaptionTop / 3) - AssumedHeaderBaselineToStepViewTop;
topToCaptionLabelOffset = HeaderBaselineToCaptionTop - AssumedHeaderBaselineToStepViewTop;
}
_topToProgressViewConstraint.constant = topToProgressViewOffset;
_topToCaptionLabelConstraint.constant = topToCaptionLabelOffset;
_captionLabelToTapCountLabelConstraint.constant = CaptionBaselineToTapCountBaseline;
_tapButtonToBottomConstraint.constant = TapButtonBottomToBottom;
}
- (void)updateConstraints {
[self updateConstraintConstantsForWindow:self.window];
[super updateConstraints];
}
@@ -53,7 +53,7 @@
NSTimeInterval const ORKTwoFingerTappingMinimumDuration = 5.0;
if ( self.stepDuration < ORKTwoFingerTappingMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKTwoFingerTappingMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKTwoFingerTappingMinimumDuration)] userInfo:nil];
}
}
@@ -136,7 +136,7 @@
return;
}
NSTimeInterval mediaTime = CACurrentMediaTime();
NSTimeInterval mediaTime = touch.timestamp;
if (_tappingStart == 0) {
_tappingStart = mediaTime;
@@ -90,29 +90,23 @@
}
- (void)updateConstraints {
if ([self.constraints count]) {
[NSLayoutConstraint deactivateConstraints:self.constraints];
self.constraints = nil;
}
[NSLayoutConstraint deactivateConstraints:self.constraints];
NSMutableArray *constraintsArray = [NSMutableArray array];
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _imageView);
[constraintsArray addObjectsFromArray:
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_progressView]|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
[constraintsArray addObjectsFromArray:
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_progressView]-(>=10)-[_imageView]-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil views:views]];
self.constraints = constraintsArray;
[self addConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:self.constraints];
[NSLayoutConstraint activateConstraints:constraints];
[super updateConstraints];
}
+1 -1
View File
@@ -66,7 +66,7 @@
}
if (self.stepDuration < ORKTimedWalkMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKTimedWalkMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKTimedWalkMinimumDuration)] userInfo:nil];
}
}
@@ -38,9 +38,6 @@
#import "ORKActiveStepView.h"
double const kDistanceInMetersTrackingThreshold = 100.0;
@interface ORKTimedWalkStepViewController ()
@property (nonatomic, strong) NSMutableArray *samples;
@@ -101,7 +98,7 @@ double const kDistanceInMetersTrackingThreshold = 100.0;
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKTimedWalkResult *timedWalkResult = [[ORKTimedWalkResult alloc] initWithIdentifier:(NSString *__nonnull)self.step.identifier];
ORKTimedWalkResult *timedWalkResult = [[ORKTimedWalkResult alloc] initWithIdentifier:self.step.identifier];
timedWalkResult.distanceInMeters = [self timedWalkStep].distanceInMeters;
timedWalkResult.timeLimit = [self timedWalkStep].stepDuration;
timedWalkResult.duration = self.trialDuration;
@@ -38,20 +38,19 @@
@property (nonatomic, strong) ORKUnitLabel *captionLabel;
@property (nonatomic, strong) UIProgressView *progressView;
- (void)setupConstraints;
@end
@implementation ORKToneAudiometryContentView {
ORKScreenType _screenType;
NSLayoutConstraint *_topToProgressViewConstraint;
NSLayoutConstraint *_topToCaptionLabelConstraint;
NSLayoutConstraint *_tapButtonToBottomConstraint;
}
- (instancetype)init {
self = [super init];
if (self) {
_screenType = ORKGetVerticalScreenTypeForWindow(self.window);
_captionLabel = [ORKUnitLabel new];
_captionLabel.textAlignment = NSTextAlignmentCenter;
_captionLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -73,13 +72,18 @@
_captionLabel.text = nil;
[self setupConstraints];
[self setNeedsUpdateConstraints];
[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];
@@ -101,86 +105,105 @@
self.tapButton.enabled = NO;
}
- (void)updateConstraintConstantsForWindow:(UIWindow *)window {
const CGFloat HeaderBaselineToCaptionTop = ORKGetMetricForWindow(ORKScreenMetricCaptionBaselineToTappingLabelTop, window);
const CGFloat AssumedHeaderBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window);
static const CGFloat TapButtonBottomToBottom = 36.0;
_topToProgressViewConstraint.constant = (HeaderBaselineToCaptionTop / 3) - AssumedHeaderBaselineToStepViewTop;
_topToCaptionLabelConstraint.constant = HeaderBaselineToCaptionTop - AssumedHeaderBaselineToStepViewTop;
_tapButtonToBottomConstraint.constant = TapButtonBottomToBottom;
}
- (void)updateLayoutMargins {
CGFloat margin = ORKStandardHorizontalMarginForView(self);
self.layoutMargins = (UIEdgeInsets) { .left=margin*2, .right=margin*2 };
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 {
ORKScreenType screenType = _screenType;
const CGFloat HeaderBaselineToCaptionTop = ORKGetMetricForScreenType(ORKScreenMetricCaptionBaselineToTappingLabelTop, screenType);
const CGFloat AssumedHeaderBaselineToStepViewTop = ORKGetMetricForScreenType(ORKScreenMetricLearnMoreBaselineToStepViewTop, screenType);
static const CGFloat TapButtonBottomToBottom = 36;
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _captionLabel, _tapButton);
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1 constant:(HeaderBaselineToCaptionTop/3) - AssumedHeaderBaselineToStepViewTop]];
_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];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_captionLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1 constant:(HeaderBaselineToCaptionTop - AssumedHeaderBaselineToStepViewTop)]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_tapButton
attribute:NSLayoutAttributeBottom
multiplier:1 constant:TapButtonBottomToBottom]];
_tapButtonToBottomConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_tapButton
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]; // constant will be set in updateConstraintConstantsForWindow:
[constraints addObject:_tapButtonToBottomConstraint];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_captionLabel]-(>=10)-[_tapButton]"
options:NSLayoutFormatAlignAllCenterX
metrics:nil views:views]];
metrics:nil
views:views]];
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
options:(NSLayoutFormatOptions)0
metrics:nil views:views]];
NSLayoutConstraint *wideProgress = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:2000];
wideProgress.priority = UILayoutPriorityRequired-1;
[constraints addObject:wideProgress];
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]];
metrics:nil
views:views]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_tapButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1 constant:0]];
multiplier:1.0
constant:0.0]];
[self addConstraints:constraints];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)updateConstraints {
[self updateConstraintConstantsForWindow:self.window];
[super updateConstraints];
}
@end
@@ -44,7 +44,7 @@
NSTimeInterval const ORKToneAudiometryTaskToneMinimumDuration = 5.0;
if (self.toneDuration < ORKToneAudiometryTaskToneMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"tone duration can not be shorter than %@ seconds.", @(ORKToneAudiometryTaskToneMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"tone duration cannot be shorter than %@ seconds.", @(ORKToneAudiometryTaskToneMinimumDuration)] userInfo:nil];
}
}
@@ -110,7 +110,7 @@
NSMutableArray *results = [NSMutableArray arrayWithArray:sResult.results];
ORKToneAudiometryResult *toneResult = [[ORKToneAudiometryResult alloc] initWithIdentifier:(NSString *__nonnull)self.step.identifier];
ORKToneAudiometryResult *toneResult = [[ORKToneAudiometryResult alloc] initWithIdentifier:self.step.identifier];
toneResult.startDate = sResult.startDate;
toneResult.endDate = now;
toneResult.samples = [self.samples copy];
@@ -180,8 +180,7 @@
self.currentTestIndex ++;
if (self.currentTestIndex == (self.testingFrequencies.count * 2)) {
[self finish];
}
else {
} else {
[self startCurrentTest];
}
}
+2 -7
View File
@@ -113,10 +113,10 @@
}
- (void)start {
if (! _logger) {
if (!_logger) {
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (! _logger) {
if (!_logger) {
[self finishRecordingWithError:err];
return;
}
@@ -203,11 +203,6 @@
@end
@interface ORKTouchRecorderConfiguration ()
@end
@implementation ORKTouchRecorderConfiguration
- (instancetype)initWithIdentifier:(NSString *)identifier {
@@ -33,7 +33,9 @@
NS_ASSUME_NONNULL_BEGIN
/**
*/
ORK_CLASS_AVAILABLE
@interface ORKTowerOfHanoiStep : ORKActiveStep
@@ -33,7 +33,8 @@
#import "ORKTowerOfHanoiStepViewController.h"
#import "ORKHelpers.h"
static const NSUInteger kMaximumNumberOfDisks = 8;
static const NSUInteger MaximumNumberOfDisks = 8;
@implementation ORKTowerOfHanoiStep
@@ -95,8 +96,8 @@ static const NSUInteger kMaximumNumberOfDisks = 8;
- (void)validateParameters {
[super validateParameters];
if (self.numberOfDisks > kMaximumNumberOfDisks) {
ORK_Log_Oops(@"Having a large number of disks provides a poor user experience, consider reducing the number below %@.", @(kMaximumNumberOfDisks));
if (self.numberOfDisks > MaximumNumberOfDisks) {
ORK_Log_Warning(@"Having a large number of disks provides a poor user experience, consider reducing the number below %@.", @(MaximumNumberOfDisks));
}
}
@@ -37,7 +37,8 @@
#import "ORKTowerOfHanoiStep.h"
#import "ORKSkin.h"
static const NSUInteger kNumberOfTowers = 3;
static const NSUInteger NumberOfTowers = 3;
@interface ORKTowerOfHanoiViewController () <ORKTowerOfHanoiTowerViewDataSource, ORKTowerOfHanoiTowerViewDelegate>
@@ -46,10 +47,11 @@ static const NSUInteger kNumberOfTowers = 3;
@end
@implementation ORKTowerOfHanoiViewController {
ORKActiveStepCustomView *_towerOfHanoiCustomView;
NSNumber *_selectedIndex;
NSArray *_currentConstraints;
NSArray *_variableConstraints;
NSMutableArray *_towers;
NSArray *_towerViews;
NSTimer *_timer;
@@ -62,12 +64,12 @@ static const NSUInteger kNumberOfTowers = 3;
- (void)viewDidLoad {
[super viewDidLoad];
_towerOfHanoiCustomView = [ORKActiveStepCustomView new];
[_towerOfHanoiCustomView setTranslatesAutoresizingMaskIntoConstraints:NO];
_towerOfHanoiCustomView.translatesAutoresizingMaskIntoConstraints = NO;
self.activeStepView.activeCustomView = _towerOfHanoiCustomView;
self.activeStepView.minimumStepHeaderHeight = ORKGetMetricForWindow(ORKScreenMetricMinimumStepHeaderHeightForTowerOfHanoiPuzzle, self.view.window);
[self setupTowers];
[self setupTowerViews];
[self setUpTowers];
[self setUpTowerViews];
[self reloadData];
NSString *title = ORKLocalizedString(@"TOWER_OF_HANOI_TASK_ACTIVE_STEP_INTRO_TEXT",nil);
NSString *text = ORKLocalizedString(@"TOWER_OF_HANOI_TASK_INTRO_TEXT",nil);
@@ -83,14 +85,19 @@ static const NSUInteger kNumberOfTowers = 3;
- (void)updateViewConstraints {
[super updateViewConstraints];
if (_currentConstraints) {
[NSLayoutConstraint deactivateConstraints:_currentConstraints];
_currentConstraints = nil;
[NSLayoutConstraint deactivateConstraints:_variableConstraints];
_variableConstraints = nil;
if (!_variableConstraints) {
_variableConstraints = [NSMutableArray new];
}
BOOL needCompactLayout = self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact &&
self.traitCollection.verticalSizeClass != UIUserInterfaceSizeClassCompact;
_currentConstraints = needCompactLayout ? [self compactConstraints] : [self regularConstraints];
[NSLayoutConstraint activateConstraints:_currentConstraints];
BOOL needCompactLayout =
(self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) &&
(self.traitCollection.verticalSizeClass != UIUserInterfaceSizeClassCompact);
_variableConstraints = needCompactLayout ? [self compactConstraints] : [self regularConstraints];
[NSLayoutConstraint activateConstraints:_variableConstraints];
}
#pragma mark - ORKStepViewController
@@ -195,7 +202,7 @@ static const NSUInteger kNumberOfTowers = 3;
}
}
- (void)setupTowers {
- (void)setUpTowers {
NSMutableArray *diskStack = [NSMutableArray array];
for (NSInteger disk = [self numberOfDisks] ; disk > 0 ; disk--) {
[diskStack addObject: @(disk)];
@@ -203,15 +210,15 @@ static const NSUInteger kNumberOfTowers = 3;
_towers = [@[[[ORKTowerOfHanoiTower alloc] initWithDisks:diskStack], [ORKTowerOfHanoiTower emptyTower], [ORKTowerOfHanoiTower emptyTower]] mutableCopy];
}
- (void)setupTowerViews {
- (void)setUpTowerViews {
NSMutableArray *towerViews = [NSMutableArray array];
for (NSInteger index = 0 ; index < 3 ; index++) {
ORKTowerOfHanoiTowerView *towerView = [[ORKTowerOfHanoiTowerView alloc] initWithFrame:CGRectZero maximumNumberOfDisks:[self numberOfDisks]];
towerView.delegate = self;
towerView.dataSource = self;
towerView.targeted = (index == kNumberOfTowers - 1);
towerView.targeted = (index == NumberOfTowers - 1);
[towerViews addObject:towerView];
[towerView setTranslatesAutoresizingMaskIntoConstraints:NO];
towerView.translatesAutoresizingMaskIntoConstraints = NO;
[_towerOfHanoiCustomView addSubview:towerView];
}
_towerViews = towerViews;
@@ -222,8 +229,7 @@ static const NSUInteger kNumberOfTowers = 3;
ORKTowerOfHanoiTower *recipientTower = _towers[recipientTowerIndex];
if ([recipientTower recieveDiskFrom:donorTower]) {
[self makeMoveFromTowerAtIndex:donorTowerIndex toTowerAtIndex:recipientTowerIndex];
}
else {
} else {
NSNumber *donorSize = [self towerOfHanoiView:_towerViews[donorTowerIndex] diskAtIndex:0];
NSNumber *recipientSize = [self towerOfHanoiView:_towerViews[recipientTowerIndex] diskAtIndex:0];
@@ -265,13 +271,41 @@ static const NSUInteger kNumberOfTowers = 3;
NSDictionary *views = @{ @"A" : _towerViews[0], @"B" : _towerViews[1], @"C" : _towerViews[2]};
NSMutableArray *newConstraints = [NSMutableArray new];
[newConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|-[A]-[B]-[C]-|"] options:0 metrics:nil views:views]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[0] attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_towerViews[1] attribute:NSLayoutAttributeHeight multiplier:1 constant:0]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[2] attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_towerViews[1] attribute:NSLayoutAttributeHeight multiplier:1 constant:0]];
[newConstraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|-[A]-[B]-[C]-|"]
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[0]
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_towerViews[1]
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0.0]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[2]
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_towerViews[1]
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0.0]];
for (int index = 0 ; index < _towerViews.count ; index++) {
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[index] attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:compactWidth]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[index] attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_towerOfHanoiCustomView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[index]
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:compactWidth]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[index]
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:_towerOfHanoiCustomView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
}
return newConstraints;
@@ -281,13 +315,41 @@ static const NSUInteger kNumberOfTowers = 3;
NSDictionary *views = @{ @"A" : _towerViews[0], @"B" : _towerViews[1], @"C" : _towerViews[2]};
NSMutableArray *newConstraints = [NSMutableArray new];
[newConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[A]-|" options:0 metrics:nil views:views]];
[newConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[B]-|" options:0 metrics:nil views:views]];
[newConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[C]-|" options:0 metrics:nil views:views]];
[newConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[A]-[B]-[C]-|" options:0 metrics:nil views:views]];
[newConstraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[A]-|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[newConstraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[B]-|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[newConstraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[C]-|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[newConstraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[A]-[B]-[C]-|"
options:(NSLayoutFormatOptions)0
metrics:nil
views:views]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[0] attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_towerViews[1] attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[2] attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_towerViews[1] attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[0]
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:_towerViews[1]
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
[newConstraints addObject:[NSLayoutConstraint constraintWithItem:_towerViews[2]
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:_towerViews[1]
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
return newConstraints;
}
@@ -52,7 +52,7 @@
}
- (BOOL)canRecieveDisk:(NSNumber *)disk {
return _disks.count == 0 || [_disks.lastObject integerValue] > disk.integerValue;
return _disks.count == 0 || ((NSNumber *)_disks.lastObject).integerValue > disk.integerValue;
}
- (BOOL)recieveDiskFrom:(ORKTowerOfHanoiTower*)donorTower {
@@ -56,7 +56,7 @@ static const CGFloat BaseSpacing = 10;
_maximumNumberOfDisks = maximumNumberOfDisks;
_base = [[UIView alloc] initWithFrame:CGRectZero];
_base.backgroundColor = [UIColor ork_midGrayTintColor];
[_base setTranslatesAutoresizingMaskIntoConstraints:NO];
_base.translatesAutoresizingMaskIntoConstraints = NO;
_base.layer.cornerRadius = 2.5;
_base.layer.masksToBounds = YES;
_diskViews = [NSMutableArray new];
@@ -78,7 +78,6 @@ static const CGFloat BaseSpacing = 10;
}
CGFloat height = (DiskHeight * _maximumNumberOfDisks) + (DiskSpacing * _maximumNumberOfDisks);
[_variableConstraints addObject:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationGreaterThanOrEqual
@@ -101,7 +100,7 @@ static const CGFloat BaseSpacing = 10;
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:2]];
constant:2.0]];
[_variableConstraints addObject:[NSLayoutConstraint constraintWithItem:_base
attribute:NSLayoutAttributeCenterX
@@ -123,7 +122,7 @@ static const CGFloat BaseSpacing = 10;
for (NSInteger index = 0 ; index < _diskSizes.count ; index++) {
UIView *disk = _diskViews[index];
CGFloat divide = 1.0 / _maximumNumberOfDisks;
CGFloat multiply = [(NSNumber *)_diskSizes[index] floatValue] * divide;
CGFloat multiply = ((NSNumber *)_diskSizes[index]).floatValue * divide;
[_variableConstraints addObject:[NSLayoutConstraint constraintWithItem:disk
attribute:NSLayoutAttributeCenterX
@@ -133,8 +132,6 @@ static const CGFloat BaseSpacing = 10;
multiplier:1.0
constant:0.0]];
[_variableConstraints addObject:[NSLayoutConstraint constraintWithItem:disk
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
@@ -261,7 +258,7 @@ static const CGFloat BaseSpacing = 10;
}
- (NSString *)accessibilityValue {
NSString *disksString = @"";
for (NSNumber *diskSize in _diskSizes) {
+1 -1
View File
@@ -72,7 +72,7 @@
AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:text];
float speechRate = AVSpeechUtteranceDefaultSpeechRate;
if (! [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){.majorVersion = 9, .minorVersion = 0, .patchVersion = 0}]) {
if (![[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){.majorVersion = 9, .minorVersion = 0, .patchVersion = 0}]) {
speechRate = AVSpeechUtteranceDefaultSpeechRate / 2.5;
}
utterance.rate = speechRate;
+1 -1
View File
@@ -56,7 +56,7 @@
if ( self.numberOfStepsPerLeg < ORKShortWalkTaskMinimumNumberOfStepsPerLeg) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@"numberOfStepsPerLeg can not be less than %@.", @(ORKShortWalkTaskMinimumNumberOfStepsPerLeg)]
reason:[NSString stringWithFormat:@"numberOfStepsPerLeg cannot be less than %@.", @(ORKShortWalkTaskMinimumNumberOfStepsPerLeg)]
userInfo:nil];
}
}
@@ -45,7 +45,6 @@
@interface ORKWalkingContentView : ORKActiveStepCustomView {
ORKScreenType _screenType;
NSLayoutConstraint *_topConstraint;
}
@@ -56,18 +55,11 @@
@implementation ORKWalkingContentView
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
_screenType = ORKGetVerticalScreenTypeForWindow(newWindow);
[self updateConstraintConstants];
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_progressView = [ORKProgressView new];
_progressView.translatesAutoresizingMaskIntoConstraints = NO;
_screenType = ORKScreenTypeiPhone4;
#if LAYOUT_DEBUG
self.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
@@ -75,29 +67,53 @@
#endif
[self addSubview:_progressView];
[self setNeedsUpdateConstraints];
[self setUpConstraints];
[self updateConstraintConstantsForWindow:self.window];
}
return self;
}
- (void)updateConstraintConstants {
ORKScreenType screenType = _screenType;
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
[self updateConstraintConstantsForWindow:newWindow];
}
- (void)updateConstraintConstantsForWindow:(UIWindow *)window {
const CGFloat CaptionBaselineToProgressTop = 100;
const CGFloat CaptionBaselineToStepViewTop = ORKGetMetricForScreenType(ORKScreenMetricLearnMoreBaselineToStepViewTop, screenType);
[_topConstraint setConstant:(CaptionBaselineToProgressTop - CaptionBaselineToStepViewTop)];
const CGFloat CaptionBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window);
_topConstraint.constant = CaptionBaselineToProgressTop - CaptionBaselineToStepViewTop;
}
- (void)setUpConstraints {
NSMutableArray *constraints = [NSMutableArray new];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView);
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_progressView]-(>=0)-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
_topConstraint = [NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]; // constant will be set in updateConstraintConstantsForWindow:
[constraints addObject:_topConstraint];
[constraints addObject:[NSLayoutConstraint constraintWithItem:_progressView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[NSLayoutConstraint activateConstraints:constraints];
}
- (void)updateConstraints {
[self removeConstraints:[self constraints]];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_progressView]-(>=0)-|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
_topConstraint = [NSLayoutConstraint constraintWithItem:_progressView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1 constant:0];
[self updateConstraintConstants];
[self addConstraint:_topConstraint];
[self addConstraint:[NSLayoutConstraint constraintWithItem:_progressView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[self updateConstraintConstantsForWindow:self.window];
[super updateConstraints];
}
@@ -0,0 +1,36 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "1x"
},
{
"idiom" : "iphone",
"scale" : "2x",
"filename" : "holepegtest1@2x.png"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"scale" : "3x",
"filename" : "holepegtest1@3x.png"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"scale" : "2x",
"filename" : "holepegtest1@2x~ipad.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,36 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "1x"
},
{
"idiom" : "iphone",
"scale" : "2x",
"filename" : "holepegtest2@2x.png"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"scale" : "3x",
"filename" : "holepegtest2@3x.png"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"scale" : "2x",
"filename" : "holepegtest2@2x~ipad.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

@@ -0,0 +1,36 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "1x"
},
{
"idiom" : "iphone",
"scale" : "2x",
"filename" : "holepegtest3@2x.png"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"scale" : "3x",
"filename" : "holepegtest3@3x.png"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"scale" : "2x",
"filename" : "holepegtest3@2x~ipad.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

@@ -0,0 +1,36 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "1x"
},
{
"idiom" : "iphone",
"scale" : "2x",
"filename" : "holepegtest4@2x.png"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"scale" : "3x",
"filename" : "holepegtest4@3x.png"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"scale" : "2x",
"filename" : "holepegtest4@2x~ipad.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

@@ -0,0 +1,36 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "1x"
},
{
"idiom" : "iphone",
"scale" : "2x",
"filename" : "holepegtest5@2x.png"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"scale" : "3x",
"filename" : "holepegtest5@3x.png"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"scale" : "2x",
"filename" : "holepegtest5@2x~ipad.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,36 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "1x"
},
{
"idiom" : "iphone",
"scale" : "2x",
"filename" : "holepegtest6@2x.png"
},
{
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"idiom" : "iphone",
"scale" : "3x",
"filename" : "holepegtest6@3x.png"
},
{
"idiom" : "ipad",
"scale" : "1x"
},
{
"idiom" : "ipad",
"scale" : "2x",
"filename" : "holepegtest6@2x~ipad.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

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