From e39fd21dcb4b2f164c05f73d1822059ef5322568 Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 29 Apr 2024 20:09:02 +0530 Subject: [PATCH] Committing version 1.0.4-beta --- .gitignore | 2 +- .swiftlint.yml | 137 + Docs/93-style-info-card.png | Bin 0 -> 442313 bytes Docs/94-style-buttonlog.png | Bin 0 -> 148552 bytes Docs/95-style-checklist.png | Bin 0 -> 150222 bytes Docs/96-style-numeric.png | Bin 0 -> 212214 bytes Docs/97-style-env-example.png | Bin 0 -> 53574 bytes Docs/{show-api-key.png => api-key.png} | Bin ...cation.png => biometric_authenticaion.png} | Bin ...w-api-key-details.png => client-admin.png} | Bin ...sword_less_01.png => passowrd_less_01.png} | Bin ...sword_less_02.png => passowrd_less_02.png} | Bin .../CareKitListView.swift | 157 - OTFMagicBox Watch Watch App/ContentView.swift | 20 - .../OTFMagicBox_WatchApp.swift | 17 - .../OTFMagicBox_Watch_Watch_AppTests.swift | 36 - .../OTFMagicBox_Watch_Watch_AppUITests.swift | 41 - ...ox_Watch_Watch_AppUITestsLaunchTests.swift | 32 - OTFMagicBox.xcodeproj/project.pbxproj | 872 +++--- OTFMagicBox/API/OTFNetworkObserver.swift | 10 +- OTFMagicBox/API/OTFTheraforgeNetwork.swift | 143 +- OTFMagicBox/API/SSEAndSyncManager.swift | 35 +- .../API/TheraForgeHTTPInterceptor.swift | 56 +- OTFMagicBox/AppDelegate.swift | 136 +- OTFMagicBox/AppSysParameters.yml | 145 +- OTFMagicBox/CheckUp/CheckUpView.swift | 52 +- OTFMagicBox/CheckUp/CheckUpViewModel.swift | 41 +- OTFMagicBox/CheckUp/CountProgressRow.swift | 34 +- OTFMagicBox/CheckUp/PercentProgressRow.swift | 32 +- OTFMagicBox/Consent/ConsentDocument.swift | 88 +- .../Contacts/ContactsViewController.swift | 26 +- OTFMagicBox/ContentView.swift | 66 +- .../Datastore/CareKitStoreManager.swift | 119 +- .../Datastore/CloudantSyncManager.swift | 67 +- OTFMagicBox/Datastore/OCKStoreManager.swift | 22 +- OTFMagicBox/HealthData/HealthDataStep.swift | 26 +- OTFMagicBox/HealthData/HealthRecordStep.swift | 30 +- OTFMagicBox/Library/ActivityLoader.swift | 55 - OTFMagicBox/Library/ActivityManager.swift | 132 +- OTFMagicBox/Library/Constants.swift | 137 +- .../Extension/Environment+StoreManager.swift | 17 +- .../Library/Extension/Extension+Array.swift | 14 +- .../Extension/Extension+Character.swift | 68 +- .../Library/Extension/Extension+Date.swift | 64 +- .../Library/Extension/Extension+Font.swift | 73 +- .../Library/Extension/Extension+Image.swift | 64 +- .../Extension/Extension+OCKAnyTask.swift | 20 +- .../Library/Extension/Extension+String.swift | 29 +- .../Library/Extension/Extension+UIImage.swift | 84 +- .../Extension/Extension+URLRequest.swift | 70 +- .../Extension/Extention+Notification.swift | 63 +- .../Extension/Extention+ViewController.swift | 8 +- .../OCKHealthKitStore+Extension.swift | 20 +- OTFMagicBox/Library/HealthKitManager.swift | 165 +- OTFMagicBox/Library/HealthRecordManager.swift | 89 +- .../Library/KeychainCloudManager.swift | 81 +- OTFMagicBox/Library/LoaderView.swift | 55 + OTFMagicBox/Library/LocalAuthentication.swift | 88 +- OTFMagicBox/Library/Metrics.swift | 136 +- OTFMagicBox/Library/OTFColor.swift | 30 +- OTFMagicBox/Library/OTFFont.swift | 46 + OTFMagicBox/Library/OTFHealthKitManager.swift | 86 +- OTFMagicBox/Library/UIColor.swift | 96 +- .../Library/UploadDocumentManager.swift | 40 +- OTFMagicBox/Library/UserDefaultsManager.swift | 71 +- OTFMagicBox/Library/Yaml/DataModel.swift | 64 +- .../ModuleAppYmlReader+DataModel.swift | 362 +-- OTFMagicBox/Library/Yaml/YmlReader.swift | 137 +- OTFMagicBox/Login/LoginCustomWaitStep.swift | 70 +- .../LoginExistingUserViewController.swift | 111 +- OTFMagicBox/Login/LoginSteps.swift | 48 +- OTFMagicBox/Login/LoginViewController.swift | 200 +- .../SignInWithAppleStepViewController.swift | 103 +- OTFMagicBox/ModuleAppSysParameter.yml | 16 +- OTFMagicBox/OCKStore + SampleData.swift | 96 +- .../Onboarding/OnboardingItemView.swift | 99 +- .../OnboardingOptionsViewController.swift | 140 +- .../OnboardingTaskCoordinator.swift | 134 +- OTFMagicBox/Onboarding/OnboardingView.swift | 78 +- .../Onboarding/OnboardingViewController.swift | 71 +- .../Onboarding/PasscodeViewController.swift | 99 +- .../Onboarding/PasswordlessLoginStep.swift | 88 +- OTFMagicBox/Profile/ProfileUIView.swift | 215 +- .../ViewModel/ChangePasswordViewModel.swift | 9 +- .../ViewModel/DeleteAccountViewModel.swift | 8 +- .../Profile/ViewModel/LogoutViewModel.swift | 19 +- .../ViewModel/UpdateUserViewModel.swift | 122 +- .../Profile/Views/ChangePasscodeView.swift | 70 +- .../Profile/Views/ChangePasswordView.swift | 87 +- .../Profile/Views/ConsentDocumentView.swift | 77 +- .../Profile/Views/DeleteAccountView.swift | 25 +- .../Views/DocumentPreviewViewController.swift | 53 +- OTFMagicBox/Profile/Views/HelpView.swift | 72 +- OTFMagicBox/Profile/Views/LogoutView.swift | 77 +- .../Profile/Views/PDFKitRepresentedView.swift | 13 +- OTFMagicBox/Profile/Views/PDFViewer.swift | 24 +- OTFMagicBox/Profile/Views/ReportView.swift | 89 +- OTFMagicBox/Profile/Views/SupportView.swift | 62 +- .../Views/UpdateUserProfileDetailView.swift | 263 +- .../Profile/Views/UpdateUserProfileView.swift | 217 +- OTFMagicBox/Profile/Views/WithdrawView.swift | 72 +- .../Views/WithdrawalViewController.swift | 113 +- OTFMagicBox/SceneDelegate.swift | 74 +- .../Schedule/ScheduleViewController.swift | 121 +- .../ScheduleViewControllerRepresentable.swift | 71 +- .../Schedule/SurveyItemViewController.swift | 88 +- OTFMagicBox/Schedule/TipView.swift | 62 +- OTFMagicBox/StaticViews/CardBackground.swift | 15 +- .../CareKit/CareKitTaskViews.swift | 44 +- .../StaticViews/CareKit/ContactsSection.swift | 75 +- .../StaticViews/CareKit/TasksSection.swift | 191 +- .../StaticViews/CareKit/TasksViewModel.swift | 34 +- OTFMagicBox/StaticViews/PlatformPicker.swift | 18 +- OTFMagicBox/StaticViews/RK UI/RKTasks.swift | 6 +- .../StaticViews/RK UI/SurveysList.swift | 123 +- .../RK UI/TaskListRow+Extras.swift | 369 +++ .../StaticViews/RK UI/TaskListRow.swift | 2636 +++++++---------- .../RK UI/TaskListViewController.swift | 107 +- .../TaskViewControllerRepresentable.swift | 58 +- OTFMagicBox/StaticViews/StaticUI.swift | 68 +- OTFMagicBox/Styling/OTFStyle.swift | 29 + OTFMagicBox/Styling/OTFStyleColorStyler.swift | 107 + OTFMagicBox/Styling/OTFYamlStyle.swift | 75 + OTFMagicBox/Tasks/TaskItem.swift | 65 +- OTFMagicBox/Tasks/TaskItemView.swift | 68 +- OTFMagicBox/Tasks/TaskSamples.swift | 144 +- OTFMagicBox/Tasks/TaskViewController.swift | 74 +- OTFMagicBox/Tasks/TasksUIView.swift | 90 +- .../ViewModifiers/StyleModifiers.swift | 57 +- .../ViewModifiers/ViewDidLoadModifier.swift | 62 +- OTFMagicBox/Views/LaunchView.swift | 72 +- OTFMagicBox/Views/LoadingView.swift | 67 +- OTFMagicBox/Views/MainView.swift | 53 +- OTFMagicBox/Views/RingProgressView.swift | 16 +- OTFMagicBoxTests/OTFMagicBoxTests.swift | 62 +- OTFMagicBoxTests/OTFMagicBoxYamlTests.swift | 119 +- .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 OTFMagicBoxWatch/ContentView.swift | 50 + .../DataStore/OTFCareKitStoreManager.swift | 75 + .../DataStore/WatchStoreService.swift | 48 + .../Extensions/Extension+Notification.swift | 41 + .../Extensions/Extension+OCKTask.swift | 86 + .../Managers/SessionManager.swift | 109 + .../OTFMagicBoxWatch.entitlements | 4 +- OTFMagicBoxWatch/OTFMagicBoxWatch.swift | 44 + .../Preview Assets.xcassets/Contents.json | 0 .../Views/ActivityIndicatorView.swift | 44 + OTFMagicBoxWatch/Views/CareKitListView.swift | 110 + Podfile | 47 +- README.md | 390 ++- 152 files changed, 7653 insertions(+), 6661 deletions(-) create mode 100644 .swiftlint.yml create mode 100644 Docs/93-style-info-card.png create mode 100644 Docs/94-style-buttonlog.png create mode 100644 Docs/95-style-checklist.png create mode 100644 Docs/96-style-numeric.png create mode 100644 Docs/97-style-env-example.png rename Docs/{show-api-key.png => api-key.png} (100%) rename Docs/{biometric_authentication.png => biometric_authenticaion.png} (100%) rename Docs/{show-api-key-details.png => client-admin.png} (100%) rename Docs/{password_less_01.png => passowrd_less_01.png} (100%) rename Docs/{password_less_02.png => passowrd_less_02.png} (100%) delete mode 100644 OTFMagicBox Watch Watch App/CareKitListView.swift delete mode 100644 OTFMagicBox Watch Watch App/ContentView.swift delete mode 100644 OTFMagicBox Watch Watch App/OTFMagicBox_WatchApp.swift delete mode 100644 OTFMagicBox Watch Watch AppTests/OTFMagicBox_Watch_Watch_AppTests.swift delete mode 100644 OTFMagicBox Watch Watch AppUITests/OTFMagicBox_Watch_Watch_AppUITests.swift delete mode 100644 OTFMagicBox Watch Watch AppUITests/OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift delete mode 100644 OTFMagicBox/Library/ActivityLoader.swift create mode 100644 OTFMagicBox/Library/LoaderView.swift create mode 100644 OTFMagicBox/Library/OTFFont.swift create mode 100644 OTFMagicBox/StaticViews/RK UI/TaskListRow+Extras.swift create mode 100644 OTFMagicBox/Styling/OTFStyle.swift create mode 100644 OTFMagicBox/Styling/OTFStyleColorStyler.swift create mode 100644 OTFMagicBox/Styling/OTFYamlStyle.swift rename {OTFMagicBox Watch Watch App => OTFMagicBoxWatch}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename {OTFMagicBox Watch Watch App => OTFMagicBoxWatch}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {OTFMagicBox Watch Watch App => OTFMagicBoxWatch}/Assets.xcassets/Contents.json (100%) create mode 100644 OTFMagicBoxWatch/ContentView.swift create mode 100644 OTFMagicBoxWatch/DataStore/OTFCareKitStoreManager.swift create mode 100644 OTFMagicBoxWatch/DataStore/WatchStoreService.swift create mode 100644 OTFMagicBoxWatch/Extensions/Extension+Notification.swift create mode 100644 OTFMagicBoxWatch/Extensions/Extension+OCKTask.swift create mode 100644 OTFMagicBoxWatch/Managers/SessionManager.swift rename OTFMagicBox Watch Watch App/OTFMagicBox Watch Watch App.entitlements => OTFMagicBoxWatch/OTFMagicBoxWatch.entitlements (87%) create mode 100644 OTFMagicBoxWatch/OTFMagicBoxWatch.swift rename {OTFMagicBox Watch Watch App => OTFMagicBoxWatch}/Preview Content/Preview Assets.xcassets/Contents.json (100%) create mode 100644 OTFMagicBoxWatch/Views/ActivityIndicatorView.swift create mode 100644 OTFMagicBoxWatch/Views/CareKitListView.swift diff --git a/.gitignore b/.gitignore index 53904978..3b48da8d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ xcuserdata/ ## DS_Store -.DS_Store* +.DS_Store ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) *.xcscmblueprint diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 00000000..a83a01ec --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,137 @@ +reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji) + +excluded: # paths to ignore during linting. Takes precedence over `included`. + - Carthage + - Pods + - SwiftLint/Common/3rdPartyLib +disabled_rules: # rule identifiers to exclude from running + - trailing_whitespace +# - force_cast +# - force_unwrapping +# - force_try + - empty_enum_arguments +# - overridden_super_call +# - sorted_imports +# - vertical_whitespace + - inclusive_language + - trailing_closure + - file_name + +opt_in_rules: # some rules are only opt-in +# - missing_docs + - yoda_condition # Default configuration: warning + - empty_count # Default configuration: error, only_after_dot: false + - empty_string # Default configuration: warning + - closure_end_indentation # Default configuration: warning + - closure_spacing # Default configuration: warning + - explicit_init # Default configuration: warning + - first_where # Default configuration: warning + - number_separator # Default configuration: warning, minimum_length: 0 + - explicit_failure_calls + - fatal_error_message +# - extension_access_modifier +# - implicitly_unwrapped_optional +# - operator_usage_whitespace + - vertical_parameter_alignment_on_call + - multiline_parameters +# - multiple_empty_lines # Defined into custom roles + - nesting + - file_name + - convenience_type + - modifier_order + + - private_outlet + - prohibited_super_call + - protocol_property_accessors_order + - redundant_nil_coalescing + - syntactic_sugar + - comments_space + - conditional_returns_on_newline + +conditional_returns_on_newline: + if_only: true + +line_length: + warning: 200 + error: 250 + ignores_function_declarations: true + ignores_comments: true + ignores_urls: true + +function_body_length: + warning: 300 + error: 500 + +function_parameter_count: + warning: 6 + error: 8 + +type_name: # class name + min_length: 3 + max_length: + warning: 60 + error: 80 + +type_body_length: + warning: 300 + error: 500 + +file_length: + warning: 1000 + error: 1500 + ignore_comment_only_lines: true + +identifier_name: # Variable name + allowed_symbols: "_" + min_length: 1 + max_length: + warning: 60 + error: 80 + excluded: + - id + - URL + - GlobalAPIKey + +large_tuple: + warning: 4 + error: 5 + +private_outlet: + allow_private_set: true + +#nesting: +# type_level: +# warning: 3 +# error: 6 +# statement_level: +# warning: 5 +# error: 10 + +number_separator: + minimum_length: 8 + +#cyclomatic complexity below 4 is considered good; +#cyclomatic complexity between 5 and 7 is considered medium complexity, +#between 8 and 10 is high complexity, +#and above that is extreme complexity. +cyclomatic_complexity: + ignores_case_statements: true + warning: 7 + error: 11 + +custom_rules: + comments_space: # From https://github.com/brandenr/swiftlintconfig + name: "Space After Comment" + regex: '(^ *//\w+)' + message: "There should be a space after //" + severity: warning + explicit_failure_calls: + name: “Avoid asserting ‘false’” + regex: ‘((assert|precondition)\(false)’ + message: “Use assertionFailure() or preconditionFailure() instead.” + severity: warning + multiple_empty_lines: + name: "Multiple Empty Lines" + regex: '((?:\s*\n){3,})' + message: "There are too many line breaks" + severity: error diff --git a/Docs/93-style-info-card.png b/Docs/93-style-info-card.png new file mode 100644 index 0000000000000000000000000000000000000000..d7fddde581bcdee997de9ca95fe14778a7b1a8cb GIT binary patch literal 442313 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

`=T` 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 z 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
pHxnq9cL!s)Jt^c5CnU)}-$1bZ2kpeKTWTFK&`P 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 a1wi1rg&no&;*BKWkG6(^diC805&s9k!5lsS literal 0 HcmV?d00001 diff --git a/Docs/94-style-buttonlog.png b/Docs/94-style-buttonlog.png new file mode 100644 index 0000000000000000000000000000000000000000..84398d8cebfe6773470c10ddc681ff354f0df9bd GIT binary patch literal 148552 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�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

B4l~aHf_%g zIrhF%kC*R5h-*YywkKEvwq$^GfzI&+TJ)V5>)9*E7c6yC+yGYUaD9>pl4fThKjL)+ zL!-rvY}6I2y5E3QM{#24ORow<(YO=My;;t%zYd-w*Iw+6?AK;V8~cW!Q@Rc{d19Zkgcjvw&Wy0qgX%gbxqDfYU}te6|R7-ftF zGxU)7VGJK3BBMaf*5Y7uX8x@yvLL(cV>cs7W%du{lW*A`zOg`;4S$m}>3$nN1AC!E z$lk4osp2^cz2w*DltTss^u`(m;rYB07Qte5X-`!JF`rdU67N-2Y3#a@Dn`mFJVp|a z1j8Z(c}H9yJL0$iJ@@{Yx(`po$LnzqJJQ9)r^g!oHoaBAB6t&_D9qr>_cn(D|}!|~XX zymobD_5(X%5H5Tx(|jI$t zibMq-qBUeLNsgu^M&lbBZD*PzP7wyNczr@&pXEMM>KISh0hak5qhx3p+hykI zSxGf`ytSHB;+HwPmCqlC-s{-!JjyG3C3jll0Q zr9f9UDL^YgzeKLp#~lCT75IrC;qbr$OnPNT>?(S1cAxN$U$OSB%*N@1kI%6IG0j8~ z*8u&&FNgi2qE4-N;i>2tpw*896wU*G;lq-b{<4;dQbrmo6DvaUZopaPsQBhf9 zdB*g|Kq_LO(4kV}_5JL@lPLND?Tr*r%%1CvRMd_7!`Hs|^Tk?`1%ld@Wx4(;PEA07 zbG5e}BX$QED(_1nYK_GRp~bcPx9*8qIK?Fl>qs`f^9PCz#siOLgYvZO7#MgFE%?73 z>)eOY{`3b1IYj$`aqeuo%ke+(*txxfhr)*q+yW2vg&A;&v2Jl2;(z?KJD|IU=KnB& zm}^h%qkEkG^5>2P`f@Y#OIm7hl$OfwgapId7$te`IJ1Mb})+S?Io|wOv_^#@qZ75!&oUJ&c?>($B-l5 z=og~+V62Dy>RG_VR?FBPSmgZihc(C$!%`be4i`bY)jQo~U6`g61mYKxHUdzrcU z(4oV3RqrUnVgS$-*A$i<)7N*3QrJt$*OI6IYhsVhh5D*pC27-SE-y0|CVpX-eDd}F ziV=QoXeMlLZXXKTDUjPIVon{bz?7E&8pix;zd$~CHgQ^zM27-(la$xG_cI_qcr0$5 zEe&*#*TJ#|lF%U3m~b@W>R%S89Ge>|FBGf0Zt-154}c4nKRo(=#7mC?Ua+O7H-yZ~ zXeW5^RK8%HHD{Rvlm7e3rgYALhI`>V{Qc&ChckPFmQ4zDASZSZ3H;yRDi35^|6KO3 ocKOF7|7wjt>*fDx62E=^b%&Uu&9{E{4}mXL6|Fl3x6J+j7qj#VJOBUy literal 0 HcmV?d00001 diff --git a/Docs/95-style-checklist.png b/Docs/95-style-checklist.png new file mode 100644 index 0000000000000000000000000000000000000000..b5ca4261d72b3b216cbcf0f2985543149f6d6794 GIT binary patch literal 150222 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�gk^`#nq9Om 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É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 I-n9$+KY4IFLI3~& literal 0 HcmV?d00001 diff --git a/Docs/97-style-env-example.png b/Docs/97-style-env-example.png new file mode 100644 index 0000000000000000000000000000000000000000..77bc96276d3280563e36dbc574b6baeedfe71b5c GIT binary patch literal 53574 zcmeFY1zVgkvjB>_d+}1VxVsgKTXA=a`{FLet+ARthsrNosXAfTZjARyxr;J`IXUtMP)AW(!X#l)1P z#l*;!ob10_+L%E=NQEb9z-y`uE)5fMWsDj?ff z5)W4w`7>TsPANqM2?oEh`L{El>g?>YNZ8hEYFNO!Mu%I6J@EBH*!<1;V6E8IRvb#KeRa$v%y$IcsR@y+@xQl8+SH$U1>z)IC}tryh1NIk8*xg5c@*(sXjVGH#xd@ekFGOsVHp%hAgGocXBgTSp2b495PnESW z#05fy>WN8lD6Fu?qhE}aar&$<`1cR{Bx!vlaLuao;Cv`&c(mSp( zu!?S(M@PwiF*mTv4uvc4_`qr*8bv%AmJ3t}`0?PM)rj=T5YJ)m#fB6ALN>s_DNE&F zV8oyrpmz}pLx$SLF>#FG;g&d#%|Lb%Gi&4RvwQq;HB#-a45=H37dFM^eKK{kitC*{_B=v z7!0|eg>H761_aW_cb70VViM7iwnil(3V4AZJm}*7y6%igu~?{IWuX+wKfOo-m}~@6 z?U`(9-ux!fYc@aNnNlQ00az%+e5MizZOys;)Ef7#hLqRe=J`g7(~A@I5m&3+uPl~g@ixb^Hq_HM zX7VlP$=f~VVHsP;|9o)5n5Oz>39}57rD|6bdm)4*X**~BPQ0T9F0X(1W;lSa$FGm5 zt+qzypmnbKw#ob3EiOXg$i}q4ptOKI#n{+q!>TQO(XOp9cZJ>$6-*U&5JMfz5sQl% znvZVK)3(nOh;%7Qlho&eTL?Ue6aJA~Y)xpup7~i=eSe`#G;axv;NU3?K4bq>3iUAPod_08VM>B<@trsv zO4MO-@i3gUfHAR=pGc;RHHal&?3W%?e%Yb+NP{neyI6OOw3 zyOEhDm3q*;$@ry^K|f!${@EvmzGEI}w_ti66vaM|2UBmn4g`Zp`$3{h^_S0Y7#F>r zm=-Xf0-?Jzx;{pIG{q{!kU>leE)Nb0p1ssMp=kSr72YCFluP4{rxLc@cii{2&!um@ z54#U-$HZ7TT%3)ZH_lsnnv$u+UsXn1Y(<(+q2p*Oq?6})<`R%q9A_El z5}|Ii7NHtpD2JWZt@RA2q=kg_fhE(-T8@W)txjaVSvhW5|KjKAl`_G_^!U79ZmS|F z1V|%jBAEPJ#6CyAeFL{0^wfI`eGB_!_SAY;dFsbzNB~2$N5H^t!O>(NMzlgSK&Zf~ zYwx~N<(7KSl4aCpWY&9++G-L^xJ=alL7scXX72l(y^S%k6$6*PiT6m;qWB_Z7v-wy zk73pXQk9mHtdc3fk7LK#LlhFY$e*K{;}&MOX&=&lq)Cr+rPXKna5b_jaximk+WKw= z8h6(XRcRVc8&8{CTJf$pg_vdTlhD`T&VC-XN}AUy1ubwb3@_Z26P35x-rDkTedTiD z0@+wLyfq})TH91EW1gqF^17a$F|Fp^1Mju&)$UV>mEh6gb9(tgW4430^?SeeT8C@` z^7(3rkx5R8$@q@>zVhMnbMmzV8UP9|`Ul<%j~S7zvK6CvDXpLCB!XjUNv8#N>Py?{ zC+kPAn-bOG4s7zWA3zPHMWA*(@k5jEba)NN;s_fo$yW3LY)Z7+i`ZsNw`TH-pCKvTy#G(8ALm`0;Lc1}^e0t$>p%xmo4-`%ZYI4OjTZTs@1 zo~5KsZ!7?Shok+xi?3Q=!*dDqL^)_YJ#JqKGE#?GLrub~S*z8m6?Y~2#>4oD6l1dp zIzPSXeKG8b4{i-_2%qUoro78{l&+V)NC=9jkLMrciB01@Fpe;aU@4$WN=#2|;jH(w zxm-#zX&q>er6+MSX&Zki*_~8m`4z{%eI$Mtz83yGi(oly$v@NKkk`z)_6AV!bnzsM z9oOmi>PFwH+yWtZ!{P>-f9Uvt`(Zt;BW;x3tLCNlbFJqOn{Dmw(zB{F)a483T<3;; zls)Q0;DpMs>?l9w4Ay>_HcgsbI$w#{895WKo5KC?HYcYn$}csXWW!`xo2uEUetWC= z4KoJ$=*X`~rAWeZ(&;sRe-2cq=Nc^UXYmxg)Nzz=R{`F9_MW3CwI7_#1%3^uH(TPd z(fg>6+C(l>)wUi4Pb>?iuyLCMFZ!AKar^BLsV1$NSeepPt{+mS3{GU`WvB|c51+?2 zs~`->b*DNU_IfyxJCm+PnG#zQHIn_b`g8!>i_1xYh~2md#V}E z1FiB-e#~DiUM=crkyUm023>_*qh@g-ac`{Pw3Orwv=lnAJ34P46zRk_{CbUk)Hzr0 zE#KGaw8OSNT_bI5uV1Kba1EV~p>navtgA3TY|2b=gFUzU<5sp=r{m`KNLnS?a`?DW z*Uo+a^~`#Ca?QZ6>qO*E^r^cBF5gI7%)mt5#9T#2WiaPbjB#9O93GvYWW%-ZOltmH zW}a-!x0obiA|8D}+k5bX_{H#8LaYvT!-LJ8csJ1{`ct5xISHo6GuU@K2S^1Q9CT_Q=6CT(8_mSaJQH@F6UENl9 z!4uEH=su!GyO`Exk4V4LXIJ34h8xm_cL)C=>9+o|PxNyVdKBs0ixFrLs1Q4mhaN=Q zAQ<5X0I^>M=`(wpTz+5GX>4SCWqn28*l&M+={O7O4m~GJBb)S1J>F@IL5TC(i1PB;NLI_xJ2@;%y zAc_86mVl&%fc{54*c1u1gn;>H9|ds!_lpCkzcBxkL&t|ez=MBbfs=bS)W3Q|LuEt% zs|*eO@jLsf*03&xsJLgaTgXCX$#Lb*doGcvxmiBh!fAJa_+q(b+ zDJcF9^zZL~=rnV;{Le^s&i|Yic!JD-TbNmySeXBf8w@J&x0X-I(%sBPOWe{H%ro#9 zLL4k?0{`g$|7!Wqi2ntt`5#DbZkGRs{I8b(3#sO8<|Jls3my_6^q=MWC-8qa{u5Au z`R~mCixdCD=6}?J`7DGa!2Itu6GCdCB={>z#FpZUs^A2D5B;T|zz zQXmKj5eR8k2wCOf{ zC@TbSgDua-^&x7QS~9^ILkbEuxJKyAyZ(G}VWU@}d4pSh>rJw6sr351nxb0! z-NA{HlA}5bq*xaQ3(SAA>$+m0d898PNZs;UA-jkWhdLCqZj*S^htSgULSlH@*L)=>I4C|L6Aqme>EU3kkPd z3UbAkdYS&QI<9&v=hLpsdegBVgDaVAwhSAG+=X?0!rGELomxMnoQLg&jR? zQL`4RT#7^^;c^hc(aZEwqegEp}WI*igPc-eL$*8s@_`fxb8aY_M;2JI$6d;W0 zux_pkp8JAE&hXbxaF9hp(ZnHbw%i$U!bqn&d(vkj7JPfYu#_Dh0Q1LV+;r|%D6R;f zXa1#^ifLdDDs_**Noi&uQtzqtw{o@?D@=L>Sl!8gtx~u!pp@-mQ~^5Kk9qKRqZS99 zE;l!xZklDE7HRsEl6Z*+bkkEYFlg0_!`OCYwAv`_eGzAIY(q)Ga9BB@Y5f^NR%QGz zKF-lYmDWqXxeQL%vJOvF5$Hn-~v!H*U4$KHun?fwF-`p@#yzvBH@;0pC&_HMA{4x=`Pd8wf7=@_a7yv9G`!S&&uCZtFBkn z)=ZC0G&>1Z%G!P+f|Gvz!W7lrfY953hxSaiHwG|hI~9vDn6ySK~;cxiy@h=jkcR)DcVVT2dTWl++7784GUA<%6ZU z$FpLH05*+r94@5uP$)c=Q)@bfow(NO#Sv)Mi&lrU1L2Qr#03Cvoe-g_2F;>TapYr- z#TY$`^ttK}i_0=vu_;GsqhFEvBjH>ZiGg)SMMsb00oK-kuty)+o+>Z9t#6l}f&3C?Axi9tvr3 z^;-JHAep1zp3e=Uo^nyD)Z0{Lg+Km&Sylxt1iG!S;X1F!Po`MZ8j!*gyWs{c>-D)~ z7jUkZT-^V0E9QEMW}DXoQv7aJolNZjgm^i>@sEUY(90x@6v}$eO&Hr@ig?N@trUVZ zxeE_z%~Vd(hNB~1rYpUlB>HHdxlq1w6_PyL=(wyF(KbD2{@5j^5miCxA#J@%wu>Z< zX5^JsXLezp^y+1ty74(?46s);3pQ2>@_4rx#sT%LrL30~)b^P&VCJ>_T(wW|SqpfQ zrAHlGl;O61BnE|4rFYo0=(IUi6C@V&SVf-zKT{WEoaWuunsAfu4$wlhH#?bi)?WI6 zws(dJ+d~i=1H}8j2}(BEa&3Gre>CfS*FAR3%6g7?<`@D+Lo`JmXunVRs9fwnBE-OK zck;gLaf?~|dz>Dkrvk94+qq8m2Q1nK{`j;f#y6&uKizZ1DtDJ%LeoXzdv{3f3Jte6 zUP6OPEYPA(4vp6gm!y=tv`J_QAt&-o_s`1fBjS{-Eft>P7N`l{`?LHGs2Sd9PY$69 zY$WJvbUDI3pyiG2(13hP=j7UKZO=-GzvM@!;BI6qp51UxIge|H?Y2k0P7}lFC`4W4 zqB!KolTvFa9xZlFK(9%tAvCh|RgU|u`cUwlB9Glwyt>X2++7=(dFmDOUXHYJukWa3 z;Z|(%n2xVZ^M^BPj5)Ve|hnNAfY*jb$rrYi|LD-qg@*kd4d(}|_%E0&L zI9$3`rZ0vI*Ue6-Ei>a7wdb`;+IUs1$o1%{&Y zYttQ}#R!GIk0)ce6zJ9$!tV;y4I+Rt%b6p%s#=A8yV}`6RE^?+Q1JcVxRwmX+_t8e zn=4U-xyt@L{2sp!`ii~o?5q#CV0NGMp_a(`sG`cIp4p#@vN+J}yqQ_oe4d&b(V*#p zYX5sSb^U&t(XN1?J7lKYHc$Sxjd3C@IMb?BTwIcSqm|K<6dZ6m+0xT zdv#5gJsy&i!3^HF#*w_QIBH||p{mO4+~-xxk`OjK=5V`vuwHNLs%cltIp~ zBE2Ir`nda8JIl?of63@IM{|wT%}akyXbW`Ra^7)8VfLes=|BQ-IZaXeQd4`p{HI8j z+NSOLPtSWiY0WYV|oB50WVF zHT>FRUTsxZn8<8CjzQ`Xo1s!VzE|q_E#`px-cK@*goR%FAg4eGCW6UGRu7TT9fmj- zE%{?g?vQmj;C>9DQ}O9yvm$3>a=UB8%GIc2N{dI0#lwtFk&CZSDY6yc7_dW;)D@(- zZxam{iF|6D^%1_MGKPn4nk4%1rubl@HeGDA^p`L~ZN?~{!&y}xo7ssK^UYAK3TGwD zw+lw%3*huxMw`W#&o^1>=H^-^4HuoY&(~AErt-vbu3C8)I)OsL=ml9(H|u1ZH0M{X zYM|Ppg$4bLvvaf$0RL5b`?f7$+06zD+WFeAxC$*AVQ+H5+<8hQ_BOxjIIeNCLywHr*^R8Uq!r zh}OQM7C)Y&wLCh2-*D;;$lT)R!5*CAK< z!K-h$3{9z%M_!e6)E9&Wg*T8$gu7VL)f4|lRleSf3y)u+hYf>e9`Cap^>;m@wi*`y z@WPyN@A}g0a98F>rp^owwY7BC$>==V3P!w;VnlRAOa(GXVhD7t=Wb?_00 zeu{*=!Spc2qE5~y^z6c~eUiSikGB^z_|OIjOTIP>v%ueUZmmf*)Q>$9%kqa}D6v(9 zB>ga3zke9qaEwWxG90psps8+GC^eFRgwevNQ1SW8o1VO>ezK zM42-aeCH)g`O~?qyRt6ajks}s z1qRZ1cPKTK3c@oaa=uWIYqq1-3};os@G@``zeOveD5F@=d?8*j*uJD6hJK9Ki3DXg zUR~P4lRu(16)PGZV6~HrPLx>-?el@E@z0cCajfyl{aL5%_aExRU8|ujU%OxeT1cK& z_+zLMxWfibKS<5Ey37~yeMYic(~f#jvaN&8-C7c;y(`0X^mYf^gB^5!bjx8=HD`?F zcO6bt$IQ7yg*%8;+U#|VyZC;zeiNbVl+DP&>D2*Nr$2OlYjE+T@%^7ZOpH!}u$i#qU%;Duv{kTH%cSvLGy z=ne_sjbZsNuAkNDa%seX+vq{{@!LSwjJ zYgu)SITj^R4_Vro#ByA>O=)=sN}>R7a)AtW*6kD;WJEE9 z^L=@inqV!d2B*EzA<)bHDbFqf2i{k%nT*i!XD~n1eS*x&0~fweHmWI2>swyNnvSyp zV~%;>r*l?|3yaL18F6D6Vf&p2ioTcoF%e8^xI5V zx?9=?iikmYh&_kW5A4up=7~A*rcJ)A{GgyPoX{5HcY^kozoK*Go)LsUKU5%cG)7!E zCB2I6(G)DU@kF;E4c(Wbt3XTO%$aj4;i+39#o92rKnJ2lGK4`+9WT+lAJV9Ox#-dxbA(w_ZD`~i1_{W!|LAs~Tyw+n zZnEEzHfj>88w@S=<@idX@lrYh8}>c+o;A1(nG-VVfKm4T zx5fwhRLo*w?jhw~%}kbS`Wj-Ois^mNvv#@=iyv9qRU*fYTk@3A4&i+gM#Nq24csZr zLsj{kV7lkRF+Ub%51V>&wKFac+2qRCUrVTbh;J@b$WuM~Ub67qO@l0MWec2N{PD|r zo?g6Cbsbv7q8LXAm{CL|8x2CPuG@E^VN8ORKNjxHgb+wLPJ zx9b$H;ZFBnwroT=KWuaPrKBr$&4h+nEI%KJfYr=_NWH?zi|WBXeEzbBbdSi;9JO2L zM-wQ*T+*2y)C5GA{IT?WIFirf^xc+PKcEnHvvA9v!U%XK`)b3_*dMy2N`G^rlFEHZ z`_!Xa43p&}23ajFo_V-YBGNWkD5&bq*<;6`W#9a*4urM@${r zHH{>N@*{3xpev_d$b4=Q2Yx1lI)%~Vtpc}W+j3g0fR$fTbU)v2T-orT;`ve$NYec2 zv08$FS3l~hdnSMXTNi-_Hyb%;BAW4-TMSeUJtDtutdi%kS0|%m^^$K_1+eW~!E)%r zcow|ufKPClxjAw|_lSRdf#G})1;~Q3jRS_-nQZ0cBIdR5ltxywt#01~=R$U25+?ZV zdfgytth4<2d~0I9iIO$_%JT!W_tr(q{Pd(?#j+0IAQ5wr8!LD*+J1Bz9xA>vPIhH4 zEXVE$a_m?i%UDtQz5@7ReN`y=J6R6R7+k2@76ojt9hI${rqr|7da(6kiw4(AVA6hR zE^;f=9Ihz|T?h*=CDeUmyyDy>App(Y@2z z#)7FIB=842{5>uzP)+^EhF4|tIwHe_38!U(ZGUpmr^w85t9|z}Fbtd^^NC?V%Xq5% z+>xudk5Ma$V|a*6*coCt?L%mZGA#INT@Z?*s7C$VTRj6uB4Dv8K?J_u9^-=Y>64Po zuOeLDn)iNmNL5JZD0+Z5^AsOhaN{ck*wgGSw`;g2`c?w=bu=4j{-0?O#-aq5~h{)~TwmimQk>1~v|Q&2vU=Pvx` zG3t5bwTZc+{uU#yIaHYoSf1Feg&Z)T;pgBIPEVHZRO8x@i*_0$B+kl|4nLZgS`?y> zIVvVIKHiExxguY_5Lo3&>EvUts+-D|5u%;fu9_K5Mln?GT847*-!_ml& zgYy-Fkb0{OR#-2P6r_}W?0bE|oYDcbC5dpkd)6qIZKe%u3zfSwr`u|X$H25lf6S_! zksdy+>t=GA$ZjT8QI*XL6+zuQ( zw4O=ivQ*r+(*R7_bAv%k;9>*p8;|>WjeX@KF6BUID>#Ohql&uSoqhW=P-&8n{xfpP z@u_q{<5w@SeTv9vcoPo6`uVesfz!kgvE@bORLh%YcWK9#-Q69lft!h!?Q!SG3!mth zD>a$j57fVpnER(T=_F`;?NuzC!I81JX^X39ezM^j%grJl^d zCYUmN$=c_G!*EM<{GbQ&p`u}iaY)8_yfS2%$PhVdQETCix6o*XQp$PC75d8IfU6Z9 z-=?BSkJyar+Pa|LkRgn1WS8Ithz@&s6k-qK91Kk7`i zKyUJio5TP59R2-hr~l3`-8B z`b26yrGEI0v1!j^QV!OG0%0r)N{7gbbiq0iW+jpe0l@5`Dmx3Wi{i%$ zryKlSSIbZ~kEhrvmID<~W9=Zr2=pyGoq`h0W`IW>xEi{CDHx#!q~Wk`moztx{K|Vs z&ouV2unmL&DuLM}ITEERv_KaF9lGKemoxbbhUD^D>P1^9gFG%c!Y73W>;c#dFPv8s z_m}^1_QfIvVJwqE*eW<^c}4S({`|;T3#Es4XB{gk+E$CWw|V96Eg$~eCEr9CD5 z%2Q<--~0H__(kaIYxZ>g8%U@-H;8Pge7Gq8)Y$kcC2%;x~eK zB$O#-P66R>Z!(n@v6Zivu|Qli!1ZL;JE(QloBwVN>Y%Te{kL)hxfWJ_W&uXNNAdxT zot=?%x^PocCSyn_JA@S-4B4C0n!T*Qen+k~ssl66$UQv}0 zJ5tn1v-`p%Er>=Z@6jB9U16U=gOkf)QtX1}QC|qvtMBb;f3mlyIOOe)WN`q^1%YWk zqF(Phzv(G}$XXE{o$H{r%cy|Lw+<_P9c*YxrCZRTZ)xs9tfQ}Zk@3dWwmg;I{@ke0 zNVI{h*6kxyf3UY|k3aE5$Zvln=Xr6CbU~?NmZ>V z9VoK%z{T!E-Uag8eDjdbh1-eZX{DIkIsCCs_;@9pn^1M3I*?uUix$6yIpSxz8o8fp z-A=`DBfj2R)jbKr_D)}FsT^2e!O0#y1?Z;!sSh?(Yu5G(cf;fmCI2OV@9P8hhju-Q ztpEP-vFkwkd+gzXz{SQdkhU})5|jT&VKwc|_NNPN@hJb%&G4`gI><=jgWC{j#|iZ< z$Kv_^!_31F$Pr@Nn}l;eT^DZ=&T*Sa6ylE2rt23qI^~SovpnLJA{*CV*LiLu`>at{ zmH9@@-xazgwVf}Zn&E#23F@b|rkr?Y4J2p=1|?Qt8f-R|YF@uAFTKv92~Pl&ZC{qX zL$s*QcahnDGrh^3%sMA(bK03%MBWrHl@M?E17Ag(jqi$ zUqDy`D{J%U0^+N)8mp;VURZGT7mA1@DU1Q+Us4WU7MNSgMF z_~mOwaE)^BZTJW6CvQC4=>5)GhEX7bx>$bmJ&jkYX=^YiYd%ZJ@a3RWBlKZbPo5Hi z-)a{?2un8wE;qBZ|xAUrQ@8e=Tf}-%DO)gWXY z6rWJ@?JM1D;)mf@4#4T0N{P92HzmibK;n(MuW)D~+v<<6LU~4FIz9OS+uV^D>VTM9zy&`xlGYImXS9@pc1;us6$(0eO~veK}X8@P<|vo zk|Z@+&;9mPU1MFmu!CR@I%y1xm@9cJ^9K^Ghzhl~IX;6MG&`Dt95Xa7NztxDjN$ml z!n*+SsYIRSMJ~WIC>z??fjYZ3g(vtu@$S&c*%`q;9eI}5#lr7PUS<*Cd)A%Xr!zY*RLlN zsLT4D|8}GBfy91gN8t0Z2r3!R(YeH9ZDWP?}gi5_JY{vgBG< zE(i;WhvVu%x-mH)T^P{juO?>Yk-L)@~zqJZ8XPYc#T9BD?v(xmwd#Ih5pbak6!99a*TsW z8qEitRqt8bX_Ff^H?H#{fe$>oT09R{NgQ5@2UswBw&$c-k5R4iG*Hj+q0H5lrOgIp zGe**&u;nW#?BuKqI-MCq)@U4o5whq&>P0i;lcKdld|D}NIxx&d)eb6LgirP;l0EIjW&dNPkG&H z(fW`^e@4vmIvsuFL?-(c@AE$AW$JPTD9PiuS(*kC^sfd}DT;21A%4?1$>u2&?64_O znPr|KM1%Ex*HOXw)PeSH#R^4==w-|J_g!3DA{VvJq`Gd$P3|?a#)g5Z!8Lnk&T-76 zo^CDz7sh^SpvT59-%!Y42thoee+vE%>9N0q>ls#WCYy@d?cQzBm*#E_(m+GSpi(^~ zS!1tdFWLfujz*kj2sk_UN997%c&p)veL=5nAC}KKyBb->>g&_CL_xE+y6>~loq;nV zRNXf0BeOvzpfrbn;M=D@78Kt6X(NsOl{O*YUBd!{cCQkh;wUzpfk$z(Nxt&WrJ7hdT*(yE4yrF~rC3AN|9i*|z)i&FTb zszziggg$ny`gspk%-}@i!p~|~N$GyhIAmMM$J*#bzWMw%m!dx*wmO+XGT(pG_pyZB zQ6fUkP0!py_7D4koyJsS4DjbZVt4`hsmV^SV^6E2SsmLIxTHCyIBzeSV^+he!CkK9 zIB?98>g8~rXyd|KX<-h7$g-3Oa%~&!{Ghv?#in5WVg_lWkj9-@vyC>^cfDq{V*!|R z-i}oAt)Eqko?>8u_awTazIDri@qhOK;oD8byJXO(IWx@-uuFuFaMY7qyj<{i0@%%F zK(LKjH~Tllg<@@r2gmS~aqi<>M1v^>Nyb6;6W3LBk#363wZ(K2qtS{?MHq|mJy-`( zHlOsfr@#HS%h1Iw^1$5J?YeYWkO*)Ekl0M=~3so%AgCS>_oDu^1s?8Nqk z>8Xts_p&#}4@9e^mf{+Ed+D6uhU`AY+BsED`m%ab?zRPS3>}WbLZx61>@8lr7A|q` zkSfdvxISAjCDP~Xx9Mn~OlnjzEVSNq39ftODO5`HcuJc{R~_+fS{+KzM+3P5%8t69 z*1(nqufXW*y+mT^Yr64g&5C`TL*yUw7tx+ct@V42Abj~mrS?T$YlEwSEbvt`8nF?}0`ydH{LNe;X>Kd>t$>1?Yit!Ls(fKHj$Bvv!L ztvm3mzKzt}?OHN#UDEwVXSnJavIF`QvZn}}QAbHlzfOgoR2=oLsd`8%9Iko?W$ff0 zF7t8txMiz%e>gF*ijqUpKL23?tE6nE5Z)|>9&)`;<=@?l@#JRkU63xpp*y6k(()cN z@O%w#H6UjCa7=Pd0@TCr>s*ZLuRj%3U!xV~ZXq-4AgOPR5m7R^k96CZMu`aaz%fuV zqpfx~y^`*!9Hqbhe88&<>WqiuGDUhC*4z8i%oKej#L!l^^Xzdg*dakQjl)XVkv;wz zqriar0XGoCuPEBBB^b^CqvOqpU!m^ou=CHuNQhU#np7d(k6h+)Is}KF+kI?+v4z8i zSnNdmx*GsZR9EMGRRxIKc2J&b&;}#ClcNVepZ|kFJ^mUFKkP8cC?qkY6z4&1`;t6x z!SXo>DR97LsFlrT#z!T3l?r!u$jNnpIq$Kyg6wr)xewBC-uTNFb@$z*Y}4f!iX&2} zoo7D3-4bTB=K^?b^I}Y2cC<*mUGj_t1-RBiHa%v-CoR?3&`A>_S4kpzHERpEyLc+( z!BJT0LUEYK)mn=5mG9*zhv~-L4P;dr{9b#O(F%0T`f=AGXM$k1q4>o}z-OXVtx|i@ zu`g;w1VUJ9R>ogGx&mA!g5b!$zwCW0N;cJ!^$^dilqPwiIj0jU62iBkGrFgkerbwC zbAD4VZ)HJ*tb4~noSE;V#W3~Dz>!vz&cOjkDt+NN^AY?Aj>r>?cEx^{!8n2*QF7{J zlME(eu;iHB*eRpdf?YDSQ&l3R-f>V7iv+ne!~F=2z)Y1?ct?lEr|>)I0`l#ucX)gAvXKy7o5!xyGQsIJuwR7im16EOI=&pN%x!hs&<(N0D`qHW6|%uz%x@(S|4 zj`OlO@%cK6x~zHs!P^j^q_iYi!Kg9x1<)(m*whGREy0Y4Yc6}Utb6r=Wuj9p#x<)D zPyUoH9ovgGVJ->V&fx;qcKZyX24AfPDW|*rsaJTYe!D)qm1M2MSV?i?Y$@Imok_|& zGV3au50O^@0Uh!R3o%}r72ei^lnP2|do(|x7^G~|W%)^AEQ)=hh2A9sD2Y6fB)}+- zp-FZNSxRx7h!58Rw3zGsbEDxpt2?fpeZJ`D?i_wfn5?e5gSL`CcZazh2HoZDz&uHi z6LdSFv9bag@oiX}2m1h|ExY|OIzLKCU9{)dXX5Y2xf6AU`(S5#oK-z>X$#M(lSaW-}n z147P(9HBaZz&$rv4QA)bp~Ecy>M3(=@B(vPlYO$a`wjs|>Ydvr3~Ewvox zNyzEj8PuBx)DwP{?vA~M;D0Hb0?}D*K43ZvrWxr^9h^Q#;4wHkE2WFbf%cKUbnQ(F zCEsm(a(fNaP^EA+l0zgorKKK!we~spaMx&NCt>~`1szsnW2kAva|Qa2C@&jiqx{J$ zHeBJdeC|CSP2&o3&HlGjN?mL${^0=HOdYWD>M?I+=TKN~5$wNp;+KikDp5MDbvB5X z?IDX?fB_!UnaNc!+I_=!CcHsOKOo(W9A zaU~OGUFfNIsO;XrlFn(pa`)3?*RAB*Cq9*)SvWsMaLA|75j2pEJB+lQ>+naeQ%G}F z$(Lnw7+O&*%0Px2fT*@;015jE<1JF-b;pLM$Y&*EcbICyAGNgvvq> zgUtm^-Lo@tpG)-fqKYWi6>2 z&s*CM#%8~2V8UQAsORu&G#^rU?;O6wK#}%dg+lTnt*5&h0vR29f54usncew&O#6Gw}u9|0|MlwkGXlK zz;KLCdo;x)?|xfg1<9gczJ4 zBEQ1QAUWwywS}fMWxEHcbu#*oPwwlHt%m6oNc5XxxnG&-^h(_Pu3auyv|%Cdb#>R@ zXj94@CO@p3XGnd(iiJmdHU&Fd8NlKZ2TRpj2m`4AYM1E9SHV-Def*8yj-)HZ4qWv9?pr3qpGzCA( z*qx*Ck&oAFZI1>NLM84ueGGO+lMhQ0)kv+U+4LNaFv-RrHL0Q}*t7&UlnWyc>kzl? zu-F1_?;bE|nqC2)EtEf|JXQ|ssRLB57Q2>g$`8-E9WH1Ka}wkpVeWE7dvNzS5s4I~ zPebkr89$-`ilwdXMEzYS61u*IWTKk@aZNo}w4rt@W{hKjtZY42V)Z}g^76wnb9k@n z*v{Gt&cx_79)m(ST2^iw=iuCbr)~fshd#~KEqK}Bv0qGDGhqL1b9b;fH+=G1HeA- zc#+0on=XoX(JM|_>EXx>tVyP7HuKhV2oTlMO|qHOj)^;G9T)7hj8KLd`1KeO`yQJ9 zJUQ%n)m?Ofw`*Ta_EZOsEL`Vxvixjb-F@Pe0kd61DHY6-*ntLQT_d6WI>%+5C2L@m zt1(0p56Fp?X}XE{bWg{kv>Ul@T^aF;^r-o&d0yn}|R!TDz9TCLL`woS21Xiu8 zXT|NTFvei9#DMM-`YvV|7^rX&_ucC{7m%Nknd%CK+yQ=@c8omCOXzQ_e^MLMQ z#;NYJW_h^Il$I3YbLIJ*WO=w$_OkK#q$pB7?05CwAwdZnk?$iqP1k$h-_2NI(^+B& zHn5$pZa0#;?NMV0G=(q|HT1q}WKW56-_cMI+=Ws)NlMgYo6EuF7t@L@&?dO<2=qSS z8zVPaz1yLVapASvO!jVjgK?el)mB6jQ+%Ym@P)Td+krl@C91gp<(F?qJU94Zsc|q7 zE5+*fV&avU3zG~Q zzFx&iZLBpPs z3JgssfUKxCIVsW(Uu5Hdy^nz0HPqn*

N1a%s&B)h6c#3E^pz8K?jj{5~8enQUll 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 literal 0 HcmV?d00001 diff --git a/Docs/show-api-key.png b/Docs/api-key.png similarity index 100% rename from Docs/show-api-key.png rename to Docs/api-key.png diff --git a/Docs/biometric_authentication.png b/Docs/biometric_authenticaion.png similarity index 100% rename from Docs/biometric_authentication.png rename to Docs/biometric_authenticaion.png diff --git a/Docs/show-api-key-details.png b/Docs/client-admin.png similarity index 100% rename from Docs/show-api-key-details.png rename to Docs/client-admin.png diff --git a/Docs/password_less_01.png b/Docs/passowrd_less_01.png similarity index 100% rename from Docs/password_less_01.png rename to Docs/passowrd_less_01.png diff --git a/Docs/password_less_02.png b/Docs/passowrd_less_02.png similarity index 100% rename from Docs/password_less_02.png rename to Docs/passowrd_less_02.png diff --git a/OTFMagicBox Watch Watch App/CareKitListView.swift b/OTFMagicBox Watch Watch App/CareKitListView.swift deleted file mode 100644 index 45ec2c16..00000000 --- a/OTFMagicBox Watch Watch App/CareKitListView.swift +++ /dev/null @@ -1,157 +0,0 @@ -// -// CareKitListView.swift -// OTFMagicBox Watch Watch App -// -// Created by Tomas Martins on 13/09/23. -// - -import SwiftUI -import Contacts -import OTFCareKit -import OTFCareKitUI -import OTFCareKitStore - -struct CareKitListView: View { - @ObservedObject var storeManager: OCKStoreManager = .shared - @State var tasks: [OCKTask] = [] - - var body: some View { - List { - if tasks.isEmpty { - emptyState - } else { - ForEach(tasks, id: \.id) { task in - SimpleTaskView(isComplete: false) { - Text(task.title ?? "No title for task") - } - } - } - } - .task { - await fetchTasksAsync() - } - .refreshable { - await fetchTasksAsync() - } - } - - func fetchTasksAsync() async { - await withCheckedContinuation { continuation in - Task { - storeManager.coreDataStore.populateSampleData() - storeManager.coreDataStore.fetchTasks { result in - switch result { - case .success(let success): - self.tasks = success - continuation.resume() - case .failure(let error): - dump(error) - self.tasks = [] - continuation.resume() - } - } - } - } - } - - var emptyState: some View { - SimpleTaskView(title: Text(Constants.CustomiseStrings.noTasks), - detail: Text(Constants.CustomiseStrings.noTasksForThisDate), - isComplete: false) - } -} - -struct CareKitListView_Previews: PreviewProvider { - static var previews: some View { - CareKitListView() - } -} - -internal extension OCKStore { - - enum Tasks: String, CaseIterable { - case doxylamine - case nausea - case kegels - } - - enum Contacts: String, CaseIterable { - case jane - case matthew - } - - // Adds tasks and contacts into the store - func populateSampleData() { - - let thisMorning = Calendar.current.startOfDay(for: Date()) - let aFewDaysAgo = Calendar.current.date(byAdding: .day, value: -4, to: thisMorning)! - let beforeBreakfast = Calendar.current.date(byAdding: .hour, value: 8, to: aFewDaysAgo)! - let afterLunch = Calendar.current.date(byAdding: .hour, value: 14, to: aFewDaysAgo)! - - let schedule = OCKSchedule(composing: [ - OCKScheduleElement(start: beforeBreakfast, end: nil, - interval: DateComponents(day: 1)), - - OCKScheduleElement(start: afterLunch, end: nil, - interval: DateComponents(day: 2)) - ]) - - var doxylamine = OCKTask(id: Tasks.doxylamine.rawValue, title: "Take Doxylamine", - carePlanUUID: nil, schedule: schedule) - doxylamine.instructions = "Take 25mg of doxylamine when you experience nausea." - doxylamine.asset = "pills" - let nauseaSchedule = OCKSchedule(composing: [ - OCKScheduleElement(start: beforeBreakfast, end: nil, interval: DateComponents(day: 1), - text: "Anytime throughout the day", targetValues: [], duration: .allDay) - ]) - - var nausea = OCKTask(id: Tasks.nausea.rawValue, title: "Track your nausea", - carePlanUUID: nil, schedule: nauseaSchedule) - nausea.impactsAdherence = false - nausea.instructions = "Tap the button below anytime you experience nausea." - - let kegelElement = OCKScheduleElement(start: beforeBreakfast, end: nil, interval: DateComponents(day: 2)) - let kegelSchedule = OCKSchedule(composing: [kegelElement]) - var kegels = OCKTask(id: Tasks.kegels.rawValue, title: "Kegel Exercises", carePlanUUID: nil, schedule: kegelSchedule) - kegels.impactsAdherence = true - kegels.instructions = "Perform kegel exercies" - - addTasks([nausea, doxylamine, kegels], callbackQueue: .main, completion: nil) - - var contact1 = OCKContact(id: Contacts.jane.rawValue, givenName: "Jane", - familyName: "Daniels", carePlanUUID: nil) - contact1.asset = "JaneDaniels" - contact1.title = "Family Practice Doctor" - contact1.role = "Dr. Daniels is a family practice doctor with 8 years of experience." - contact1.emailAddresses = [OCKLabeledValue(label: CNLabelEmailiCloud, value: "janedaniels@icloud.com")] - contact1.phoneNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(324) 555-7415")] - contact1.messagingNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(324) 555-7415")] - - contact1.address = { - let address = OCKPostalAddress() - address.street = "2598 Reposa Way" - address.city = "San Francisco" - address.state = "CA" - address.postalCode = "94127" - return address - }() - - var contact2 = OCKContact(id: Contacts.matthew.rawValue, givenName: "Matthew", - familyName: "Reiff", carePlanUUID: nil) - contact2.asset = "MatthewReiff" - contact2.title = "OBGYN" - contact2.role = "Dr. Reiff is an OBGYN with 13 years of experience." - contact2.phoneNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(324) 555-7415")] - contact2.messagingNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(324) 555-7415")] - contact2.address = { - let address = OCKPostalAddress() - address.street = "396 El Verano Way" - address.city = "San Francisco" - address.state = "CA" - address.postalCode = "94127" - return address - }() - - addContacts([contact1, contact2]) - } -} diff --git a/OTFMagicBox Watch Watch App/ContentView.swift b/OTFMagicBox Watch Watch App/ContentView.swift deleted file mode 100644 index 67586957..00000000 --- a/OTFMagicBox Watch Watch App/ContentView.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// ContentView.swift -// OTFMagicBox Watch Watch App -// -// Created by Tomas Martins on 14/08/23. -// - -import SwiftUI - -struct ContentView: View { - var body: some View { - CareKitListView() - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/OTFMagicBox Watch Watch App/OTFMagicBox_WatchApp.swift b/OTFMagicBox Watch Watch App/OTFMagicBox_WatchApp.swift deleted file mode 100644 index 3414d1a2..00000000 --- a/OTFMagicBox Watch Watch App/OTFMagicBox_WatchApp.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// OTFMagicBox_WatchApp.swift -// OTFMagicBox Watch Watch App -// -// Created by Tomas Martins on 14/08/23. -// - -import SwiftUI - -@main -struct OTFMagicBox_Watch_Watch_AppApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/OTFMagicBox Watch Watch AppTests/OTFMagicBox_Watch_Watch_AppTests.swift b/OTFMagicBox Watch Watch AppTests/OTFMagicBox_Watch_Watch_AppTests.swift deleted file mode 100644 index 5c4d594c..00000000 --- a/OTFMagicBox Watch Watch AppTests/OTFMagicBox_Watch_Watch_AppTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// OTFMagicBox_Watch_Watch_AppTests.swift -// OTFMagicBox Watch Watch AppTests -// -// Created by Tomas Martins on 14/08/23. -// - -import XCTest -@testable import OTFMagicBox_Watch_Watch_App - -final class OTFMagicBox_Watch_Watch_AppTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Tests marked async will run the test method on an arbitrary thread managed by the Swift runtime. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/OTFMagicBox Watch Watch AppUITests/OTFMagicBox_Watch_Watch_AppUITests.swift b/OTFMagicBox Watch Watch AppUITests/OTFMagicBox_Watch_Watch_AppUITests.swift deleted file mode 100644 index e9a496f5..00000000 --- a/OTFMagicBox Watch Watch AppUITests/OTFMagicBox_Watch_Watch_AppUITests.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// OTFMagicBox_Watch_Watch_AppUITests.swift -// OTFMagicBox Watch Watch AppUITests -// -// Created by Tomas Martins on 14/08/23. -// - -import XCTest - -final class OTFMagicBox_Watch_Watch_AppUITests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false - - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // UI tests must launch the application that they test. - let app = XCUIApplication() - app.launch() - - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testLaunchPerformance() throws { - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { - // This measures how long it takes to launch your application. - measure(metrics: [XCTApplicationLaunchMetric()]) { - XCUIApplication().launch() - } - } - } -} diff --git a/OTFMagicBox Watch Watch AppUITests/OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift b/OTFMagicBox Watch Watch AppUITests/OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift deleted file mode 100644 index 7abb99a2..00000000 --- a/OTFMagicBox Watch Watch AppUITests/OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift -// OTFMagicBox Watch Watch AppUITests -// -// Created by Tomas Martins on 14/08/23. -// - -import XCTest - -final class OTFMagicBox_Watch_Watch_AppUITestsLaunchTests: XCTestCase { - - override class var runsForEachTargetApplicationUIConfiguration: Bool { - true - } - - override func setUpWithError() throws { - continueAfterFailure = false - } - - func testLaunch() throws { - let app = XCUIApplication() - app.launch() - - // Insert steps here to perform after app launch but before taking a screenshot, - // such as logging into a test account or navigating somewhere in the app - - let attachment = XCTAttachment(screenshot: app.screenshot()) - attachment.name = "Launch Screen" - attachment.lifetime = .keepAlways - add(attachment) - } -} diff --git a/OTFMagicBox.xcodeproj/project.pbxproj b/OTFMagicBox.xcodeproj/project.pbxproj index 0d8aebaa..aff49b74 100644 --- a/OTFMagicBox.xcodeproj/project.pbxproj +++ b/OTFMagicBox.xcodeproj/project.pbxproj @@ -7,8 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 04CDFE9A4C5C79E8EACA8709 /* Pods_OTFMagicBox_Watch_Watch_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 44835E788FC7C51DB58219C2 /* Pods_OTFMagicBox_Watch_Watch_App.framework */; }; - 06540FA342BE7267771D8AF4 /* Pods_OTFMagicBox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55AC9A6EAEB0412B5C7F5D6C /* Pods_OTFMagicBox.framework */; }; 326086F7283E48A300888678 /* DeleteAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326086F6283E48A300888678 /* DeleteAccountView.swift */; }; 32AAA4A5283396CF00DA0DA8 /* ModuleAppSysParameter.yml in Resources */ = {isa = PBXBuildFile; fileRef = 32AAA4A4283396CF00DA0DA8 /* ModuleAppSysParameter.yml */; }; 32AAA4A728339E7F00DA0DA8 /* ModuleAppYmlReader+DataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32AAA4A628339E7F00DA0DA8 /* ModuleAppYmlReader+DataModel.swift */; }; @@ -16,6 +14,7 @@ 32C6DD9828D8A04700E453A4 /* LogoutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C6DD9728D8A04700E453A4 /* LogoutViewModel.swift */; }; 32C6DD9A28D8A06F00E453A4 /* UpdateUserViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C6DD9928D8A06F00E453A4 /* UpdateUserViewModel.swift */; }; 32C6DD9C28D8A08700E453A4 /* ChangePasswordViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C6DD9B28D8A08700E453A4 /* ChangePasswordViewModel.swift */; }; + 4CF07F71CAF10A608704FCFF /* Pods_OTFMagicBox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E86A26F2DE6C8AB4A0B19344 /* Pods_OTFMagicBox.framework */; }; 5A41D023266A9106007CCEB4 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A41D022266A9106007CCEB4 /* MainView.swift */; }; 5A41D034266A91CB007CCEB4 /* TasksUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A41D033266A91CB007CCEB4 /* TasksUIView.swift */; }; 5A41D037266A955C007CCEB4 /* TaskItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A41D036266A955C007CCEB4 /* TaskItem.swift */; }; @@ -71,18 +70,7 @@ 5AB1808F26BC58DE007AF766 /* HealthRecordStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AB1808E26BC58DE007AF766 /* HealthRecordStep.swift */; }; 7C7EC6792A65912C003B0FFB /* OTFNetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C7EC6782A65912C003B0FFB /* OTFNetworkObserver.swift */; }; 7C979A602A5731C200EBCE2F /* OTFColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C979A5F2A5731C200EBCE2F /* OTFColor.swift */; }; - 7CA3D2F32A8A43C300FCB048 /* OTFMagicBox_WatchApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA3D2F22A8A43C300FCB048 /* OTFMagicBox_WatchApp.swift */; }; - 7CA3D2F52A8A43C300FCB048 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA3D2F42A8A43C300FCB048 /* ContentView.swift */; }; - 7CA3D2F72A8A43C400FCB048 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7CA3D2F62A8A43C400FCB048 /* Assets.xcassets */; }; - 7CA3D2FA2A8A43C400FCB048 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7CA3D2F92A8A43C400FCB048 /* Preview Assets.xcassets */; }; - 7CA3D3042A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA3D3032A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppTests.swift */; }; - 7CA3D30E2A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA3D30D2A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITests.swift */; }; - 7CA3D3102A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA3D30F2A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift */; }; - 7CA3D3132A8A43C400FCB048 /* OTFMagicBox Watch Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 7CA3D2F02A8A43C300FCB048 /* OTFMagicBox Watch Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 7CA403032AB20C0F00A3D022 /* CareKitListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA403022AB20C0F00A3D022 /* CareKitListView.swift */; }; - 7CD965022AB6AA5E003E9394 /* OCKStoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467619A27DF8A1F00A3207E /* OCKStoreManager.swift */; }; - 7CD965032AB6B784003E9394 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AADFD4F264E9A880069FEF7 /* Constants.swift */; }; - 7CEB1FC52A8A5A83002918FE /* (null) in Embed Frameworks */ = {isa = PBXBuildFile; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 84146ED82BD14F4B007D768C /* TaskListRow+Extras.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84146ED72BD14F4B007D768C /* TaskListRow+Extras.swift */; }; 841CA60A275F719100C6861D /* ViewDidLoadModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841CA609275F719000C6861D /* ViewDidLoadModifier.swift */; }; 841CA60C275F827300C6861D /* CareKitStoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841CA60B275F827300C6861D /* CareKitStoreManager.swift */; }; 841FEFBB274E5CE100698892 /* SSEAndSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841FEFBA274E5CE000698892 /* SSEAndSyncManager.swift */; }; @@ -126,10 +114,26 @@ 849989DE2AD7CB1C009CBA41 /* PDFViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849989DD2AD7CB1B009CBA41 /* PDFViewer.swift */; }; 849989E02AD7CB25009CBA41 /* PDFKitRepresentedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849989DF2AD7CB25009CBA41 /* PDFKitRepresentedView.swift */; }; 849989E22AD7CC67009CBA41 /* UploadDocumentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849989E12AD7CC67009CBA41 /* UploadDocumentManager.swift */; }; - 849989E42AD7CD53009CBA41 /* ActivityLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849989E32AD7CD53009CBA41 /* ActivityLoader.swift */; }; + 849989E42AD7CD53009CBA41 /* LoaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849989E32AD7CD53009CBA41 /* LoaderView.swift */; }; 849989E62AD7D182009CBA41 /* Extension+Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849989E52AD7D182009CBA41 /* Extension+Array.swift */; }; 84A1758B2750A035001587BD /* Extention+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A1758A2750A035001587BD /* Extention+Notification.swift */; }; + 84EEAD042BBCA6D100414955 /* OTFStyleColorStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EEAD012BBCA6D100414955 /* OTFStyleColorStyler.swift */; }; + 84EEAD052BBCA6D100414955 /* OTFStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EEAD022BBCA6D100414955 /* OTFStyle.swift */; }; + 84EEAD062BBCA6D100414955 /* OTFYamlStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EEAD032BBCA6D100414955 /* OTFYamlStyle.swift */; }; + 84F43F502B4D6A4A009DFFF8 /* OTFMagicBoxWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F43F4F2B4D6A4A009DFFF8 /* OTFMagicBoxWatch.swift */; }; + 84F43F542B4D6A4C009DFFF8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84F43F532B4D6A4C009DFFF8 /* Assets.xcassets */; }; + 84F43F572B4D6A4C009DFFF8 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84F43F562B4D6A4C009DFFF8 /* Preview Assets.xcassets */; }; + 84F43F5A2B4D6A4C009DFFF8 /* OTFMagicBoxWatch.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 84F43F4D2B4D6A4A009DFFF8 /* OTFMagicBoxWatch.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 9004A9222AD7DD390084622A /* HelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9004A9212AD7DD390084622A /* HelpView.swift */; }; + 901700F42B63B856006C611C /* ActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 901700F32B63B856006C611C /* ActivityIndicatorView.swift */; }; + 902E18A62AE8F0A000F694F2 /* OTFFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 902E18A52AE8F0A000F694F2 /* OTFFont.swift */; }; + 90C79E452B4DCE120020D20F /* OTFCareKitStoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C79E3F2B4DCE110020D20F /* OTFCareKitStoreManager.swift */; }; + 90C79E462B4DCE120020D20F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C79E402B4DCE110020D20F /* ContentView.swift */; }; + 90C79E472B4DCE120020D20F /* CareKitListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C79E412B4DCE120020D20F /* CareKitListView.swift */; }; + 90C79E482B4DCE120020D20F /* Extension+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C79E422B4DCE120020D20F /* Extension+Notification.swift */; }; + 90C79E492B4DCE120020D20F /* Extension+OCKTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C79E432B4DCE120020D20F /* Extension+OCKTask.swift */; }; + 90C79E4A2B4DCE120020D20F /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C79E442B4DCE120020D20F /* SessionManager.swift */; }; + 90C79E4C2B4E862A0020D20F /* WatchStoreService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C79E4B2B4E862A0020D20F /* WatchStoreService.swift */; }; A8C0556B296D61770098D1FB /* Extention+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C0556A296D61770098D1FB /* Extention+ViewController.swift */; }; A8FCD2AA2A4C6EF7006E0B6E /* KeychainCloudManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8FCD2A92A4C6EF7006E0B6E /* KeychainCloudManager.swift */; }; A8FCD2AC2A4C6F0D006E0B6E /* LocalAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8FCD2AB2A4C6F0D006E0B6E /* LocalAuthentication.swift */; }; @@ -139,6 +143,7 @@ CE482CFB262C954A00C0A2D5 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE482CFA262C954A00C0A2D5 /* ContentView.swift */; }; CE482CFD262C954C00C0A2D5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CE482CFC262C954C00C0A2D5 /* Assets.xcassets */; }; CE482D03262C954C00C0A2D5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE482D01262C954C00C0A2D5 /* LaunchScreen.storyboard */; }; + FFB3790929612305437E0E08 /* Pods_OTFMagicBoxWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC70EC922D0E3C888B7C474 /* Pods_OTFMagicBoxWatch.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -149,26 +154,12 @@ remoteGlobalIDString = CE482CF2262C954A00C0A2D5; remoteInfo = OTFMagicBox; }; - 7CA3D3002A8A43C400FCB048 /* PBXContainerItemProxy */ = { + 84F43F582B4D6A4C009DFFF8 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = CE482CEB262C954A00C0A2D5 /* Project object */; proxyType = 1; - remoteGlobalIDString = 7CA3D2EF2A8A43C300FCB048; - remoteInfo = "OTFMagicBox Watch Watch App"; - }; - 7CA3D30A2A8A43C400FCB048 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CE482CEB262C954A00C0A2D5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7CA3D2EF2A8A43C300FCB048; - remoteInfo = "OTFMagicBox Watch Watch App"; - }; - 7CA3D3112A8A43C400FCB048 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CE482CEB262C954A00C0A2D5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7CA3D2EF2A8A43C300FCB048; - remoteInfo = "OTFMagicBox Watch Watch App"; + remoteGlobalIDString = 84F43F4C2B4D6A4A009DFFF8; + remoteInfo = "OTFMagicBoxWatch Watch App"; }; /* End PBXContainerItemProxy section */ @@ -179,26 +170,15 @@ dstPath = "$(CONTENTS_FOLDER_PATH)/Watch"; dstSubfolderSpec = 16; files = ( - 7CA3D3132A8A43C400FCB048 /* OTFMagicBox Watch Watch App.app in Embed Watch Content */, + 84F43F5A2B4D6A4C009DFFF8 /* OTFMagicBoxWatch.app in Embed Watch Content */, ); name = "Embed Watch Content"; runOnlyForDeploymentPostprocessing = 0; }; - 7CEB1FC62A8A5A83002918FE /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 7CEB1FC52A8A5A83002918FE /* (null) in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 23661129E1AA02D9A3410FC7 /* Pods-OTFMagicBox Watch Watch App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBox Watch Watch App.debug.xcconfig"; path = "Target Support Files/Pods-OTFMagicBox Watch Watch App/Pods-OTFMagicBox Watch Watch App.debug.xcconfig"; sourceTree = ""; }; + 2DC70EC922D0E3C888B7C474 /* Pods_OTFMagicBoxWatch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OTFMagicBoxWatch.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 32100A2B28AE5BB500035F5E /* .github */ = {isa = PBXFileReference; lastKnownFileType = folder; path = .github; sourceTree = ""; }; 326086F6283E48A300888678 /* DeleteAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteAccountView.swift; sourceTree = ""; }; 32AAA4A4283396CF00DA0DA8 /* ModuleAppSysParameter.yml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.yaml; path = ModuleAppSysParameter.yml; sourceTree = ""; }; @@ -208,8 +188,7 @@ 32C6DD9928D8A06F00E453A4 /* UpdateUserViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateUserViewModel.swift; sourceTree = ""; }; 32C6DD9B28D8A08700E453A4 /* ChangePasswordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangePasswordViewModel.swift; sourceTree = ""; }; 32E5138C28EC68F100A16FA5 /* Extention+ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extention+ViewController.swift"; sourceTree = ""; }; - 44835E788FC7C51DB58219C2 /* Pods_OTFMagicBox_Watch_Watch_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OTFMagicBox_Watch_Watch_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 55AC9A6EAEB0412B5C7F5D6C /* Pods_OTFMagicBox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OTFMagicBox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 58ADE8FC0AF041D6DF78CE64 /* Pods-OTFMagicBoxWatch.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBoxWatch.release.xcconfig"; path = "Target Support Files/Pods-OTFMagicBoxWatch/Pods-OTFMagicBoxWatch.release.xcconfig"; sourceTree = ""; }; 5A41D022266A9106007CCEB4 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 5A41D033266A91CB007CCEB4 /* TasksUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksUIView.swift; sourceTree = ""; }; 5A41D036266A955C007CCEB4 /* TaskItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskItem.swift; sourceTree = ""; }; @@ -267,20 +246,10 @@ 5AB1808926B9C76D007AF766 /* SurveyItemViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SurveyItemViewController.swift; sourceTree = ""; }; 5AB1808C26BC4ED6007AF766 /* LoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; 5AB1808E26BC58DE007AF766 /* HealthRecordStep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HealthRecordStep.swift; sourceTree = ""; }; + 62EB2116D692E7C5E54E80E1 /* Pods-OTFMagicBoxWatch.care.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBoxWatch.care.xcconfig"; path = "Target Support Files/Pods-OTFMagicBoxWatch/Pods-OTFMagicBoxWatch.care.xcconfig"; sourceTree = ""; }; 7C7EC6782A65912C003B0FFB /* OTFNetworkObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTFNetworkObserver.swift; sourceTree = ""; }; 7C979A5F2A5731C200EBCE2F /* OTFColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTFColor.swift; sourceTree = ""; }; - 7CA3D2F02A8A43C300FCB048 /* OTFMagicBox Watch Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "OTFMagicBox Watch Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 7CA3D2F22A8A43C300FCB048 /* OTFMagicBox_WatchApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTFMagicBox_WatchApp.swift; sourceTree = ""; }; - 7CA3D2F42A8A43C300FCB048 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; - 7CA3D2F62A8A43C400FCB048 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7CA3D2F92A8A43C400FCB048 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 7CA3D2FF2A8A43C400FCB048 /* OTFMagicBox Watch Watch AppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OTFMagicBox Watch Watch AppTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 7CA3D3032A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTFMagicBox_Watch_Watch_AppTests.swift; sourceTree = ""; }; - 7CA3D3092A8A43C400FCB048 /* OTFMagicBox Watch Watch AppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OTFMagicBox Watch Watch AppUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 7CA3D30D2A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTFMagicBox_Watch_Watch_AppUITests.swift; sourceTree = ""; }; - 7CA3D30F2A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift; sourceTree = ""; }; - 7CA403022AB20C0F00A3D022 /* CareKitListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CareKitListView.swift; sourceTree = ""; }; - 7CD965012AB660E8003E9394 /* OTFMagicBox Watch Watch App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "OTFMagicBox Watch Watch App.entitlements"; sourceTree = ""; }; + 84146ED72BD14F4B007D768C /* TaskListRow+Extras.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TaskListRow+Extras.swift"; sourceTree = ""; }; 841CA609275F719000C6861D /* ViewDidLoadModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewDidLoadModifier.swift; sourceTree = ""; }; 841CA60B275F827300C6861D /* CareKitStoreManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CareKitStoreManager.swift; sourceTree = ""; }; 841FEFBA274E5CE000698892 /* SSEAndSyncManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSEAndSyncManager.swift; sourceTree = ""; }; @@ -323,15 +292,34 @@ 849989DD2AD7CB1B009CBA41 /* PDFViewer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFViewer.swift; sourceTree = ""; }; 849989DF2AD7CB25009CBA41 /* PDFKitRepresentedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFKitRepresentedView.swift; sourceTree = ""; }; 849989E12AD7CC67009CBA41 /* UploadDocumentManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadDocumentManager.swift; sourceTree = ""; }; - 849989E32AD7CD53009CBA41 /* ActivityLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityLoader.swift; sourceTree = ""; }; + 849989E32AD7CD53009CBA41 /* LoaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoaderView.swift; sourceTree = ""; }; 849989E52AD7D182009CBA41 /* Extension+Array.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Extension+Array.swift"; sourceTree = ""; }; 84A1758A2750A035001587BD /* Extention+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extention+Notification.swift"; sourceTree = ""; }; + 84EEAD012BBCA6D100414955 /* OTFStyleColorStyler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTFStyleColorStyler.swift; sourceTree = ""; }; + 84EEAD022BBCA6D100414955 /* OTFStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTFStyle.swift; sourceTree = ""; }; + 84EEAD032BBCA6D100414955 /* OTFYamlStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTFYamlStyle.swift; sourceTree = ""; }; + 84F43F4D2B4D6A4A009DFFF8 /* OTFMagicBoxWatch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OTFMagicBoxWatch.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 84F43F4F2B4D6A4A009DFFF8 /* OTFMagicBoxWatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTFMagicBoxWatch.swift; sourceTree = ""; }; + 84F43F532B4D6A4C009DFFF8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 84F43F562B4D6A4C009DFFF8 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 9004A9212AD7DD390084622A /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = ""; }; - A5576C00FEC63C6798D1DB53 /* Pods-OTFMagicBox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBox.release.xcconfig"; path = "Target Support Files/Pods-OTFMagicBox/Pods-OTFMagicBox.release.xcconfig"; sourceTree = ""; }; + 901700F32B63B856006C611C /* ActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorView.swift; sourceTree = ""; }; + 902E18A52AE8F0A000F694F2 /* OTFFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTFFont.swift; sourceTree = ""; }; + 90C79E3E2B4DCD9D0020D20F /* OTFMagicBoxWatch.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OTFMagicBoxWatch.entitlements; sourceTree = ""; }; + 90C79E3F2B4DCE110020D20F /* OTFCareKitStoreManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTFCareKitStoreManager.swift; sourceTree = ""; }; + 90C79E402B4DCE110020D20F /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 90C79E412B4DCE120020D20F /* CareKitListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CareKitListView.swift; sourceTree = ""; }; + 90C79E422B4DCE120020D20F /* Extension+Notification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Extension+Notification.swift"; sourceTree = ""; }; + 90C79E432B4DCE120020D20F /* Extension+OCKTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Extension+OCKTask.swift"; sourceTree = ""; }; + 90C79E442B4DCE120020D20F /* SessionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = ""; }; + 90C79E4B2B4E862A0020D20F /* WatchStoreService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchStoreService.swift; sourceTree = ""; }; + 9BC94C5B492FDF7370667F8A /* Pods-OTFMagicBox.care.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBox.care.xcconfig"; path = "Target Support Files/Pods-OTFMagicBox/Pods-OTFMagicBox.care.xcconfig"; sourceTree = ""; }; + A49F6F1563A78034A9EBE56C /* Pods-OTFMagicBoxWatch.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBoxWatch.debug.xcconfig"; path = "Target Support Files/Pods-OTFMagicBoxWatch/Pods-OTFMagicBoxWatch.debug.xcconfig"; sourceTree = ""; }; A8C0556A296D61770098D1FB /* Extention+ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extention+ViewController.swift"; sourceTree = ""; }; A8FCD2A92A4C6EF7006E0B6E /* KeychainCloudManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainCloudManager.swift; sourceTree = ""; }; A8FCD2AB2A4C6F0D006E0B6E /* LocalAuthentication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthentication.swift; sourceTree = ""; }; - C68B1F7051EF9581BEEB32BF /* Pods-OTFMagicBox.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBox.debug.xcconfig"; path = "Target Support Files/Pods-OTFMagicBox/Pods-OTFMagicBox.debug.xcconfig"; sourceTree = ""; }; + BE0B0929EFF0E25E87CF3B71 /* Pods-OTFMagicBox.carehealth.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBox.carehealth.xcconfig"; path = "Target Support Files/Pods-OTFMagicBox/Pods-OTFMagicBox.carehealth.xcconfig"; sourceTree = ""; }; + C786F095D5BBC2634543074F /* Pods-OTFMagicBox.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBox.debug.xcconfig"; path = "Target Support Files/Pods-OTFMagicBox/Pods-OTFMagicBox.debug.xcconfig"; sourceTree = ""; }; CE2DB9C6263B1EC400E2FB88 /* AppSysParameters.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = AppSysParameters.yml; sourceTree = ""; }; CE482CF3262C954A00C0A2D5 /* OTFMagicBox.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OTFMagicBox.app; sourceTree = BUILT_PRODUCTS_DIR; }; CE482CF6262C954A00C0A2D5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -340,7 +328,9 @@ CE482CFC262C954C00C0A2D5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; CE482D02262C954C00C0A2D5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; CE482D04262C954C00C0A2D5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E5CF7B6203990ECA79E1B177 /* Pods-OTFMagicBox Watch Watch App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBox Watch Watch App.release.xcconfig"; path = "Target Support Files/Pods-OTFMagicBox Watch Watch App/Pods-OTFMagicBox Watch Watch App.release.xcconfig"; sourceTree = ""; }; + E86A26F2DE6C8AB4A0B19344 /* Pods_OTFMagicBox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OTFMagicBox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F07B7C39F5B74DE968EFEDC4 /* Pods-OTFMagicBox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBox.release.xcconfig"; path = "Target Support Files/Pods-OTFMagicBox/Pods-OTFMagicBox.release.xcconfig"; sourceTree = ""; }; + F2F96CA14BB557FB216784C9 /* Pods-OTFMagicBoxWatch.carehealth.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OTFMagicBoxWatch.carehealth.xcconfig"; path = "Target Support Files/Pods-OTFMagicBoxWatch/Pods-OTFMagicBoxWatch.carehealth.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -351,25 +341,11 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 7CA3D2ED2A8A43C300FCB048 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 04CDFE9A4C5C79E8EACA8709 /* Pods_OTFMagicBox_Watch_Watch_App.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7CA3D2FC2A8A43C400FCB048 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7CA3D3062A8A43C400FCB048 /* Frameworks */ = { + 84F43F4A2B4D6A4A009DFFF8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + FFB3790929612305437E0E08 /* Pods_OTFMagicBoxWatch.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -378,7 +354,7 @@ buildActionMask = 2147483647; files = ( 5A49628526DF73B700A4B4DF /* HealthKit.framework in Frameworks */, - 06540FA342BE7267771D8AF4 /* Pods_OTFMagicBox.framework in Frameworks */, + 4CF07F71CAF10A608704FCFF /* Pods_OTFMagicBox.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -507,7 +483,7 @@ 5A49632926EB5E2E00A4B4DF /* Extension */, 5A49626D26D4A2EA00A4B4DF /* Yaml */, 5AADFD4F264E9A880069FEF7 /* Constants.swift */, - 849989E32AD7CD53009CBA41 /* ActivityLoader.swift */, + 849989E32AD7CD53009CBA41 /* LoaderView.swift */, 5AB1808126B88A2B007AF766 /* Metrics.swift */, 5A49627D26DEA59F00A4B4DF /* HealthKitManager.swift */, 5A49627926DE69AE00A4B4DF /* OTFHealthKitManager.swift */, @@ -519,6 +495,7 @@ A8FCD2A92A4C6EF7006E0B6E /* KeychainCloudManager.swift */, 849989E12AD7CC67009CBA41 /* UploadDocumentManager.swift */, A8FCD2AB2A4C6F0D006E0B6E /* LocalAuthentication.swift */, + 902E18A52AE8F0A000F694F2 /* OTFFont.swift */, ); path = Library; sourceTree = ""; @@ -595,44 +572,6 @@ path = Contacts; sourceTree = ""; }; - 7CA3D2F12A8A43C300FCB048 /* OTFMagicBox Watch Watch App */ = { - isa = PBXGroup; - children = ( - 7CD965012AB660E8003E9394 /* OTFMagicBox Watch Watch App.entitlements */, - 7CA3D2F22A8A43C300FCB048 /* OTFMagicBox_WatchApp.swift */, - 7CA3D2F42A8A43C300FCB048 /* ContentView.swift */, - 7CA403022AB20C0F00A3D022 /* CareKitListView.swift */, - 7CA3D2F62A8A43C400FCB048 /* Assets.xcassets */, - 7CA3D2F82A8A43C400FCB048 /* Preview Content */, - ); - path = "OTFMagicBox Watch Watch App"; - sourceTree = ""; - }; - 7CA3D2F82A8A43C400FCB048 /* Preview Content */ = { - isa = PBXGroup; - children = ( - 7CA3D2F92A8A43C400FCB048 /* Preview Assets.xcassets */, - ); - path = "Preview Content"; - sourceTree = ""; - }; - 7CA3D3022A8A43C400FCB048 /* OTFMagicBox Watch Watch AppTests */ = { - isa = PBXGroup; - children = ( - 7CA3D3032A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppTests.swift */, - ); - path = "OTFMagicBox Watch Watch AppTests"; - sourceTree = ""; - }; - 7CA3D30C2A8A43C400FCB048 /* OTFMagicBox Watch Watch AppUITests */ = { - isa = PBXGroup; - children = ( - 7CA3D30D2A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITests.swift */, - 7CA3D30F2A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift */, - ); - path = "OTFMagicBox Watch Watch AppUITests"; - sourceTree = ""; - }; 841FEFBC274E5D8200698892 /* Datastore */ = { isa = PBXGroup; children = ( @@ -674,11 +613,11 @@ 846761A927DF8BC300A3207E /* StaticViews */ = { isa = PBXGroup; children = ( - 846761AA27DF8BC300A3207E /* PlatformPicker.swift */, - 846761AB27DF8BC300A3207E /* StaticUI.swift */, + 846761B427DF8BC300A3207E /* CareKit */, 846761AC27DF8BC300A3207E /* RK UI */, 846761B327DF8BC300A3207E /* CardBackground.swift */, - 846761B427DF8BC300A3207E /* CareKit */, + 846761AA27DF8BC300A3207E /* PlatformPicker.swift */, + 846761AB27DF8BC300A3207E /* StaticUI.swift */, ); path = StaticViews; sourceTree = ""; @@ -691,6 +630,7 @@ 846761AF27DF8BC300A3207E /* TaskViewControllerRepresentable.swift */, 846761B027DF8BC300A3207E /* RKTasks.swift */, 846761B127DF8BC300A3207E /* TaskListRow.swift */, + 84146ED72BD14F4B007D768C /* TaskListRow+Extras.swift */, 846761B227DF8BC300A3207E /* TaskListViewController.swift */, ); path = "RK UI"; @@ -707,17 +647,90 @@ path = CareKit; sourceTree = ""; }; + 84847E4A2BA1C42300B2B016 /* Views */ = { + isa = PBXGroup; + children = ( + 901700F32B63B856006C611C /* ActivityIndicatorView.swift */, + 90C79E412B4DCE120020D20F /* CareKitListView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 84847E4B2BA1C51600B2B016 /* DataStore */ = { + isa = PBXGroup; + children = ( + 90C79E4B2B4E862A0020D20F /* WatchStoreService.swift */, + 90C79E3F2B4DCE110020D20F /* OTFCareKitStoreManager.swift */, + ); + path = DataStore; + sourceTree = ""; + }; + 84847E4C2BA1C58100B2B016 /* Managers */ = { + isa = PBXGroup; + children = ( + 90C79E442B4DCE120020D20F /* SessionManager.swift */, + ); + path = Managers; + sourceTree = ""; + }; + 84EEAD002BBCA6D100414955 /* Styling */ = { + isa = PBXGroup; + children = ( + 84EEAD012BBCA6D100414955 /* OTFStyleColorStyler.swift */, + 84EEAD022BBCA6D100414955 /* OTFStyle.swift */, + 84EEAD032BBCA6D100414955 /* OTFYamlStyle.swift */, + ); + path = Styling; + sourceTree = ""; + }; + 84F43F4E2B4D6A4A009DFFF8 /* OTFMagicBoxWatch */ = { + isa = PBXGroup; + children = ( + 84F43F4F2B4D6A4A009DFFF8 /* OTFMagicBoxWatch.swift */, + 90C79E402B4DCE110020D20F /* ContentView.swift */, + 84847E4C2BA1C58100B2B016 /* Managers */, + 84847E4B2BA1C51600B2B016 /* DataStore */, + 901700EF2B5A701F006C611C /* Extensions */, + 84847E4A2BA1C42300B2B016 /* Views */, + 84F43F552B4D6A4C009DFFF8 /* Preview Content */, + 84F43F532B4D6A4C009DFFF8 /* Assets.xcassets */, + 90C79E3E2B4DCD9D0020D20F /* OTFMagicBoxWatch.entitlements */, + ); + path = OTFMagicBoxWatch; + sourceTree = ""; + }; + 84F43F552B4D6A4C009DFFF8 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 84F43F562B4D6A4C009DFFF8 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; 8C979D2203D122CC68BA93F2 /* Pods */ = { isa = PBXGroup; children = ( - C68B1F7051EF9581BEEB32BF /* Pods-OTFMagicBox.debug.xcconfig */, - A5576C00FEC63C6798D1DB53 /* Pods-OTFMagicBox.release.xcconfig */, - 23661129E1AA02D9A3410FC7 /* Pods-OTFMagicBox Watch Watch App.debug.xcconfig */, - E5CF7B6203990ECA79E1B177 /* Pods-OTFMagicBox Watch Watch App.release.xcconfig */, + C786F095D5BBC2634543074F /* Pods-OTFMagicBox.debug.xcconfig */, + BE0B0929EFF0E25E87CF3B71 /* Pods-OTFMagicBox.carehealth.xcconfig */, + 9BC94C5B492FDF7370667F8A /* Pods-OTFMagicBox.care.xcconfig */, + F07B7C39F5B74DE968EFEDC4 /* Pods-OTFMagicBox.release.xcconfig */, + A49F6F1563A78034A9EBE56C /* Pods-OTFMagicBoxWatch.debug.xcconfig */, + F2F96CA14BB557FB216784C9 /* Pods-OTFMagicBoxWatch.carehealth.xcconfig */, + 62EB2116D692E7C5E54E80E1 /* Pods-OTFMagicBoxWatch.care.xcconfig */, + 58ADE8FC0AF041D6DF78CE64 /* Pods-OTFMagicBoxWatch.release.xcconfig */, ); path = Pods; sourceTree = ""; }; + 901700EF2B5A701F006C611C /* Extensions */ = { + isa = PBXGroup; + children = ( + 90C79E432B4DCE120020D20F /* Extension+OCKTask.swift */, + 90C79E422B4DCE120020D20F /* Extension+Notification.swift */, + ); + path = Extensions; + sourceTree = ""; + }; A8705D29296E8E85003AFC0B /* Recovered References */ = { isa = PBXGroup; children = ( @@ -730,8 +743,8 @@ isa = PBXGroup; children = ( 5A49628426DF73B700A4B4DF /* HealthKit.framework */, - 55AC9A6EAEB0412B5C7F5D6C /* Pods_OTFMagicBox.framework */, - 44835E788FC7C51DB58219C2 /* Pods_OTFMagicBox_Watch_Watch_App.framework */, + E86A26F2DE6C8AB4A0B19344 /* Pods_OTFMagicBox.framework */, + 2DC70EC922D0E3C888B7C474 /* Pods_OTFMagicBoxWatch.framework */, ); name = Frameworks; sourceTree = ""; @@ -742,9 +755,7 @@ 32100A2B28AE5BB500035F5E /* .github */, CE482CF5262C954A00C0A2D5 /* OTFMagicBox */, 5A7B6DAA26FD282C00F872A1 /* OTFMagicBoxTests */, - 7CA3D2F12A8A43C300FCB048 /* OTFMagicBox Watch Watch App */, - 7CA3D3022A8A43C400FCB048 /* OTFMagicBox Watch Watch AppTests */, - 7CA3D30C2A8A43C400FCB048 /* OTFMagicBox Watch Watch AppUITests */, + 84F43F4E2B4D6A4A009DFFF8 /* OTFMagicBoxWatch */, CE482CF4262C954A00C0A2D5 /* Products */, 8C979D2203D122CC68BA93F2 /* Pods */, C9D92AAC7DE27C25427A4DB9 /* Frameworks */, @@ -757,9 +768,7 @@ children = ( CE482CF3262C954A00C0A2D5 /* OTFMagicBox.app */, 5A7B6DA926FD282C00F872A1 /* OTFMagicBoxTests.xctest */, - 7CA3D2F02A8A43C300FCB048 /* OTFMagicBox Watch Watch App.app */, - 7CA3D2FF2A8A43C400FCB048 /* OTFMagicBox Watch Watch AppTests.xctest */, - 7CA3D3092A8A43C400FCB048 /* OTFMagicBox Watch Watch AppUITests.xctest */, + 84F43F4D2B4D6A4A009DFFF8 /* OTFMagicBoxWatch.app */, ); name = Products; sourceTree = ""; @@ -783,6 +792,7 @@ 5AADFD43264E86B00069FEF7 /* Login */, 5AADFD3D264E86A20069FEF7 /* Library */, 5AADFD35264E86950069FEF7 /* Onboarding */, + 84EEAD002BBCA6D100414955 /* Styling */, CE482CF8262C954A00C0A2D5 /* SceneDelegate.swift */, CE482CF6262C954A00C0A2D5 /* AppDelegate.swift */, 5AB1807F26B8877C007AF766 /* OCKStore + SampleData.swift */, @@ -819,77 +829,42 @@ productReference = 5A7B6DA926FD282C00F872A1 /* OTFMagicBoxTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 7CA3D2EF2A8A43C300FCB048 /* OTFMagicBox Watch Watch App */ = { + 84F43F4C2B4D6A4A009DFFF8 /* OTFMagicBoxWatch */ = { isa = PBXNativeTarget; - buildConfigurationList = 7CA3D31B2A8A43C400FCB048 /* Build configuration list for PBXNativeTarget "OTFMagicBox Watch Watch App" */; + buildConfigurationList = 84F43F5D2B4D6A4C009DFFF8 /* Build configuration list for PBXNativeTarget "OTFMagicBoxWatch" */; buildPhases = ( - 05EB063AD94BCC1191F92DD8 /* [CP] Check Pods Manifest.lock */, - 7CA3D2EC2A8A43C300FCB048 /* Sources */, - 7CA3D2ED2A8A43C300FCB048 /* Frameworks */, - 7CA3D2EE2A8A43C300FCB048 /* Resources */, - 7CEB1FC62A8A5A83002918FE /* Embed Frameworks */, - 9333C6CAA54ADF6700EA8400 /* [CP] Embed Pods Frameworks */, + FFD91FC98245B864E873D8DF /* [CP] Check Pods Manifest.lock */, + 84F43F492B4D6A4A009DFFF8 /* Sources */, + 84F43F4A2B4D6A4A009DFFF8 /* Frameworks */, + 84F43F4B2B4D6A4A009DFFF8 /* Resources */, + 901EEAFD2BDA2A10004EC8B5 /* ShellScript */, + CA4E7853B35A745B8BED7B95 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); - name = "OTFMagicBox Watch Watch App"; - productName = "OTFMagicBox Watch Watch App"; - productReference = 7CA3D2F02A8A43C300FCB048 /* OTFMagicBox Watch Watch App.app */; + name = OTFMagicBoxWatch; + productName = "OTFMagicBoxWatch Watch App"; + productReference = 84F43F4D2B4D6A4A009DFFF8 /* OTFMagicBoxWatch.app */; productType = "com.apple.product-type.application"; }; - 7CA3D2FE2A8A43C400FCB048 /* OTFMagicBox Watch Watch AppTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7CA3D31C2A8A43C400FCB048 /* Build configuration list for PBXNativeTarget "OTFMagicBox Watch Watch AppTests" */; - buildPhases = ( - 7CA3D2FB2A8A43C400FCB048 /* Sources */, - 7CA3D2FC2A8A43C400FCB048 /* Frameworks */, - 7CA3D2FD2A8A43C400FCB048 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7CA3D3012A8A43C400FCB048 /* PBXTargetDependency */, - ); - name = "OTFMagicBox Watch Watch AppTests"; - productName = "OTFMagicBox Watch Watch AppTests"; - productReference = 7CA3D2FF2A8A43C400FCB048 /* OTFMagicBox Watch Watch AppTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 7CA3D3082A8A43C400FCB048 /* OTFMagicBox Watch Watch AppUITests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7CA3D31D2A8A43C400FCB048 /* Build configuration list for PBXNativeTarget "OTFMagicBox Watch Watch AppUITests" */; - buildPhases = ( - 7CA3D3052A8A43C400FCB048 /* Sources */, - 7CA3D3062A8A43C400FCB048 /* Frameworks */, - 7CA3D3072A8A43C400FCB048 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7CA3D30B2A8A43C400FCB048 /* PBXTargetDependency */, - ); - name = "OTFMagicBox Watch Watch AppUITests"; - productName = "OTFMagicBox Watch Watch AppUITests"; - productReference = 7CA3D3092A8A43C400FCB048 /* OTFMagicBox Watch Watch AppUITests.xctest */; - productType = "com.apple.product-type.bundle.ui-testing"; - }; CE482CF2262C954A00C0A2D5 /* OTFMagicBox */ = { isa = PBXNativeTarget; buildConfigurationList = CE482D07262C954C00C0A2D5 /* Build configuration list for PBXNativeTarget "OTFMagicBox" */; buildPhases = ( - DC173994E8AF983CB6A1D9DA /* [CP] Check Pods Manifest.lock */, + C6C3FF89D47613EA5AA1A900 /* [CP] Check Pods Manifest.lock */, CE482CEF262C954A00C0A2D5 /* Sources */, CE482CF0262C954A00C0A2D5 /* Frameworks */, CE482CF1262C954A00C0A2D5 /* Resources */, 7CA3D3142A8A43C400FCB048 /* Embed Watch Content */, - A2C2909005B20CD8C57AFCCC /* [CP] Embed Pods Frameworks */, + 902E18A92AEA869B00F694F2 /* ShellScript */, + 93B66E92271BF6A28C38EA90 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( - 7CA3D3122A8A43C400FCB048 /* PBXTargetDependency */, + 84F43F592B4D6A4C009DFFF8 /* PBXTargetDependency */, ); name = OTFMagicBox; productName = CompletelyNewApp; @@ -903,23 +878,15 @@ isa = PBXProject; attributes = { DefaultBuildSystemTypeForWorkspace = Original; - LastSwiftUpdateCheck = 1430; + LastSwiftUpdateCheck = 1500; LastUpgradeCheck = 1240; TargetAttributes = { 5A7B6DA826FD282C00F872A1 = { CreatedOnToolsVersion = 12.5.1; TestTargetID = CE482CF2262C954A00C0A2D5; }; - 7CA3D2EF2A8A43C300FCB048 = { - CreatedOnToolsVersion = 14.3.1; - }; - 7CA3D2FE2A8A43C400FCB048 = { - CreatedOnToolsVersion = 14.3.1; - TestTargetID = 7CA3D2EF2A8A43C300FCB048; - }; - 7CA3D3082A8A43C400FCB048 = { - CreatedOnToolsVersion = 14.3.1; - TestTargetID = 7CA3D2EF2A8A43C300FCB048; + 84F43F4C2B4D6A4A009DFFF8 = { + CreatedOnToolsVersion = 15.0.1; }; CE482CF2262C954A00C0A2D5 = { CreatedOnToolsVersion = 12.4; @@ -941,9 +908,7 @@ targets = ( CE482CF2262C954A00C0A2D5 /* OTFMagicBox */, 5A7B6DA826FD282C00F872A1 /* OTFMagicBoxTests */, - 7CA3D2EF2A8A43C300FCB048 /* OTFMagicBox Watch Watch App */, - 7CA3D2FE2A8A43C400FCB048 /* OTFMagicBox Watch Watch AppTests */, - 7CA3D3082A8A43C400FCB048 /* OTFMagicBox Watch Watch AppUITests */, + 84F43F4C2B4D6A4A009DFFF8 /* OTFMagicBoxWatch */, ); }; /* End PBXProject section */ @@ -956,26 +921,12 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 7CA3D2EE2A8A43C300FCB048 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7CA3D2FA2A8A43C400FCB048 /* Preview Assets.xcassets in Resources */, - 7CA3D2F72A8A43C400FCB048 /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7CA3D2FD2A8A43C400FCB048 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7CA3D3072A8A43C400FCB048 /* Resources */ = { + 84F43F4B2B4D6A4A009DFFF8 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 84F43F572B4D6A4C009DFFF8 /* Preview Assets.xcassets in Resources */, + 84F43F542B4D6A4C009DFFF8 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -996,7 +947,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 05EB063AD94BCC1191F92DD8 /* [CP] Check Pods Manifest.lock */ = { + 901EEAFD2BDA2A10004EC8B5 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1004,38 +955,34 @@ inputFileListPaths = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-OTFMagicBox Watch Watch App-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; - 9333C6CAA54ADF6700EA8400 /* [CP] Embed Pods Frameworks */ = { + 902E18A92AEA869B00F694F2 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-OTFMagicBox Watch Watch App/Pods-OTFMagicBox Watch Watch App-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + ); outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-OTFMagicBox Watch Watch App/Pods-OTFMagicBox Watch Watch App-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-OTFMagicBox Watch Watch App/Pods-OTFMagicBox Watch Watch App-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; - A2C2909005B20CD8C57AFCCC /* [CP] Embed Pods Frameworks */ = { + 93B66E92271BF6A28C38EA90 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1052,7 +999,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-OTFMagicBox/Pods-OTFMagicBox-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - DC173994E8AF983CB6A1D9DA /* [CP] Check Pods Manifest.lock */ = { + C6C3FF89D47613EA5AA1A900 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1074,44 +1021,70 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 5A7B6DA526FD282C00F872A1 /* Sources */ = { - isa = PBXSourcesBuildPhase; + CA4E7853B35A745B8BED7B95 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( - 5A7B6DB426FD285000F872A1 /* OTFMagicBoxYamlTests.swift in Sources */, - 5A7B6DAC26FD282C00F872A1 /* OTFMagicBoxTests.swift in Sources */, + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-OTFMagicBoxWatch/Pods-OTFMagicBoxWatch-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-OTFMagicBoxWatch/Pods-OTFMagicBoxWatch-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-OTFMagicBoxWatch/Pods-OTFMagicBoxWatch-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; - 7CA3D2EC2A8A43C300FCB048 /* Sources */ = { - isa = PBXSourcesBuildPhase; + FFD91FC98245B864E873D8DF /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( - 7CD965032AB6B784003E9394 /* Constants.swift in Sources */, - 7CA403032AB20C0F00A3D022 /* CareKitListView.swift in Sources */, - 7CD965022AB6AA5E003E9394 /* OCKStoreManager.swift in Sources */, - 7CA3D2F52A8A43C300FCB048 /* ContentView.swift in Sources */, - 7CA3D2F32A8A43C300FCB048 /* OTFMagicBox_WatchApp.swift in Sources */, + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-OTFMagicBoxWatch-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - 7CA3D2FB2A8A43C400FCB048 /* Sources */ = { +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5A7B6DA526FD282C00F872A1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7CA3D3042A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppTests.swift in Sources */, + 5A7B6DB426FD285000F872A1 /* OTFMagicBoxYamlTests.swift in Sources */, + 5A7B6DAC26FD282C00F872A1 /* OTFMagicBoxTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 7CA3D3052A8A43C400FCB048 /* Sources */ = { + 84F43F492B4D6A4A009DFFF8 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7CA3D3102A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITestsLaunchTests.swift in Sources */, - 7CA3D30E2A8A43C400FCB048 /* OTFMagicBox_Watch_Watch_AppUITests.swift in Sources */, + 84F43F502B4D6A4A009DFFF8 /* OTFMagicBoxWatch.swift in Sources */, + 90C79E492B4DCE120020D20F /* Extension+OCKTask.swift in Sources */, + 90C79E452B4DCE120020D20F /* OTFCareKitStoreManager.swift in Sources */, + 90C79E472B4DCE120020D20F /* CareKitListView.swift in Sources */, + 90C79E482B4DCE120020D20F /* Extension+Notification.swift in Sources */, + 901700F42B63B856006C611C /* ActivityIndicatorView.swift in Sources */, + 90C79E462B4DCE120020D20F /* ContentView.swift in Sources */, + 90C79E4A2B4DCE120020D20F /* SessionManager.swift in Sources */, + 90C79E4C2B4E862A0020D20F /* WatchStoreService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1129,8 +1102,10 @@ 5AB1808826B9C489007AF766 /* ScheduleViewController.swift in Sources */, 84268457274791E5007C5D50 /* SignInWithAppleStepViewController.swift in Sources */, 841FEFBF274E5D8200698892 /* CloudantSyncManager.swift in Sources */, + 84EEAD062BBCA6D100414955 /* OTFYamlStyle.swift in Sources */, 5A49632426EB257200A4B4DF /* Extension+UIImage.swift in Sources */, 846761C327DF8BC300A3207E /* ContactsSection.swift in Sources */, + 84EEAD042BBCA6D100414955 /* OTFStyleColorStyler.swift in Sources */, 849989E62AD7D182009CBA41 /* Extension+Array.swift in Sources */, 5A7B6D8F26FA353B00F872A1 /* OTFTheraforgeNetwork.swift in Sources */, 5AADFD47264E89510069FEF7 /* ConsentDocument.swift in Sources */, @@ -1149,6 +1124,7 @@ 32AAA4A728339E7F00DA0DA8 /* ModuleAppYmlReader+DataModel.swift in Sources */, 846761C527DF8BC300A3207E /* CareKitTaskViews.swift in Sources */, 5AB1808A26B9C76D007AF766 /* SurveyItemViewController.swift in Sources */, + 84146ED82BD14F4B007D768C /* TaskListRow+Extras.swift in Sources */, 84A1758B2750A035001587BD /* Extention+Notification.swift in Sources */, A8C0556B296D61770098D1FB /* Extention+ViewController.swift in Sources */, 849989E22AD7CC67009CBA41 /* UploadDocumentManager.swift in Sources */, @@ -1206,10 +1182,11 @@ 5A4304A0272AE85200926584 /* DocumentPreviewViewController.swift in Sources */, 846761BD27DF8BC300A3207E /* TaskViewControllerRepresentable.swift in Sources */, 841CA60C275F827300C6861D /* CareKitStoreManager.swift in Sources */, - 849989E42AD7CD53009CBA41 /* ActivityLoader.swift in Sources */, + 849989E42AD7CD53009CBA41 /* LoaderView.swift in Sources */, 5AB1808D26BC4ED6007AF766 /* LoginViewController.swift in Sources */, 841FEFC0274E5D8200698892 /* TheraForgeHTTPInterceptor.swift in Sources */, 846761A127DF8A6900A3207E /* OCKHealthKitStore+Extension.swift in Sources */, + 84EEAD052BBCA6D100414955 /* OTFStyle.swift in Sources */, 5A49628D26E1BD5D00A4B4DF /* UIColor.swift in Sources */, 5AB1807726B8849A007AF766 /* ChangePasscodeView.swift in Sources */, 846761A027DF8A6900A3207E /* Extension+OCKAnyTask.swift in Sources */, @@ -1223,6 +1200,7 @@ 846761BF27DF8BC300A3207E /* TaskListRow.swift in Sources */, 7C7EC6792A65912C003B0FFB /* OTFNetworkObserver.swift in Sources */, 8467619927DF89DE00A3207E /* CheckUpView.swift in Sources */, + 902E18A62AE8F0A000F694F2 /* OTFFont.swift in Sources */, 849989E02AD7CB25009CBA41 /* PDFKitRepresentedView.swift in Sources */, 5A49627C26DE6A2E00A4B4DF /* ActivityManager.swift in Sources */, 5AADFD50264E9A880069FEF7 /* Constants.swift in Sources */, @@ -1238,20 +1216,10 @@ target = CE482CF2262C954A00C0A2D5 /* OTFMagicBox */; targetProxy = 5A7B6DAE26FD282C00F872A1 /* PBXContainerItemProxy */; }; - 7CA3D3012A8A43C400FCB048 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7CA3D2EF2A8A43C300FCB048 /* OTFMagicBox Watch Watch App */; - targetProxy = 7CA3D3002A8A43C400FCB048 /* PBXContainerItemProxy */; - }; - 7CA3D30B2A8A43C400FCB048 /* PBXTargetDependency */ = { + 84F43F592B4D6A4C009DFFF8 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 7CA3D2EF2A8A43C300FCB048 /* OTFMagicBox Watch Watch App */; - targetProxy = 7CA3D30A2A8A43C400FCB048 /* PBXContainerItemProxy */; - }; - 7CA3D3122A8A43C400FCB048 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7CA3D2EF2A8A43C300FCB048 /* OTFMagicBox Watch Watch App */; - targetProxy = 7CA3D3112A8A43C400FCB048 /* PBXContainerItemProxy */; + target = 84F43F4C2B4D6A4A009DFFF8 /* OTFMagicBoxWatch */; + targetProxy = 84F43F582B4D6A4C009DFFF8 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -1309,34 +1277,38 @@ }; name = Release; }; - 7CA3D3152A8A43C400FCB048 /* Debug */ = { + 84F43F5B2B4D6A4C009DFFF8 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 23661129E1AA02D9A3410FC7 /* Pods-OTFMagicBox Watch Watch App.debug.xcconfig */; + baseConfigurationReference = A49F6F1563A78034A9EBE56C /* Pods-OTFMagicBoxWatch.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CODE_SIGN_ENTITLEMENTS = "OTFMagicBox Watch Watch App/OTFMagicBox Watch Watch App.entitlements"; + CODE_SIGN_ENTITLEMENTS = OTFMagicBoxWatch/OTFMagicBoxWatch.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"OTFMagicBox Watch Watch App/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_ASSET_PATHS = "\"OTFMagicBoxWatch/Preview Content\""; + DEVELOPMENT_TEAM = 53UK9NNVG5; ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "OTFMagicBox Watch"; + INFOPLIST_KEY_CFBundleDisplayName = OTFMagicBoxWatch; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_WKCompanionAppBundleIdentifier = org.theraforge.magicbox.ios; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = org.theraforge.magicbox.ios.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = watchos; SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; @@ -1344,32 +1316,35 @@ }; name = Debug; }; - 7CA3D3162A8A43C400FCB048 /* Release */ = { + 84F43F5C2B4D6A4C009DFFF8 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E5CF7B6203990ECA79E1B177 /* Pods-OTFMagicBox Watch Watch App.release.xcconfig */; + baseConfigurationReference = 58ADE8FC0AF041D6DF78CE64 /* Pods-OTFMagicBoxWatch.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CODE_SIGN_ENTITLEMENTS = "OTFMagicBox Watch Watch App/OTFMagicBox Watch Watch App.entitlements"; + CODE_SIGN_ENTITLEMENTS = OTFMagicBoxWatch/OTFMagicBoxWatch.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"OTFMagicBox Watch Watch App/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_ASSET_PATHS = "\"OTFMagicBoxWatch/Preview Content\""; + DEVELOPMENT_TEAM = 53UK9NNVG5; ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "OTFMagicBox Watch"; + INFOPLIST_KEY_CFBundleDisplayName = OTFMagicBoxWatch; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_WKCompanionAppBundleIdentifier = org.theraforge.magicbox.ios; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = org.theraforge.magicbox.ios.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -1379,91 +1354,307 @@ }; name = Release; }; - 7CA3D3172A8A43C400FCB048 /* Debug */ = { + 90C79E4D2B4E9ED00020D20F /* Care */ = { isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Care; + }; + 90C79E4E2B4E9ED00020D20F /* Care */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9BC94C5B492FDF7370667F8A /* Pods-OTFMagicBox.care.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = OTFMagicBox/OTFMagicBox.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = 53UK9NNVG5; + ENABLE_PREVIEWS = YES; + EXCLUDED_ARCHS = ""; + INFOPLIST_FILE = OTFMagicBox/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.1.1; + PRODUCT_BUNDLE_IDENTIFIER = org.theraforge.magicbox.ios; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = OTFMagicBox_debug; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Care; + }; + 90C79E4F2B4E9ED00020D20F /* Care */ = { + isa = XCBuildConfiguration; + buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ZTGHLM6H83; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "tfmartins.OTFMagicBox-Watch-Watch-AppTests"; + DEVELOPMENT_TEAM = D25537G8CD; + INFOPLIST_FILE = OTFMagicBoxTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = MyCompany.OTFMagicBoxTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = watchos; - SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OTFMagicBox Watch Watch App.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/OTFMagicBox Watch Watch App"; - WATCHOS_DEPLOYMENT_TARGET = 9.4; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OTFMagicBox.app/OTFMagicBox"; }; - name = Debug; + name = Care; }; - 7CA3D3182A8A43C400FCB048 /* Release */ = { + 90C79E502B4E9ED00020D20F /* Care */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 62EB2116D692E7C5E54E80E1 /* Pods-OTFMagicBoxWatch.care.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = OTFMagicBoxWatch/OTFMagicBoxWatch.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ZTGHLM6H83; + DEVELOPMENT_ASSET_PATHS = "\"OTFMagicBoxWatch/Preview Content\""; + DEVELOPMENT_TEAM = 53UK9NNVG5; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = OTFMagicBoxWatch; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_WKCompanionAppBundleIdentifier = org.theraforge.magicbox.ios; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "tfmartins.OTFMagicBox-Watch-Watch-AppTests"; + PRODUCT_BUNDLE_IDENTIFIER = org.theraforge.magicbox.ios.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; - SWIFT_EMIT_LOC_STRINGS = NO; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OTFMagicBox Watch Watch App.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/OTFMagicBox Watch Watch App"; - WATCHOS_DEPLOYMENT_TARGET = 9.4; + WATCHOS_DEPLOYMENT_TARGET = 8.0; }; - name = Release; + name = Care; + }; + 90C79E512B4E9F070020D20F /* CareHealth */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = CareHealth; }; - 7CA3D3192A8A43C400FCB048 /* Debug */ = { + 90C79E522B4E9F070020D20F /* CareHealth */ = { isa = XCBuildConfiguration; + baseConfigurationReference = BE0B0929EFF0E25E87CF3B71 /* Pods-OTFMagicBox.carehealth.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = OTFMagicBox/OTFMagicBox.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = 53UK9NNVG5; + ENABLE_PREVIEWS = YES; + EXCLUDED_ARCHS = ""; + INFOPLIST_FILE = OTFMagicBox/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.1.1; + PRODUCT_BUNDLE_IDENTIFIER = org.theraforge.magicbox.ios; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = OTFMagicBox_debug; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = CareHealth; + }; + 90C79E532B4E9F070020D20F /* CareHealth */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ZTGHLM6H83; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "tfmartins.OTFMagicBox-Watch-Watch-AppUITests"; + DEVELOPMENT_TEAM = D25537G8CD; + INFOPLIST_FILE = OTFMagicBoxTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = MyCompany.OTFMagicBoxTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = watchos; - SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; - TEST_TARGET_NAME = "OTFMagicBox Watch Watch App"; - WATCHOS_DEPLOYMENT_TARGET = 9.4; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OTFMagicBox.app/OTFMagicBox"; }; - name = Debug; + name = CareHealth; }; - 7CA3D31A2A8A43C400FCB048 /* Release */ = { + 90C79E542B4E9F070020D20F /* CareHealth */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F2F96CA14BB557FB216784C9 /* Pods-OTFMagicBoxWatch.carehealth.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = OTFMagicBoxWatch/OTFMagicBoxWatch.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ZTGHLM6H83; + DEVELOPMENT_ASSET_PATHS = "\"OTFMagicBoxWatch/Preview Content\""; + DEVELOPMENT_TEAM = 53UK9NNVG5; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = OTFMagicBoxWatch; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_WKCompanionAppBundleIdentifier = org.theraforge.magicbox.ios; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "tfmartins.OTFMagicBox-Watch-Watch-AppUITests"; + PRODUCT_BUNDLE_IDENTIFIER = org.theraforge.magicbox.ios.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; - SWIFT_EMIT_LOC_STRINGS = NO; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - TEST_TARGET_NAME = "OTFMagicBox Watch Watch App"; - WATCHOS_DEPLOYMENT_TARGET = 9.4; + WATCHOS_DEPLOYMENT_TARGET = 8.0; }; - name = Release; + name = CareHealth; }; CE482D05262C954C00C0A2D5 /* Debug */ = { isa = XCBuildConfiguration; @@ -1583,7 +1774,7 @@ }; CE482D08262C954C00C0A2D5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = C68B1F7051EF9581BEEB32BF /* Pods-OTFMagicBox.debug.xcconfig */; + baseConfigurationReference = C786F095D5BBC2634543074F /* Pods-OTFMagicBox.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1595,6 +1786,7 @@ DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 53UK9NNVG5; ENABLE_PREVIEWS = YES; + EXCLUDED_ARCHS = ""; INFOPLIST_FILE = OTFMagicBox/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.5; LD_RUNPATH_SEARCH_PATHS = ( @@ -1612,7 +1804,7 @@ }; CE482D09262C954C00C0A2D5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A5576C00FEC63C6798D1DB53 /* Pods-OTFMagicBox.release.xcconfig */; + baseConfigurationReference = F07B7C39F5B74DE968EFEDC4 /* Pods-OTFMagicBox.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1646,34 +1838,20 @@ isa = XCConfigurationList; buildConfigurations = ( 5A7B6DB026FD282C00F872A1 /* Debug */, + 90C79E532B4E9F070020D20F /* CareHealth */, + 90C79E4F2B4E9ED00020D20F /* Care */, 5A7B6DB126FD282C00F872A1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 7CA3D31B2A8A43C400FCB048 /* Build configuration list for PBXNativeTarget "OTFMagicBox Watch Watch App" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7CA3D3152A8A43C400FCB048 /* Debug */, - 7CA3D3162A8A43C400FCB048 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7CA3D31C2A8A43C400FCB048 /* Build configuration list for PBXNativeTarget "OTFMagicBox Watch Watch AppTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7CA3D3172A8A43C400FCB048 /* Debug */, - 7CA3D3182A8A43C400FCB048 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7CA3D31D2A8A43C400FCB048 /* Build configuration list for PBXNativeTarget "OTFMagicBox Watch Watch AppUITests" */ = { + 84F43F5D2B4D6A4C009DFFF8 /* Build configuration list for PBXNativeTarget "OTFMagicBoxWatch" */ = { isa = XCConfigurationList; buildConfigurations = ( - 7CA3D3192A8A43C400FCB048 /* Debug */, - 7CA3D31A2A8A43C400FCB048 /* Release */, + 84F43F5B2B4D6A4C009DFFF8 /* Debug */, + 90C79E542B4E9F070020D20F /* CareHealth */, + 90C79E502B4E9ED00020D20F /* Care */, + 84F43F5C2B4D6A4C009DFFF8 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -1682,6 +1860,8 @@ isa = XCConfigurationList; buildConfigurations = ( CE482D05262C954C00C0A2D5 /* Debug */, + 90C79E512B4E9F070020D20F /* CareHealth */, + 90C79E4D2B4E9ED00020D20F /* Care */, CE482D06262C954C00C0A2D5 /* Release */, ); defaultConfigurationIsVisible = 0; @@ -1691,6 +1871,8 @@ isa = XCConfigurationList; buildConfigurations = ( CE482D08262C954C00C0A2D5 /* Debug */, + 90C79E522B4E9F070020D20F /* CareHealth */, + 90C79E4E2B4E9ED00020D20F /* Care */, CE482D09262C954C00C0A2D5 /* Release */, ); defaultConfigurationIsVisible = 0; diff --git a/OTFMagicBox/API/OTFNetworkObserver.swift b/OTFMagicBox/API/OTFNetworkObserver.swift index 2e7d005e..caee8b36 100644 --- a/OTFMagicBox/API/OTFNetworkObserver.swift +++ b/OTFMagicBox/API/OTFNetworkObserver.swift @@ -11,29 +11,29 @@ import Foundation class OTFNetworkObserver: ObservableObject { @Published private(set) var status: OTFNetworkStatus - + private let pathMonitor = NWPathMonitor() private let pathMonitorQueue = DispatchQueue(label: "NWPathMonitor") - + init(status: OTFNetworkStatus = .unsatisfied, active: Bool = true) { self.status = status if active { enablePathMonitor() } } - + private func enablePathMonitor() { pathMonitor.pathUpdateHandler = { path in guard path.status == .satisfied else { self.status = .offline return } - + self.pingEndpoint(isExpensive: path.isExpensive) } pathMonitor.start(queue: pathMonitorQueue) } - + func pingEndpoint(isExpensive: Bool) { guard let url = URL(string: "https://theraforge.org/api/v1/") else { self.status = .offline diff --git a/OTFMagicBox/API/OTFTheraforgeNetwork.swift b/OTFMagicBox/API/OTFTheraforgeNetwork.swift index 253412b3..531a7634 100644 --- a/OTFMagicBox/API/OTFTheraforgeNetwork.swift +++ b/OTFMagicBox/API/OTFTheraforgeNetwork.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -41,45 +41,45 @@ typealias AuthType = Request.SocialLogin.AuthType typealias SocialType = Request.SocialLogin.SocialType class OTFTheraforgeNetwork { - + static let shared = OTFTheraforgeNetwork() - + var otfNetworkService: TheraForgeNetwork! - + private init() { - + configureNetwork() - + } - + // Configure the API with required URL and API key. public func configureNetwork() { guard let url = URL(string: Constants.API.developmentUrl) else { OTFLog("Error: cannot create URL") return } - + let configurations = NetworkingLayer.Configurations(APIBaseURL: url, apiKey: YmlReader().apiKey) TheraForgeNetwork.configureNetwork(configurations) otfNetworkService = TheraForgeNetwork.shared } - + // Login request public func loginRequest(email: String, password: String) -> AnyPublisher { return Future { promise in self.otfNetworkService.login(request: OTFCloudClientAPI.Request.Login(email: email, - password: password)) { [weak self] result in + password: password)) { [weak self] result in self?.handleResponse(result, completion: promise) } } .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + public func socialLoginRequest(userType: UserType, socialType: SocialType, authType: AuthType, - idToken: String) -> AnyPublisher{ + idToken: String) -> AnyPublisher { return Future { promise in let socialRequest = OTFCloudClientAPI.Request.SocialLogin(userType: userType, socialType: socialType, @@ -92,23 +92,19 @@ class OTFTheraforgeNetwork { .receive(on: RunLoop.main) .eraseToAnyPublisher() } - - // Registration request - // swiftlint:disable all - public func signUpRequest(firstName: String, lastName: String, type: String, email: String, - password: String, dob: String, gender: String, encryptedMasterKey: String, publicKey: String, encryptedDefaultStorageKey: String, encryptedConfidentialStorageKey: String) -> AnyPublisher { - + + public func signUpRequest(signupRequest: OTFCloudClientAPI.Request.SignUp) -> AnyPublisher { + return Future { promise in - self.otfNetworkService.signup(request: OTFCloudClientAPI.Request.SignUp(email: email, password: password, first_name: firstName, last_name: lastName, type: .patient, dob: dob, gender: gender, phoneNo: "", encryptedMasterKey: encryptedMasterKey, publicKey: publicKey, encryptedDefaultStorageKey: encryptedDefaultStorageKey, encryptedConfidentialStorageKey: encryptedConfidentialStorageKey)) { [weak self] result in + self.otfNetworkService.signup( + request: signupRequest) { [weak self] result in self?.handleResponse(result, completion: promise) } } .receive(on: RunLoop.main) .eraseToAnyPublisher() } - - // delete user account public func deleteUser(userId: String) -> AnyPublisher { return Future { promise in @@ -124,10 +120,8 @@ class OTFTheraforgeNetwork { .receive(on: RunLoop.main) .eraseToAnyPublisher() } - - // Forgot password request - public func forgotPassword(email: String) -> AnyPublisher{ + public func forgotPassword(email: String) -> AnyPublisher { return Future { promise in self.otfNetworkService.forgotPassword(request: OTFCloudClientAPI.Request.ForgotPassword(email: email)) { [weak self] result in self?.handleResponse(result, completion: promise) @@ -136,36 +130,31 @@ class OTFTheraforgeNetwork { .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + // Reset password request public func resetPassword(email: String, code: String, newPassword: String) -> AnyPublisher { return Future { promise in self.otfNetworkService.resetPassword(request: OTFCloudClientAPI.Request.ResetPassword(email: email, - code: code, - newPassword: newPassword)) { [weak self] result in + code: code, + newPassword: newPassword)) { [weak self] result in self?.handleResponse(result, completion: promise) } } .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + // Signout request. public func signOut() -> AnyPublisher { return Future { promise in self.otfNetworkService.signOut { [weak self] result in - switch result { - case .failure(_): self?.handleResponse(result, promise: promise) - case .success(_): - self?.moveToOnboardingView() - } } } .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + // Change password request. public func changePassword(email: String, oldPassword: String, newPassword: String) -> AnyPublisher { return Future { promise in @@ -176,18 +165,25 @@ class OTFTheraforgeNetwork { .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + // Upload file request. - public func uploadFile(data: Data, fileName: String, type: Request.AttachmentLocation,encryptedFileKey: String? = nil, hashFileKey: String ) -> AnyPublisher { + public func uploadFile(data: Data, fileName: String, type: Request.AttachmentLocation, encryptedFileKey: String? = nil, hashFileKey: String ) -> AnyPublisher { return Future { promise in - self.otfNetworkService.uploadFile(request: OTFCloudClientAPI.Request.UploadFiles(data: data, fileName: fileName, type: type, meta: "true", encryptedFileKey: encryptedFileKey, hashFileKey: hashFileKey)) { [weak self] result in + self.otfNetworkService.uploadFile( + request: OTFCloudClientAPI.Request.UploadFiles( + data: data, + fileName: fileName, + type: type, + meta: "true", + encryptedFileKey: encryptedFileKey, + hashFileKey: hashFileKey)) { [weak self] result in self?.handleResponse(result, promise: promise) } } .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + // Download file request. public func downloadFile(attachmentID: String, type: Request.AttachmentLocation) -> AnyPublisher { return Future { promise in @@ -198,7 +194,7 @@ class OTFTheraforgeNetwork { .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + // Delete file request. public func deleteFile(attachmentID: String) -> AnyPublisher { return Future { promise in @@ -209,22 +205,23 @@ class OTFTheraforgeNetwork { .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + func refreshToken(_ completionHandler: @escaping (Result) -> Void) { - guard (TheraForgeKeychainService.shared.loadAuth() != nil) else { + + if TheraForgeKeychainService.shared.loadAuth() == nil { completionHandler(.failure(.missingCredential)) return } - + otfNetworkService.refreshToken { [weak self] response in self?.handleResponse(response, promise: completionHandler) } } - + func disconnectFromSSE() { NetworkingLayer.shared.eventSource?.disconnect() } - + func handleResponse(_ response: Result, completion: ((Result) -> Void)?) { switch response { case .success(_): @@ -237,11 +234,9 @@ class OTFTheraforgeNetwork { return } } - + completion?(response) } - - func handleResponse(_ response: Result, promise: (Result) -> Void) { switch response { case .success(_): @@ -254,13 +249,13 @@ class OTFTheraforgeNetwork { return } } - return promise(response) + return promise(response) } - + public func moveToOnboardingView() { DispatchQueue.main.async { UserDefaultsManager.setOnboardingCompleted(false) - try? CareKitManager.shared.wipe() + try? CareKitStoreManager.shared.wipe() self.disconnectFromSSE() NotificationCenter.default.post(name: .onboardingDidComplete, object: false) } diff --git a/OTFMagicBox/API/SSEAndSyncManager.swift b/OTFMagicBox/API/SSEAndSyncManager.swift index f5b00f1f..f1383b57 100644 --- a/OTFMagicBox/API/SSEAndSyncManager.swift +++ b/OTFMagicBox/API/SSEAndSyncManager.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -38,35 +38,42 @@ import OTFUtilities class SSEAndSyncManager { static let shared = SSEAndSyncManager() - + // Subscribe to SSE public func subscribeToSSEWith(auth: Auth) { OTFTheraforgeNetwork.shared.otfNetworkService.eventSourceOnOpen = { [unowned self] in syncDatabase(postNotification: true) } - + OTFTheraforgeNetwork.shared.otfNetworkService.onReceivedMessage = { [unowned self] event in OTFLog("event type %{public}@.", event.type.rawValue) if event.type.rawValue == EventType.dbUpdate.rawValue { syncDatabase(postNotification: true) } else if event.type.rawValue == EventType.userDeleted.rawValue { - NotificationCenter.default.post(name: .deleteUserAccount, object: nil) - } } - - OTFTheraforgeNetwork.shared.otfNetworkService.eventSourceOnComplete = { code, reconnect, error in + + OTFTheraforgeNetwork.shared.otfNetworkService.eventSourceOnComplete = { _, reconnect, error in OTFError("error on receiving event in SSEAndSyncManager %{public}@.", error?.localizedDescription ?? "") if reconnect == true { TheraForgeNetwork.shared.observeOnServerSentEvents(auth: auth) } } - + TheraForgeNetwork.shared.observeOnServerSentEvents(auth: auth) } - + private func syncDatabase(postNotification: Bool = false) { + // Sync local sore witth watchOS + CloudantSyncManager.shared.cloudantStore?.synchronize(target: .mobile, completion: { error in + if let error = error { + print(error) + } else { + OTFLog("Synced successfully!") + } + }) + CloudantSyncManager.shared.syncCloudantStore(notifyWhenDone: postNotification) { _ in } diff --git a/OTFMagicBox/API/TheraForgeHTTPInterceptor.swift b/OTFMagicBox/API/TheraForgeHTTPInterceptor.swift index af853b79..d14ce03b 100644 --- a/OTFMagicBox/API/TheraForgeHTTPInterceptor.swift +++ b/OTFMagicBox/API/TheraForgeHTTPInterceptor.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 OTFCDTDatastore @@ -42,7 +42,7 @@ class TheraForgeHTTPInterceptor: NSObject, CDTHTTPInterceptor { forHTTPHeaderField: "Client") context.request.addValue("\(TheraForgeNetwork.configurations!.apiKey)", forHTTPHeaderField: "API-KEY") - + if let currentAuth = TheraForgeNetwork.shared.currentAuth { context.request.setValue("Bearer \(currentAuth.token)", forHTTPHeaderField: "Authorization") } else if let auth = TheraForgeKeychainService.shared.loadAuth() { @@ -57,12 +57,12 @@ class TheraForgeHTTPInterceptor: NSObject, CDTHTTPInterceptor { NSLog("TheraForgeHTTPInterceptor: Response is nil") return context } - + guard let responseData = context.responseData else { NSLog("TheraForgeHTTPInterceptor: Response data is nil") return context } - + NSLog("TheraForgeHTTPInterceptor: \n\n\(context.request)\n\n\(String(describing: response))\n\ndata: \(String(data: responseData, encoding: .utf8)!)") return context } diff --git a/OTFMagicBox/AppDelegate.swift b/OTFMagicBox/AppDelegate.swift index 1718db81..27ca8e90 100644 --- a/OTFMagicBox/AppDelegate.swift +++ b/OTFMagicBox/AppDelegate.swift @@ -1,59 +1,69 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import UIKit +import OTFUtilities +import WatchConnectivity +import OTFCareKitStore +import OTFCloudantStore import OTFTemplateBox import OTFResearchKit -import OTFUtilities @main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - + let careKitManager = CareKitStoreManager.shared + private(set) lazy var sessionManager: SessionManager = { + let sessionManager = SessionManager() + sessionManager.peer = self.careKitManager.cloudantSyncManager.peer + sessionManager.store = self.careKitManager.cloudantStore + return sessionManager + }() + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. - + do { try OTFConfigManager.shared.loadDataFromFile(nil) } catch { OTFLog("error while loading data from file %{public}@", error.localizedDescription) } - let tintColor = YmlReader().tintColor + let tintColor = YmlReader().appStyle.buttonTextColor.color let defaultProtection = OTFConfigManager.shared.defaultOTFProtectionLevel() - + switch defaultProtection { case .runToCompletionWithIn10Seconds: OTFLog("Default protection is set runToCompletionWithIn10Seconds") @@ -67,25 +77,71 @@ class AppDelegate: UIResponder, UIApplicationDelegate { OCKStoreManager.shared.coreDataStore.populateSampleData() + WCSession.default.delegate = sessionManager + WCSession.default.activate() + UIView.appearance(whenContainedInInstancesOf: [ORKTaskViewController.self]).tintColor = tintColor + if #available(iOS 15, *) { + let appearance = UINavigationBarAppearance() + appearance.configureWithOpaqueBackground() + UINavigationBar.appearance().standardAppearance = appearance + UINavigationBar.appearance().scrollEdgeAppearance = appearance + } + return true } // MARK: UISceneSession Lifecycle - + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } - + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } - - } +class SessionManager: NSObject, WCSessionDelegate { + + fileprivate var peer: OTFWatchConnectivityPeer! + fileprivate var store: OTFCloudantStore! + + func session(_ session: WCSession, + activationDidCompleteWith activationState: WCSessionActivationState, + error: Error?) { + print("WCSession activation did complete: \(activationState)") + } + + func sessionDidBecomeInactive(_ session: WCSession) { + print("WCSession did become inactive") + } + + func sessionDidDeactivate(_ session: WCSession) { + print("WCSession did deactivate") + } + + func session(_ session: WCSession, + didReceiveMessage message: [String: Any], + replyHandler: @escaping ([String: Any]) -> Void) { + print("Did receive message from WATCHAPP! - \(message)") + if message[databaseSyncedKey] as? String != nil { + self.store.synchronize { error in + print(error?.localizedDescription ?? "Successful sync!") + DispatchQueue.main.async { + NotificationCenter.default.post(name: .databaseSuccessfllySynchronized, object: nil) + CloudantSyncManager.shared.syncCloudantStore(notifyWhenDone: false) { _ in } + } + } + } else { + peer.reply(to: message, store: store) { reply in + replyHandler(reply) + } + } + } +} diff --git a/OTFMagicBox/AppSysParameters.yml b/OTFMagicBox/AppSysParameters.yml index 1b8de5ff..7d0a6372 100644 --- a/OTFMagicBox/AppSysParameters.yml +++ b/OTFMagicBox/AppSysParameters.yml @@ -106,12 +106,13 @@ DataModel: useCareKit: "true" ############################################################################## -# TheraForge system # +# TheraForge Custom Style # ############################################################################## #Fixed colors -# Usually don't use fixed colors because they don't adapt to dark mode and accessibility mode. +# Avoid using fixed UIKit colors because they don't adapt to dark mode and accessibility modes. +# See: https://developer.apple.com/documentation/uikit/uicolor/standard_colors#3174519 # black # blue @@ -130,9 +131,10 @@ DataModel: # yellow -# Its recommened to use Adaptable colors because they adapt to dark mode and accessibility mode. -#Adaptable gray colors +# It's recommended to use adaptable UIKit grey colors because they adapt to dark mode and accessibility mode. +# See: https://developer.apple.com/documentation/uikit/uicolor/standard_colors#3281252 +# Adaptable gray colors # systemGray # systemGray1 # systemGray2 @@ -141,8 +143,11 @@ DataModel: # systemGray5 # systemGray6 -#Adaptable colors +# It's recommended to use adaptable UIKit colors because they adapt to dark mode and accessibility mode. +# See: https://developer.apple.com/documentation/uikit/uicolor/standard_colors#3174530 +# And see: https://developer.apple.com/documentation/uikit/uicolor/ui_element_colors +# Adaptable colors # systemBlue # systemBrown # systemOrange @@ -170,76 +175,80 @@ DataModel: # secondarySystemBackground # tertiarySystemBackground - appTheme: - backgroundColor: "systemBackground" - textColor: "label" - separatorColor: "separator" - cellbackgroundColor: "secondarySystemGroupedBackground" - buttonTextColor: "systemBlue" - borderColor: "Black" - headerColor: "label" - screenTitleFont: "Header" - screenTitleWeight: "" - headerTitleFont: "HeaderInherited" - headerTitleWeight: "Bold" - textWeight: "" - textFont: "Inherited" - appTitleSize: "Large Title" + # Select the active style + selectedStyle: "customStyle" + + # Define available styles with their respective configurations + styles: + # A clean and customizable look, providing a starting point for your unique app style. + - name: "customStyle" + # Background color of the app + backgroundColor: "systemBackground" + # Text color used throughout the app + textColor: "label" + # Color of separators between UI elements + separatorColor: "separator" + # Background color of table cells + cellbackgroundColor: "secondarySystemGroupedBackground" + # Text color for buttons with a red theme + buttonTextColor: "systemBlue" + # Color for borders + borderColor: "Black" + # Text color for headers and labels + headerColor: "label" + # Font for screen titles + screenTitleFont: "Header" + # Font weight for screen titles (if applicable) + screenTitleWeight: "" + # Font for header titles + headerTitleFont: "HeaderInherited" + # Font weight for header titles + headerTitleWeight: "Bold" + # Default font weight for text + textWeight: "" + # Default font for text + textFont: "Inherited" + # Font size for app titles + appTitleSize: "Large Title" + # Embraces the aesthetics of Apple's Health application, maintaining a familiar and health-centric appearance. + - name: "healthStyle" + backgroundColor: "systemBackground" + textColor: "label" + separatorColor: "separator" + cellbackgroundColor: "secondarySystemGroupedBackground" + buttonTextColor: "systemBlue" + borderColor: "Black" + headerColor: "label" + screenTitleFont: "Header" + screenTitleWeight: "" + headerTitleFont: "HeaderInherited" + headerTitleWeight: "Bold" + textWeight: "" + textFont: "Inherited" + appTitleSize: "Large Title" + # Provides a standard and consistent appearance, suitable for CareKit components. + - name: "careKitStyle" + backgroundColor: "systemBackground" + textColor: "label" + separatorColor: "separator" + cellbackgroundColor: "secondarySystemGroupedBackground" + buttonTextColor: "Teal" + borderColor: "Black" + headerColor: "label" + screenTitleFont: "Header" + screenTitleWeight: "" + headerTitleFont: "HeaderInherited" + headerTitleWeight: "Bold" + textWeight: "" + textFont: "Inherited" + appTitleSize: "Large Title" designConfig: # Offset value. - name: "offset" textValue: "20" - # Color codes - # Colors will be used in the design of the application. - # Please choose the colors according to Human Interface Guidelines from Apple. - # Refer here https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color - - name: "tintColor" - textValue: "Blue" - - name: "label" - textValue: "Teal" - - name: "secondaryLabel" - textValue: "Brown" - - name: "tertiaryLabel" - textValue: "Cyan" - - name: "customBackground" - textValue: "Brown" - - name: "secondaryCustomBackground" - textValue: "Black" - - name: "customGroupedBackground" - textValue: "Brown" - - name: "secondaryCustomGroupedBackground" - textValue: "Brown" - - name: "tertiaryCustomGroupedBackground" - textValue: "Brown" - - name: "separator" - textValue: "Gray" - - name: "customFill" - textValue: "Blue" - - name: "secondaryCustomFill" - textValue: "Mint" - - name: "tertiaryCustomFill" - textValue: "Teal" - - name: "quaternaryCustomFill" - textValue: "Blue" - - name: "customBlue" - textValue: "blue" - - name: "customGray" - textValue: "Gray" - - name: "customGray2" - textValue: "Gray2" - - name: "customGray3" - textValue: "Gray3" - - name: "customGray4" - textValue: "Gray4" - - name: "customGray5" - textValue: "Gray5" - - name: "black" - textValue: "black" - - name: "white" - textValue: "white" # Fonts # Fonts will be used in the design of the application. diff --git a/OTFMagicBox/CheckUp/CheckUpView.swift b/OTFMagicBox/CheckUp/CheckUpView.swift index d3065f31..0d5f3e22 100644 --- a/OTFMagicBox/CheckUp/CheckUpView.swift +++ b/OTFMagicBox/CheckUp/CheckUpView.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -37,28 +37,28 @@ import SwiftUI struct CheckUpView: View { @StateObject var viewmodel = CheckUpViewModel() @State private var isPresenting = false - + var body: some View { VStack { Text(Constants.CustomiseStrings.checkUp).font(.headerFontStyle) .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.screenTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) + .font(Font.otfscreenTitleFont) + .fontWeight(Font.otfheaderTitleWeight) List { Section(header: Text(Constants.CustomiseStrings.checkupListHeader) - .foregroundColor(.otfHeaderColor)) { - CountProgressRow(title: Constants.CustomiseStrings.progressRowTitle1, + .foregroundColor(.otfHeaderColor)) { + CountProgressRow(title: Constants.CustomiseStrings.progressRowTitle1, completed: viewmodel.activityTasksAndEvents.completedTasks.count, total: viewmodel.activityTasksAndEvents.eventsOfTasks.count, color: .blue, lineWidth: 4.0) .padding(.vertical, Metrics.PADDING_VERTICAL_ROW) - PercentProgressRow(title:Constants.CustomiseStrings.progressRowTitle2, + PercentProgressRow(title: Constants.CustomiseStrings.progressRowTitle2, progress: Float(viewmodel.medicationTasksAndEvents.progress), color: .green, lineWidth: 4.0) .padding(.vertical, Metrics.PADDING_VERTICAL_ROW) - PercentProgressRow(title:Constants.CustomiseStrings.progressRowTitle3, + PercentProgressRow(title: Constants.CustomiseStrings.progressRowTitle3, progress: Float(viewmodel.checkupTasksAndEvents.progress), color: .green, lineWidth: 4.0) @@ -70,16 +70,16 @@ struct CheckUpView: View { lineWidth: 4.0) .padding(.vertical, Metrics.PADDING_VERTICAL_ROW) } - .listRowBackground(Color.otfCellBackground) + .listRowBackground(Color.otfCellBackground) } - .onReceive(NotificationCenter.default.publisher(for: .deleteUserAccount)) { notification in + .onReceive(NotificationCenter.default.publisher(for: .deleteUserAccount)) { _ in isPresenting = true }.alert(isPresented: $isPresenting) { - + Alert( title: Text(Constants.CustomiseStrings.accountDeleted) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), message: Text(Constants.deleteAccount), dismissButton: .default(Text(Constants.CustomiseStrings.okay), action: { OTFTheraforgeNetwork.shared.moveToOnboardingView() @@ -88,8 +88,8 @@ struct CheckUpView: View { } .listStyle(GroupedListStyle()) .onAppear { - UITableView.appearance().separatorColor = YmlReader().appTheme?.separatorColor.color - UITableView.appearance().backgroundColor = YmlReader().appTheme?.backgroundColor.color + UITableView.appearance().separatorColor = YmlReader().appStyle.separatorColor.color + UITableView.appearance().backgroundColor = YmlReader().appStyle.backgroundColor.color DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { viewmodel.fetchTasks() } @@ -115,7 +115,7 @@ struct ViewProvider: LibraryContentProvider { lineWidth: 4.0), title: Constants.CustomiseStrings.rowTitle2, category: .control) - + LibraryItem(CountProgressRow(title: Constants.CustomiseStrings.rowTitle3, completed: 3, total: 5, @@ -123,25 +123,25 @@ struct ViewProvider: LibraryContentProvider { lineWidth: 4.0), title: Constants.CustomiseStrings.rowTitle4, category: .control) - + LibraryItem(InstructionTaskView(task: dummyTask, date: Date(), storeManager: storeManager), title: Constants.CustomiseStrings.rowTitle5, category: .control) - + LibraryItem(GridTaskView(task: dummyTask, date: Date(), storeManager: storeManager), title: Constants.CustomiseStrings.rowTitle6, category: .control) - + LibraryItem(SimpleTaskView(task: dummyTask, date: Date(), storeManager: storeManager), title: Constants.CustomiseStrings.rowTitle7, category: .control) - + LibraryItem(ChecklistTaskView(task: dummyTask, date: Date(), storeManager: storeManager), title: Constants.CustomiseStrings.rowTitle8, category: .control) - + LibraryItem(ButtonLogTaskView(task: dummyTask, date: Date(), storeManager: storeManager), title: Constants.CustomiseStrings.rowTitle9, diff --git a/OTFMagicBox/CheckUp/CheckUpViewModel.swift b/OTFMagicBox/CheckUp/CheckUpViewModel.swift index fb11b5cb..dae3401b 100644 --- a/OTFMagicBox/CheckUp/CheckUpViewModel.swift +++ b/OTFMagicBox/CheckUp/CheckUpViewModel.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -39,7 +39,6 @@ import OTFCareKitUI struct TaskEvents { let interval: DateInterval let events: [OCKEvent]? - var progress: Double { guard let events = events, !events.isEmpty else { return 0 } let performed = events.filter({ $0.outcome != nil }) @@ -50,14 +49,12 @@ struct TaskEvents { struct CategoryTasksAndEvents { let category: TaskCategory let eventsOfTasks: [TaskEvents] - var completedTasks: [OCKTask] { let completed = eventsOfTasks.filter({ $0.progress == 1 }) return completed.compactMap({ $0.events?.first?.task }) } - var progress: Double { - guard eventsOfTasks.count > 0 else { + guard !eventsOfTasks.isEmpty else { return 0 } return Double(completedTasks.count) / Double(eventsOfTasks.count) @@ -69,25 +66,25 @@ final class CheckUpViewModel: ObservableObject { @Published private(set) var activityTasksAndEvents = CategoryTasksAndEvents(category: .activity, eventsOfTasks: []) @Published private(set) var checkupTasksAndEvents = CategoryTasksAndEvents(category: .checkup, eventsOfTasks: []) @Published private(set) var appointmentTasksAndEvents = CategoryTasksAndEvents(category: .appointment, eventsOfTasks: []) - + func fetchTasks() { let todayStart = Calendar.current.startOfDay(for: Date()) let todayEnd = Calendar.current.date(byAdding: .day, value: 1, to: todayStart)!.addingTimeInterval(-1) let todayInterval = DateInterval(start: todayStart, end: todayEnd) let query = OCKTaskQuery(dateInterval: DateInterval(start: todayStart, end: todayEnd)) - - CareKitManager.shared.cloudantStore?.fetchTasks(query: query, - callbackQueue: DispatchQueue.global(qos: .userInitiated)) { result in + + CareKitStoreManager.shared.cloudantStore?.fetchTasks(query: query, + callbackQueue: DispatchQueue.global(qos: .userInitiated)) { result in if case let .success(tasks) = result { let group = DispatchGroup() var error: Error? var events: [OCKEvent] = [] - + for task in tasks { group.enter() let query = OCKEventQuery(dateInterval: todayInterval) - - CareKitManager.shared.cloudantStore?.fetchEvents(task: task, query: query, previousEvents: []) { + + CareKitStoreManager.shared.cloudantStore?.fetchEvents(task: task, query: query, previousEvents: []) { switch $0 { case .failure(let fetchError): error = fetchError @@ -97,21 +94,21 @@ final class CheckUpViewModel: ObservableObject { group.leave() } } - + group.notify(queue: .main) { if error != nil { return } - + let medTasksAndEvents = events.getTasksAndEventsOf(category: .medication, for: todayInterval) self.medicationTasksAndEvents = CategoryTasksAndEvents(category: .medication, eventsOfTasks: medTasksAndEvents) - + let actTasksAndEvents = events.getTasksAndEventsOf(category: .activity, for: todayInterval) self.activityTasksAndEvents = CategoryTasksAndEvents(category: .activity, eventsOfTasks: actTasksAndEvents) - + let checkupTasksAndEvents = events.getTasksAndEventsOf(category: .checkup, for: todayInterval) self.checkupTasksAndEvents = CategoryTasksAndEvents(category: .checkup, eventsOfTasks: checkupTasksAndEvents) - + let appointTasksAndEvents = events.getTasksAndEventsOf(category: .appointment, for: todayInterval) self.appointmentTasksAndEvents = CategoryTasksAndEvents(category: .appointment, eventsOfTasks: appointTasksAndEvents) } diff --git a/OTFMagicBox/CheckUp/CountProgressRow.swift b/OTFMagicBox/CheckUp/CountProgressRow.swift index 288fd89c..295dfbcb 100644 --- a/OTFMagicBox/CheckUp/CountProgressRow.swift +++ b/OTFMagicBox/CheckUp/CountProgressRow.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -35,41 +35,41 @@ import SwiftUI struct CountProgressRow: View { - + static var lessonsCompleted: CountProgressRow { CountProgressRow(title: "Lessons Completed", completed: 3, total: 5, color: .green, lineWidth: 4.0) } - + static var appointmentsScheduled: CountProgressRow { CountProgressRow(title: "Appointments", completed: 1, total: 3, color: .green, lineWidth: 4.0) } - + var title: String var completed: Int var total: Int var color: Color var lineWidth: CGFloat var opacity: Double = 0.3 - + var body: some View { HStack { Text(title) .foregroundColor(.otfTextColor) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont) Spacer() Text("\(completed) of \(total)") - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) .foregroundColor(color) RingProgressView(progress: total < 1 ? 0 : Float(completed) / Float(total), - color: color, - lineWidth: lineWidth) - .frame(width: Metrics.FRAME_ROW_WIDTH, height: Metrics.FRAME_ROW_HEIGHT) + color: color, + lineWidth: lineWidth) + .frame(width: Metrics.FRAME_ROW_WIDTH, height: Metrics.FRAME_ROW_HEIGHT) } } } diff --git a/OTFMagicBox/CheckUp/PercentProgressRow.swift b/OTFMagicBox/CheckUp/PercentProgressRow.swift index 94153305..bd699eac 100644 --- a/OTFMagicBox/CheckUp/PercentProgressRow.swift +++ b/OTFMagicBox/CheckUp/PercentProgressRow.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -41,35 +41,35 @@ struct PercentProgressRow: View { color: .green, lineWidth: 4.0) } - + static var vitalsMeasured: PercentProgressRow { PercentProgressRow(title: "Checkups", progress: 0, color: .green, lineWidth: 4.0) } - + var title: String var progress: Float var color: Color var lineWidth: CGFloat var opacity: Double = 0.3 - + var body: some View { HStack { Text(title) .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) Spacer() Text(String(format: "%.1f", progress*100) + "%") .foregroundColor(color) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) RingProgressView(progress: progress, - color: color, - lineWidth: lineWidth) - .frame(width: Metrics.FRAME_ROW_WIDTH, height: Metrics.FRAME_ROW_HEIGHT) + color: color, + lineWidth: lineWidth) + .frame(width: Metrics.FRAME_ROW_WIDTH, height: Metrics.FRAME_ROW_HEIGHT) } } } diff --git a/OTFMagicBox/Consent/ConsentDocument.swift b/OTFMagicBox/Consent/ConsentDocument.swift index 9666ba53..f330bbe8 100644 --- a/OTFMagicBox/Consent/ConsentDocument.swift +++ b/OTFMagicBox/Consent/ConsentDocument.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 OTFResearchKit @@ -38,17 +38,12 @@ import OTFResearchKit The Consent document of the patient. */ class ConsentDocument: ORKConsentDocument { - // MARK: Properties - override init() { super.init() - let consentTitle = ModuleAppYmlReader().consentTitle - title = consentTitle ?? Constants.YamlDefaults.ConsentTitle sections = [] - let sectionTypes: [ORKConsentSectionType] = [ .overview, .dataGathering, @@ -60,68 +55,59 @@ class ConsentDocument: ORKConsentDocument { .withdrawing, .custom ] - - let consentData = (ModuleAppYmlReader().consent?.data ?? [ConsentDescription(show: Constants.YamlDefaults.ConsentShow ? Constants.true : Constants.false, summary: Constants.YamlDefaults.ConsentSummary, content: Constants.YamlDefaults.ConsentContent, title: Constants.YamlDefaults.defaultTitleForRK, image: Constants.Images.ConsentCustomImg)]) - + let consentData = (ModuleAppYmlReader().consent?.data ?? [ConsentDescription( + show: Constants.YamlDefaults.ConsentShow ? Constants.true : Constants.false, + summary: Constants.YamlDefaults.ConsentSummary, + content: Constants.YamlDefaults.ConsentContent, + title: Constants.YamlDefaults.defaultTitleForRK, + image: Constants.Images.ConsentCustomImg)]) for (sectionType, consentData) in zip(sectionTypes, consentData) where consentData.show == Constants.true { let section = ORKConsentSection(type: sectionType) - if sectionType == .custom { section.customImage = UIImage(named: consentData.image)?.crop(to: Constants.sizeToCropImage) section.title = consentData.title } else { section.title = consentData.title } - section.summary = consentData.summary - section.content = consentData.content - sections?.append(section) + section.summary = consentData.summary + section.content = consentData.content + sections?.append(section) } - - let signature = ORKConsentSignature(forPersonWithTitle: nil, dateFormatString: nil, identifier: Constants.UserDefaults.ConsentDocumentSignature) + let signature = ORKConsentSignature(forPersonWithTitle: nil, + dateFormatString: nil, + identifier: Constants.UserDefaults.ConsentDocumentSignature) signature.title = title signaturePageTitle = title addSignature(signature) } - required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension ORKConsentSectionType: CustomStringConvertible { - public var description: String { switch self { case .overview: return "Welcome" - case .privacy: return "Protecting your Data" - case .dataUse: return "Data Use" - case .timeCommitment: return "Time Commitment" - case .studySurvey: return "Surveys" - case .studyTasks: return "Study Tasks" - case .withdrawing: return "Withdrawing" - case .custom: return "Custom consent section" - case .onlyInDocument: return "Only In Document" - case .dataGathering: return "Data Processing" - @unknown default: return "" } diff --git a/OTFMagicBox/Contacts/ContactsViewController.swift b/OTFMagicBox/Contacts/ContactsViewController.swift index eee15a2b..61ba2916 100644 --- a/OTFMagicBox/Contacts/ContactsViewController.swift +++ b/OTFMagicBox/Contacts/ContactsViewController.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -43,28 +43,28 @@ struct ContactsViewController: UIViewControllerRepresentable { @State private var contactsListViewController: OCKContactsListViewController var syncStoreManager: OCKSynchronizedStoreManager let queue = OperationQueue() - + init(storeManager: OCKSynchronizedStoreManager) { self.syncStoreManager = storeManager let viewController = OCKContactsListViewController(storeManager: storeManager) contactsListViewController = viewController viewController.title = Constants.CustomiseStrings.careTeam - + NotificationCenter.default.addObserver(forName: .deleteUserAccount, object: nil, queue: queue) { _ in DispatchQueue.main.async { - viewController.alertWithAction(title: Constants.CustomiseStrings.accountDeleted, message: Constants.deleteAccount) { action in + viewController.alertWithAction(title: Constants.CustomiseStrings.accountDeleted, message: Constants.deleteAccount) { _ in OTFTheraforgeNetwork.shared.moveToOnboardingView() } } } - + NotificationCenter.default.addObserver(forName: .databaseSuccessfllySynchronized, object: nil, queue: queue) { _ in viewController.fetchContacts() } } - + func updateUIViewController(_ taskViewController: OCKContactsListViewController, context: Context) {} - + func makeUIViewController(context: Context) -> OCKContactsListViewController { return contactsListViewController } @@ -73,7 +73,7 @@ struct ContactsViewController: UIViewControllerRepresentable { struct ContactsNavigationView: View { let syncStoreManager: OCKSynchronizedStoreManager @State private var isPresenting = false - + var body: some View { NavigationView { ContactsViewController(storeManager: syncStoreManager) diff --git a/OTFMagicBox/ContentView.swift b/OTFMagicBox/ContentView.swift index 19578309..fdcf7ea2 100644 --- a/OTFMagicBox/ContentView.swift +++ b/OTFMagicBox/ContentView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI @@ -38,8 +38,8 @@ import OTFResearchKit struct ContentView: View { var body: some View { Text("Hello, world!") - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) .padding() } } diff --git a/OTFMagicBox/Datastore/CareKitStoreManager.swift b/OTFMagicBox/Datastore/CareKitStoreManager.swift index d9fdeae8..1c5b0ea0 100644 --- a/OTFMagicBox/Datastore/CareKitStoreManager.swift +++ b/OTFMagicBox/Datastore/CareKitStoreManager.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 Combine @@ -38,56 +38,59 @@ import OTFCareKitStore import OTFCloudantStore import OTFUtilities -class CareKitManager: NSObject { - - #if HEALTH - let healthKitStore = OCKHealthKitPassthroughStore(name: "CareKitHealthKitStore", - type: .onDisk(protection: .none)) - #endif +class CareKitStoreManager: NSObject { + lazy var peer = OTFWatchConnectivityPeer() +// private(set) lazy var cdStore = OCKStore(name: "local_db", type: .inMemory, remote: peer) +// private(set) lazy var hkStore = OCKHealthKitPassthroughStore(store: cdStore) +// #if HEALTH +// let healthKitStore = OCKHealthKitPassthroughStore(name: "CareKitHealthKitStore", +// type: .onDisk(protection: .none), remote: peer) +// #endif private(set) var cloudantStore: OTFCloudantStore? private(set) var synchronizedStoreManager: OCKSynchronizedStoreManager! + private(set) var cloudantSyncManager = CloudantSyncManager.shared private(set) lazy var coordinator: OCKStoreCoordinator = { let coordinator = OCKStoreCoordinator() return coordinator }() - - static let shared = CareKitManager() - + + static let shared = CareKitStoreManager() + override init() { super.init() - - initStore() - - #if HEALTH - coordinator.attach(store: healthKitStore) - #endif - - synchronizedStoreManager = OCKSynchronizedStoreManager(wrapping: coordinator) - - subscribeToNotifications() - - guard let cloudantStore = CloudantSyncManager.shared.cloudantStore else { return } + + guard let cloudantStore = cloudantSyncManager.cloudantStore else { return } self.cloudantStore = cloudantStore coordinator.attach(store: cloudantStore) + synchronizedStoreManager = OCKSynchronizedStoreManager(wrapping: coordinator) + + subscribeToNotifications() } - + func wipe() throws { try CloudantSyncManager.shared.cloudantStore?.datastoreManager.deleteDatastoreNamed("local_db") } - + fileprivate func initStore(forceUpdate: Bool = false) { #if HEALTH healthKitStore.populateSampleData() #endif UserDefaults.standard.set(Date(), forKey: Constants.prefCareKitDataInitDate) } - + private func subscribeToNotifications() { - let subscriber = Subscribers.Sink { completion in - } receiveValue: { storeNotification in + let subscriber = Subscribers.Sink { _ in + } receiveValue: { _ in + CloudantSyncManager.shared.cloudantStore?.synchronize(target: .mobile, completion: { error in + if let error = error { + print(error) + } else { + OTFLog("Synced successfully!") + } + }) CloudantSyncManager.shared.syncCloudantStore(notifyWhenDone: true, completion: nil) } - + synchronizedStoreManager.notificationPublisher.receive(subscriber: subscriber) } } diff --git a/OTFMagicBox/Datastore/CloudantSyncManager.swift b/OTFMagicBox/Datastore/CloudantSyncManager.swift index c4b69998..3657acb0 100644 --- a/OTFMagicBox/Datastore/CloudantSyncManager.swift +++ b/OTFMagicBox/Datastore/CloudantSyncManager.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -44,7 +44,7 @@ struct Configuration { let targetURL: URL let username: String let password: String - + static var `default`: Configuration { let remoteURLString = Constants.API.dbProxyURL let remoteURL = URL(string: remoteURLString)! @@ -59,35 +59,35 @@ enum ReplicationDirection: String { class CloudantSyncManager { static let shared = CloudantSyncManager() var cloudantStore: OTFCloudantStore? - + let peer = OTFWatchConnectivityPeer() + var storeManager: OCKSynchronizedStoreManager { - CareKitManager.shared.synchronizedStoreManager + CareKitStoreManager.shared.synchronizedStoreManager } - + private var lastSynced: Date private var shouldSyncAgain: Bool { let secondsDiff = Date().timeIntervalSince(lastSynced) return secondsDiff >= 300 } - + private init() { - cloudantStore = try? StoreService.shared.currentStore() + cloudantStore = try? StoreService.shared.currentStore(peer: peer) guard let lastDate = Calendar.current.date(byAdding: .minute, value: -10, to: Date()) else { lastSynced = Date() return } lastSynced = lastDate } - + func syncCloudantStore(notifyWhenDone: Bool, completion: ((Error?) -> Void)?) { guard let auth = TheraForgeKeychainService.shared.loadAuth() else { completion?(ForgeError.missingCredential) return } - - // TODO: - Implement a check to avoid synchronisation for every little change. + // Perhaps use a timer and sync only if there are changes, perhaps. - + if auth.isValid() { startSync(notifyWhenDone: notifyWhenDone, completion: completion) } else { @@ -95,14 +95,14 @@ class CloudantSyncManager { switch result { case .success(_): startSync(notifyWhenDone: notifyWhenDone, completion: completion) - + case .failure(let error): completion?(error) } } } } - + private func startSync(notifyWhenDone: Bool, completion: ((Error?) -> Void)?) { do { try replicate(direction: .push, completionBlock: { [unowned self] error in @@ -110,22 +110,23 @@ class CloudantSyncManager { didFinishSyncWith(error: error, completion: completion) return } - + do { try replicate(direction: .pull, completionBlock: { [unowned self] error in if let error = error { OTFError("error in cloudent manager %{public}@", error.localizedDescription) - } - else { -#if DEBUG + } else { + #if DEBUG OTFLog("Synced successfully!") -#endif + #endif lastSynced = Date() + if notifyWhenDone { DispatchQueue.main.async { NotificationCenter.default.post(name: .databaseSuccessfllySynchronized, object: nil) } } + } didFinishSyncWith(error: error, completion: completion) }) @@ -137,20 +138,20 @@ class CloudantSyncManager { didFinishSyncWith(error: error, completion: completion) } } - + private func didFinishSyncWith(error: Error?, completion: ((Error?) -> Void)?) { DispatchQueue.main.async { completion?(error) } } - + private func replicate(direction: ReplicationDirection, completionBlock: @escaping ((Error?) -> Void)) throws { - let store = try StoreService.shared.currentStore() + let store = try StoreService.shared.currentStore(peer: peer) let datastoreManager = store.datastoreManager let factory = CDTReplicatorFactory(datastoreManager: datastoreManager) - + let configuration = Configuration.default - + let replication: CDTAbstractReplication switch direction { case .push: @@ -164,15 +165,15 @@ class CloudantSyncManager { username: configuration.username, password: configuration.password) } - + replication.add(TheraForgeHTTPInterceptor()) - + let replicator = try factory.oneWay(replication) let dataStore = try datastoreManager.datastoreNamed("local_db") - + replicator.sessionConfigDelegate = TheraForgeNetwork.shared dataStore.sessionConfigDelegate = TheraForgeNetwork.shared - + switch direction { case .push: dataStore.push(to: configuration.targetURL, replicator: replicator, username: configuration.username, password: configuration.password) { (error: Error?) in @@ -184,7 +185,7 @@ class CloudantSyncManager { completionBlock(nil) } } - + case .pull: dataStore.pull(from: configuration.targetURL, replicator: replicator, username: configuration.username, password: configuration.password) { error in completionBlock(error) diff --git a/OTFMagicBox/Datastore/OCKStoreManager.swift b/OTFMagicBox/Datastore/OCKStoreManager.swift index 657780a3..b57e2249 100644 --- a/OTFMagicBox/Datastore/OCKStoreManager.swift +++ b/OTFMagicBox/Datastore/OCKStoreManager.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -31,15 +31,17 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + import OTFCareKit import OTFCareKitStore +import WatchConnectivity class OCKStoreManager: ObservableObject { static let shared = OCKStoreManager() - - lazy private(set) var coreDataStore = OCKStore(name: "SampleAppStore", type: .inMemory) - - lazy private(set) var synchronizedStoreManager: OCKSynchronizedStoreManager = { + + private(set) lazy var coreDataStore = OCKStore(name: "SampleAppStore", type: .inMemory) + + private(set) lazy var synchronizedStoreManager: OCKSynchronizedStoreManager = { let coordinator = OCKStoreCoordinator() coordinator.attach(store: coreDataStore) return OCKSynchronizedStoreManager(wrapping: coordinator) diff --git a/OTFMagicBox/HealthData/HealthDataStep.swift b/OTFMagicBox/HealthData/HealthDataStep.swift index 152b4165..2eaf7bcf 100644 --- a/OTFMagicBox/HealthData/HealthDataStep.swift +++ b/OTFMagicBox/HealthData/HealthDataStep.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -33,34 +33,32 @@ */ import OTFResearchKit - - /** The Health data step of the patient. */ class HealthDataStep: ORKInstructionStep { - + override init(identifier: String) { super.init(identifier: identifier) - + title = ModuleAppYmlReader().healthPermissionsTitle text = ModuleAppYmlReader().healthPermissionsText } - + required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + } /** This class was created to override the `goForward` functionality. */ class HealthDataStepViewController: ORKInstructionStepViewController { - + override func goForward() { let manager = OTFHealthKitManager.shared - manager.getHealthAuthorization() { _,_ in + manager.getHealthAuthorization { _, _ in OperationQueue.main.addOperation { super.goForward() } diff --git a/OTFMagicBox/HealthData/HealthRecordStep.swift b/OTFMagicBox/HealthData/HealthRecordStep.swift index 03b9e20d..5ce3ad7b 100644 --- a/OTFMagicBox/HealthData/HealthRecordStep.swift +++ b/OTFMagicBox/HealthData/HealthRecordStep.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -39,28 +39,28 @@ import OTFResearchKit The Health Records Step will ask for a permission to collect HealthKit health records data of a patient. */ class HealthRecordsStep: ORKInstructionStep { - + override init(identifier: String) { super.init(identifier: identifier) - + let recordsConfig = ModuleAppYmlReader().healthRecords - + title = recordsConfig?.permissionsTitle ?? Constants.YamlDefaults.HealthRecordsPermissionsTitle - + text = recordsConfig?.permissionsText ?? Constants.YamlDefaults.HealthRecordsPermissionsText } - + required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + } class HealthRecordsStepViewController: ORKInstructionStepViewController { - + /** When this step is being dismissed, get `HealthKit` authorization in the process. - + Relies on a `CKHealthDataStep` instance as `self.step`. */ override func goForward() { @@ -69,7 +69,7 @@ class HealthRecordsStepViewController: ORKInstructionStepViewController { if succeeded { manager.upload() } - + OperationQueue.main.addOperation { super.goForward() } diff --git a/OTFMagicBox/Library/ActivityLoader.swift b/OTFMagicBox/Library/ActivityLoader.swift deleted file mode 100644 index 237b7aeb..00000000 --- a/OTFMagicBox/Library/ActivityLoader.swift +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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 SwiftUI - -struct LoaderView: View { - var tintColor: Color = .black - var scaleSize: CGFloat = 1.0 - - var body: some View { - ProgressView() - .scaleEffect(scaleSize, anchor: .center) - .progressViewStyle(CircularProgressViewStyle(tint: tintColor)) - } -} - -extension View { - @ViewBuilder func hidden(_ shouldHide: Bool) -> some View { - switch shouldHide { - case true: self.hidden() - case false: self - } - } -} diff --git a/OTFMagicBox/Library/ActivityManager.swift b/OTFMagicBox/Library/ActivityManager.swift index e537966e..12b445ae 100644 --- a/OTFMagicBox/Library/ActivityManager.swift +++ b/OTFMagicBox/Library/ActivityManager.swift @@ -1,104 +1,104 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation import HealthKit -public class ActivityManager : NSObject { - +public class ActivityManager: NSObject { + public static let shared = ActivityManager() - - public override init() { + + override public init() { super.init() - + _ = HealthKitManager.shared } - + public func load() { guard hasGrantedAuth && !typesToCollect.isEmpty else { return } - - getHealthAuthorizaton(forTypes: self.typesToCollect) { [weak self] (success, error) in - if (success) { - self?.startHealthKitCollectionInBackground(withFrequency: .hourly) // TODO: get last freq + + getHealthAuthorizaton(forTypes: self.typesToCollect) { [weak self] (success, _) in + if success { + self?.startHealthKitCollectionInBackground(withFrequency: .hourly) } } } - - public func getHealthAuthorizaton(forTypes typesToCollect:Set, _ completion: @escaping (_ success: Bool, _ error: Error?) -> Void) { + + public func getHealthAuthorizaton(forTypes typesToCollect: Set, _ completion: @escaping (_ success: Bool, _ error: Error?) -> Void) { self.typesToCollect = typesToCollect HealthKitManager.shared.getHealthKitAuth(forTypes: self.typesToCollect) { [weak self] (success, error) in self?.hasGrantedAuth = success completion(success, error) } } - + public func startHealthKitCollectionInBackground(fromStartDate startDate: Date? = nil, withFrequency frequency: HKUpdateFrequency, _ completion: ((_ success: Bool, _ error: Error?) -> Void)? = nil) { - - //check for auth + + // check for auth guard hasGrantedAuth else { let error = NSError(domain: Constants.app, code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot startHealthKitCollection without getting auth permissions first."]) completion?(false, error) return } - - //record beginning of data collection + + // record beginning of data collection if let startDate = startDate { UserDefaults.standard.set(startDate, forKey: Constants.UserDefaults.HKStartDate) } - - //and get health authorization + + // and get health authorization HealthKitManager.shared.startBackgroundDelivery(forTypes: typesToCollect, withFrequency: frequency) { [weak self] (success, error) in self?.hasStartedCollection = success completion?(success, error) } } - + public func stopHealthKitCollection() { - HealthKitManager.shared.disableHealthKit() { [weak self] (success, error) in - if (success) { //disable successfully - self?.hasStartedCollection = false //we have disabled + HealthKitManager.shared.disableHealthKit { [weak self] (success, _) in + if success { // disable successfully + self?.hasStartedCollection = false // we have disabled } } } - + fileprivate let keyHasStartedCollection = "hasStartedCollection" fileprivate let keyHasGrantedAuth = "hasGrantedAuth" fileprivate let keyTypesToCollect = "typesToCollect" - - fileprivate var hasStartedCollection : Bool { + + fileprivate var hasStartedCollection: Bool { get { return UserDefaults.standard.bool(forKey: keyHasStartedCollection) } @@ -106,8 +106,8 @@ public class ActivityManager : NSObject { UserDefaults.standard.set(newValue, forKey: keyHasStartedCollection) } } - - fileprivate var hasGrantedAuth : Bool { + + fileprivate var hasGrantedAuth: Bool { get { return UserDefaults.standard.bool(forKey: keyHasGrantedAuth) } @@ -115,18 +115,18 @@ public class ActivityManager : NSObject { UserDefaults.standard.set(newValue, forKey: keyHasGrantedAuth) } } - + fileprivate var _typesToCollect = Set() fileprivate var typesToCollect: Set { get { - if (!_typesToCollect.isEmpty) { + if !_typesToCollect.isEmpty { return _typesToCollect } - + guard let typeIds = UserDefaults.standard.array(forKey: keyTypesToCollect) as? [String] else { return Set() // no types to process } - + var types = Set() for type in typeIds { let type = HKQuantityTypeIdentifier(rawValue: type) @@ -134,8 +134,8 @@ public class ActivityManager : NSObject { types.insert(parsedType) } } - - if (!types.isEmpty) { + + if !types.isEmpty { _typesToCollect = types } return types @@ -149,5 +149,5 @@ public class ActivityManager : NSObject { _typesToCollect = newValue } } - + } diff --git a/OTFMagicBox/Library/Constants.swift b/OTFMagicBox/Library/Constants.swift index 9afe6918..22523640 100644 --- a/OTFMagicBox/Library/Constants.swift +++ b/OTFMagicBox/Library/Constants.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -40,76 +40,61 @@ enum Constants { static let userType = "patient" static let patientFirstName = "patientFirstName" static let patientLastName = "patientLastName" - static let yamlFile = "AppSysParameters.yml" static let moduleAppFileName = "ModuleAppSysParameter.yml" - static let prefConfirmedLogin = "PREF_CONFIRMED_LOGIN" static let prefFirstRunWasMarked = "PREF_FIRST_RUN" static let prefUserEmail = "PREF_USER_EMAIL" - static let prefCareKitDataInitDate = "PREF_DATA_INIT_DATE" static let prefHealthRecordsLastUploaded = "PREF_HEALTH_LAST_UPLOAD" - static let notificationUserLogin = "NOTIFICATION_USER_LOGIN" - static let dataBucketUserDetails = "userDetails" static let dataBucketSurveys = "surveys" static let dataBucketHealthKit = "healthKit" static let dataBucketStorage = "storage" - static let onboardingDidComplete = "didCompleteOnboarding" static let isConsentDocumentViewed = "isConsentDocumentViewed" - static let sizeToCropImage = CGSize(width: 1920.0, height: 1500.0) - // String representation of Bool to compare with yaml file's booleans static let `true` = "true" static let `false` = "false" - static let deleteAccount = "Your account is deleted from one of your device" - struct UserDefaults { - //Patient data + enum UserDefaults { + // Patient data static let patientEmail = "patientEmail" static let patientFirstName = "patientFirstName" static let patientLastName = "patientLastName" static let patientGender = "female" static let patientDob = "10/10/1990" - - - //Consent + // Consent static let ConsentDocumentSignature = "ConsentDocumentParticipantSignature" static let ConsentDocumentURL = "consentFormURL" - - //Misc + // Misc static let FirstRun = "firstRun" static let FirstLogin = "firstLogin" static let CompletedMarketingSurvey = "completedMarketingSurvey" static let HKDataShare = "healthKitShare" static let HKStartDate = "healthKitDate" - - //Session + // Session static let DeviceToken = "deviceToken" static let UserId = "userId" static let ValidSession = "validSession" - // Surveys static let MedicalSurvey = "medicalSurvey" static let SF12Survey = "sf12Survey" static let SurgicalSurvey = "surgicalSurvey" static let PhysicalSurvey = "physicalSurvey" - // Watch static let WatchReceivedFiles = "watch.receivedFiles" static let WatchTransferFailedFiles = "watch.failedFiles" } - struct Notification { + enum Notification { static let MessageArrivedNotification = "MessageArrivedNotification" static let DidRegisterNotifications = "DidRegisterUserNotificationSettings" static let DidRegisterNotificationsWithToken = "didRegisterForRemoteNotificationsWithDeviceToken" - + static let WalkTestRequest = "WalkTestRequest" static let APIUserErrorNotification = "APIUserErrorNotification" static let DataSyncRequest = "DataSyncRequest" @@ -119,20 +104,17 @@ enum Constants { static let deleteUserAccount = "DeleteUserAccount" static let deleteProfile = "DeleteProfile" static let fetchImage = "FetchImage" - - //Reset tab navigation badges + // Reset tab navigation badges static let BadgeReset = "BadgeReset" - - //Session + // Session static let SessionExpired = "UserSessionExpired" static let SessionReset = "SessionReset" - - //Watch + // Watch static let SessionWatchReachabilityDidChange = "SessionWatchReachabilityDidChange" static let SessionWatchStateDidChange = "sessionWatchStateDidChange" } - struct YamlDefaults { + enum YamlDefaults { static let APIKey = "this_is_a_dummy_key_to_be_replaced_by_a_valid_one" static let FileName = "AppSysParameters.yml" static let moduleAppFileName = "ModuleAppSysParameter.yml" @@ -171,13 +153,17 @@ enum Constants { static let learnMoreTitle = "Learn more title" static let birthdayText = "When is your birthday?" static let favorite = "Which is your favorite apple?" - static let participantsText = "Please use this space to provide instructions for participants. Please make sure to provide enough information so that users can progress through the survey and complete with ease." + static let participantsText = """ + Please use this space to provide instructions for participants. \ + Please make sure to provide enough information so that users can \ + progress through the survey and complete with ease. + """ static let YourQuestion = "Your question goes here" static let defaultTitleForRK = "Default Title" static let AppTitleSize = "Title" } - - struct CustomiseStrings { + + enum CustomiseStrings { static let signUp = "Sign Up" static let signinWithApple = "Sign in with Apple" static let resetPassword = "Reset Password" @@ -260,7 +246,12 @@ Your password does not meet the following criteria: minimum 8 characters with at static let apiKeyMissing = "API Key Missing" static let intendedDescription = "Tests ability to walk" static let instructionStepTitle = "Patient Questionnaire" - static let instructionStepText = "This information will help your doctors keep track of how you feel and how well you are able to do your usual activities. If you are unsure about how to answer a question, please give the best answer you can and make a written comment beside your answer." + static let instructionStepText = + """ + This information will help your doctors keep track of how you feel and how well you are able to do your usual activities. + If you are unsure about how to answer a question, please give the best answer you can and make a written comment beside your answer. + """ + static let healthScaleTitle = "Question #1" static let healthScaleQuestion = "In general, would you say your health is:" static let rowTitle1 = "Row Title" @@ -282,17 +273,17 @@ Your password does not meet the following criteria: minimum 8 characters with at static let faceIdAlertMessage = "To use faceID authentication please login with your credientials first." static let touchIdAlertMessage = "To use touchID authentication please login with your credientials first" } - - struct Images { - static let ConsentCustomImg = "online-agreement1" + + enum Images { + static let ConsentCustomImg = "online-agreement" } - - struct Passcode { + + enum Passcode { static let lengthSix = "6" static let lengthFour = "4" } - - struct Identifier { + + enum Identifier { static let ConsentStep = "VisualConsentStep" static let ConsentReviewStep = "ConsentReviewStep" static let HealthKitDataStep = "Healthkit" @@ -301,23 +292,23 @@ Your password does not meet the following criteria: minimum 8 characters with at static let CompletionStep = "CompletionStep" static let StudyOnboardingTask = "StudyOnboardingTask" } - - struct Registration { + + enum Registration { static let Identifier = "RegistrationStep" static let Title = "Registration" static let Text = "Sign up for this study." static let PasscodeInvalidMessage = "Password must be at least 10 characters in length." } - - struct Login { + + enum Login { static let Identifier = "LoginStep" static let Title = "Login" static let Text = "Log into this study." } - - struct API { - static let developmentUrl = "https://theraforge.org/api" + + enum API { + static let developmentUrl = "https://stg.theraforge.org/api" static let dbProxyURL = API.developmentUrl + "/v1/db/" } - + } diff --git a/OTFMagicBox/Library/Extension/Environment+StoreManager.swift b/OTFMagicBox/Library/Extension/Environment+StoreManager.swift index 637e3882..af88eebd 100644 --- a/OTFMagicBox/Library/Extension/Environment+StoreManager.swift +++ b/OTFMagicBox/Library/Extension/Environment+StoreManager.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -35,18 +35,17 @@ import Foundation import OTFCareKit -import Foundation import SwiftUI private struct StoreManagerEnvironmentKey: EnvironmentKey { - + static var defaultValue: OCKSynchronizedStoreManager { return OCKStoreManager.shared.synchronizedStoreManager } } public extension EnvironmentValues { - + var storeManager: OCKSynchronizedStoreManager { get { self[StoreManagerEnvironmentKey.self] } set { self[StoreManagerEnvironmentKey.self] = newValue } diff --git a/OTFMagicBox/Library/Extension/Extension+Array.swift b/OTFMagicBox/Library/Extension/Extension+Array.swift index fe8d33ad..4e9160eb 100644 --- a/OTFMagicBox/Library/Extension/Extension+Array.swift +++ b/OTFMagicBox/Library/Extension/Extension+Array.swift @@ -9,11 +9,11 @@ import Sodium extension Array { func splitFile() -> (left: [Element], right: [Element]) { - let size = self.count - let splitIndex = SecretStream.XChaCha20Poly1305.HeaderBytes - let leftSplit = self[0 ..< splitIndex] - let rightSplit = self[splitIndex ..< size] - - return (left: Array(leftSplit), right: Array(rightSplit)) - } + let size = self.count + let splitIndex = SecretStream.XChaCha20Poly1305.HeaderBytes + let leftSplit = self[0 ..< splitIndex] + let rightSplit = self[splitIndex ..< size] + + return (left: Array(leftSplit), right: Array(rightSplit)) + } } diff --git a/OTFMagicBox/Library/Extension/Extension+Character.swift b/OTFMagicBox/Library/Extension/Extension+Character.swift index 06cca258..ef6e58e8 100644 --- a/OTFMagicBox/Library/Extension/Extension+Character.swift +++ b/OTFMagicBox/Library/Extension/Extension+Character.swift @@ -1,44 +1,44 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation /** - Extension of Character to check the existance of the Emoji character. + Extension of Character to check the existance of the Emoji character. */ extension Character { - + // An emoji can either be a 2 byte unicode character or a normal UTF8 character with an emoji modifier // appended as is the case with 3️⃣. 0x238C is the first instance of UTF16 emoji that requires no modifier. // `isEmoji` will evaluate to true for any character that can be turned into an emoji by adding a modifier @@ -47,5 +47,5 @@ extension Character { guard let scalar = unicodeScalars.first else { return false } return scalar.properties.isEmoji && (scalar.value > 0x238C || unicodeScalars.count > 1) } - + } diff --git a/OTFMagicBox/Library/Extension/Extension+Date.swift b/OTFMagicBox/Library/Extension/Extension+Date.swift index 3bb83b55..390a1134 100644 --- a/OTFMagicBox/Library/Extension/Extension+Date.swift +++ b/OTFMagicBox/Library/Extension/Extension+Date.swift @@ -1,41 +1,41 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation extension Date { - + var toString: String { // Create Date Formatter let dateFormatter = DateFormatter() diff --git a/OTFMagicBox/Library/Extension/Extension+Font.swift b/OTFMagicBox/Library/Extension/Extension+Font.swift index 1e219b8d..fd8f300d 100644 --- a/OTFMagicBox/Library/Extension/Extension+Font.swift +++ b/OTFMagicBox/Library/Extension/Extension+Font.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI @@ -42,39 +42,38 @@ extension Font { static var basicFontStyle: Font { let fontSize: CGFloat = 20.0 - guard let fontName = YmlReader().appTheme?.screenTitleFont, - fontExists(fontName, size: fontSize) else { + let fontName = YmlReader().appStyle.screenTitleFont + guard fontExists(YmlReader().appStyle.screenTitleFont, size: fontSize) else { return (.system(size: fontSize)) } return Font.custom(fontName, size: fontSize) } - + static var subHeaderFontStyle: Font { let fontSize: CGFloat = 20.0 - guard let fontName = YmlReader().appTheme?.screenTitleFont, - fontExists(fontName, size: fontSize) else { + let fontName = YmlReader().appStyle.screenTitleFont + guard fontExists(fontName, size: fontSize) else { return (.system(size: fontSize)) } return Font.custom(fontName, size: fontSize) } - + static var headerFontStyle: Font { let fontSize: CGFloat = 24.0 - guard let fontName = YmlReader().appTheme?.screenTitleFont, - fontExists(fontName, size: fontSize) else { + let fontName = YmlReader().appStyle.screenTitleFont + guard fontExists(fontName, size: fontSize) else { return (.system(size: fontSize)) } return Font.custom(fontName, size: fontSize) } - + static var titleFontStyle: Font { let fontSize: CGFloat = 35.0 - guard let fontName = YmlReader().appTheme?.screenTitleFont, - fontExists(fontName, size: fontSize) else { + let fontName = YmlReader().appStyle.screenTitleFont + guard fontExists(fontName, size: fontSize) else { return (.system(size: fontSize)) } return Font.custom(fontName, size: fontSize) } } - diff --git a/OTFMagicBox/Library/Extension/Extension+Image.swift b/OTFMagicBox/Library/Extension/Extension+Image.swift index 1e76d65a..3c5a9dcd 100644 --- a/OTFMagicBox/Library/Extension/Extension+Image.swift +++ b/OTFMagicBox/Library/Extension/Extension+Image.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI @@ -38,7 +38,7 @@ extension Image { static var theraforgeLogo: Image { UIImage.loadImage(named: "TheraforgeLogo") } - + static var avatar: Image { UIImage.loadImage(named: "user_profile") } diff --git a/OTFMagicBox/Library/Extension/Extension+OCKAnyTask.swift b/OTFMagicBox/Library/Extension/Extension+OCKAnyTask.swift index 26f12d38..3c7baab3 100644 --- a/OTFMagicBox/Library/Extension/Extension+OCKAnyTask.swift +++ b/OTFMagicBox/Library/Extension/Extension+OCKAnyTask.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -46,11 +46,11 @@ extension OCKAnyTask { let keys = try? JSONDecoder().decode(GroupIdentifierKeys.self, from: data) return keys ?? GroupIdentifierKeys() } - + var category: TaskCategory { return groupIdentifierKeys.category } - + var viewType: TaskStyle { return groupIdentifierKeys.viewType } @@ -60,12 +60,12 @@ extension Collection where Element == OCKEvent { func getTasksAndEventsOf(category: TaskCategory, for interval: DateInterval) -> [TaskEvents] { let categoryTaskEvents = filter({ $0.task.category == category }) let categoryTasks = categoryTaskEvents.map({ $0.task }) - + let tasksAndEvents = categoryTasks.map { task -> TaskEvents in let eventsOfTask = categoryTaskEvents.filter({ $0.task.id == task.id }) return TaskEvents(interval: interval, events: eventsOfTask) } - + return tasksAndEvents } } diff --git a/OTFMagicBox/Library/Extension/Extension+String.swift b/OTFMagicBox/Library/Extension/Extension+String.swift index d2146cca..e7b26e85 100644 --- a/OTFMagicBox/Library/Extension/Extension+String.swift +++ b/OTFMagicBox/Library/Extension/Extension+String.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -40,10 +40,10 @@ import SwiftUI Extension of String to check the Emoji string. */ extension String { - + // Returns true if the given string contains Emoji. var containsEmojis: Bool { - if count == 0 { + if isEmpty { return false } for character in self where character.isEmoji { @@ -51,8 +51,7 @@ extension String { } return false } - - // swiftlint:disable all + var color: UIColor? { switch self { case "Red": @@ -159,9 +158,9 @@ extension String { return nil } } - + var fontWeight: Font.Weight? { - + switch self { case "Thin": return Font.Weight.thin @@ -185,10 +184,8 @@ extension String { return nil } } - - var appFont: Font? { - + switch self { case "Basic": return Font.basicFontStyle @@ -228,7 +225,7 @@ extension String { return nil } } - + var isValidEmail: Bool { NSPredicate(format: "SELF MATCHES %@", "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}").evaluate(with: self) } diff --git a/OTFMagicBox/Library/Extension/Extension+UIImage.swift b/OTFMagicBox/Library/Extension/Extension+UIImage.swift index 1802d003..bedbef34 100644 --- a/OTFMagicBox/Library/Extension/Extension+UIImage.swift +++ b/OTFMagicBox/Library/Extension/Extension+UIImage.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -37,45 +37,45 @@ import UIKit import SwiftUI /** - Extension of UIImage to load the Image depending on its image type. + Extension of UIImage to load the Image depending on its image type. */ extension UIImage { // Checks whether the given image is a SF symbol, if not returns it as a normal image. /** Checks whether the given image is a SF symbol, if not returns it as a normal image. - - Remark:- Use this method to display any of the images in your application. This method supports all kind of images like SF Symbols or any images saved from Assets. + + Remark:- Use this method to display any of the images in your application. This method supports all kind of images like SF Symbols or any images saved from Assets. */ static func loadImage(named: String) -> Image { - if let sfImage = UIImage(systemName: named){ + if let sfImage = UIImage(systemName: named) { return Image(uiImage: sfImage) } return Image(named) } - + func crop(to size: CGSize) -> UIImage? { guard let cgImage = self.cgImage else { return nil } - + let widthRatio = size.width / CGFloat(cgImage.width) let heightRatio = size.height / CGFloat(cgImage.height) let scale = max(widthRatio, heightRatio) - + let scaledWidth = CGFloat(cgImage.width) * scale let scaledHeight = CGFloat(cgImage.height) * scale - + let xOffset = (scaledWidth - size.width) / 2 let yOffset = (scaledHeight - size.height) / 2 - + let targetRect = CGRect(x: -xOffset, y: -yOffset, width: scaledWidth, height: scaledHeight) - + UIGraphicsBeginImageContextWithOptions(size, false, self.scale) draw(in: targetRect) let croppedAndFilledImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() - + return croppedAndFilledImage } } diff --git a/OTFMagicBox/Library/Extension/Extension+URLRequest.swift b/OTFMagicBox/Library/Extension/Extension+URLRequest.swift index 22dfeb61..8cff40d5 100644 --- a/OTFMagicBox/Library/Extension/Extension+URLRequest.swift +++ b/OTFMagicBox/Library/Extension/Extension+URLRequest.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -43,9 +43,9 @@ public extension URLRequest { guard let url = url, let httpMethod = httpMethod, - url.absoluteString.utf8.count > 0 + !url.absoluteString.utf8.isEmpty else { - return "" + return "" } var curlCommand = "curl --verbose \\\n" @@ -54,7 +54,7 @@ public extension URLRequest { curlCommand = curlCommand.appendingFormat(" '%@' \\\n", url.absoluteString) // Method if different from GET - if "GET" != httpMethod { + if httpMethod != "GET" { curlCommand = curlCommand.appendingFormat(" -X %@ \\\n", httpMethod) } @@ -67,7 +67,7 @@ public extension URLRequest { } // HTTP body - if let httpBody = httpBody, httpBody.count > 0 { + if let httpBody = httpBody, !httpBody.isEmpty { let httpBodyString = String(data: httpBody, encoding: String.Encoding.utf8)! let escapedHttpBody = URLRequest.escapeAllSingleQuotes(httpBodyString) curlCommand = curlCommand.appendingFormat(" --data '%@' \\\n", escapedHttpBody) diff --git a/OTFMagicBox/Library/Extension/Extention+Notification.swift b/OTFMagicBox/Library/Extension/Extention+Notification.swift index 48a34f8b..e979a4a3 100644 --- a/OTFMagicBox/Library/Extension/Extention+Notification.swift +++ b/OTFMagicBox/Library/Extension/Extention+Notification.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -38,6 +38,7 @@ extension NSNotification.Name { static let onboardingDidComplete = NSNotification.Name(Constants.onboardingDidComplete) static let dataSyncRequest = NSNotification.Name(rawValue: Constants.Notification.DataSyncRequest) static let databaseSuccessfllySynchronized = NSNotification.Name(rawValue: Constants.Notification.DatabaseSynchronizedSuccessfully) + static let databaseSync = NSNotification.Name("databaseSync") static let imageUploaded = NSNotification.Name(rawValue: Constants.Notification.ImageUploadedSuccessfully) static let imageDownloaded = NSNotification.Name(rawValue: Constants.Notification.ImageDownloadedSuccessfully) static let deleteUserAccount = Notification.Name(rawValue: Constants.Notification.deleteUserAccount) diff --git a/OTFMagicBox/Library/Extension/Extention+ViewController.swift b/OTFMagicBox/Library/Extension/Extention+ViewController.swift index 5fc81d4c..0ddc10ed 100644 --- a/OTFMagicBox/Library/Extension/Extention+ViewController.swift +++ b/OTFMagicBox/Library/Extension/Extention+ViewController.swift @@ -15,12 +15,12 @@ extension UIViewController { self.present(alert, animated: true, completion: nil) } } - - func alertWithAction(title: String , message: String, completionYes: @escaping ((UIAlertAction) -> Void)) { + + func alertWithAction(title: String, message: String, completionYes: @escaping ((UIAlertAction) -> Void)) { let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) let okayAction = UIAlertAction(title: "Okay", style: .default, handler: completionYes) alertController.addAction(okayAction) self.present(alertController, animated: true, completion: nil) } - -} \ No newline at end of file + +} diff --git a/OTFMagicBox/Library/Extension/OCKHealthKitStore+Extension.swift b/OTFMagicBox/Library/Extension/OCKHealthKitStore+Extension.swift index 1b5ae4a3..ad8c9add 100644 --- a/OTFMagicBox/Library/Extension/OCKHealthKitStore+Extension.swift +++ b/OTFMagicBox/Library/Extension/OCKHealthKitStore+Extension.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -38,11 +38,11 @@ import Foundation import OTFUtilities extension OCKHealthKitPassthroughStore { - + enum Tasks: String, CaseIterable { case steps } - + func fillWithDummyData() { // Note: If the tasks and contacts already exist in the store, these methods will fail. If you have modified the data and would like the // changes to be reflected in the app, delete and reinstall the catalog app. @@ -55,7 +55,7 @@ extension OCKHealthKitPassthroughStore { } } } - + private func makeTasks(on start: Date) -> [OCKAnyTask] { // Steps task let stepsScheduleElement = OCKScheduleElement(start: start, end: nil, interval: .init(day: 1), @@ -64,7 +64,7 @@ extension OCKHealthKitPassthroughStore { var stepsTask = OCKHealthKitTask(id: Tasks.steps.rawValue, title: "Steps", carePlanUUID: nil, schedule: .init(composing: [stepsScheduleElement]), healthKitLinkage: hkLinkage) stepsTask.instructions = "A walk a day keeps the doctor away." - + return [stepsTask] } } diff --git a/OTFMagicBox/Library/HealthKitManager.swift b/OTFMagicBox/Library/HealthKitManager.swift index 5d278c29..e7086216 100644 --- a/OTFMagicBox/Library/HealthKitManager.swift +++ b/OTFMagicBox/Library/HealthKitManager.swift @@ -1,41 +1,41 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import HealthKit import OTFUtilities -@objc protocol SyncDelegate : AnyObject { +@objc protocol SyncDelegate: AnyObject { @objc optional func didSyncWalkTests() @objc optional func didSyncSurveys() @objc optional func didSyncEvents() @@ -43,48 +43,47 @@ import OTFUtilities } class HealthKitManager: SyncDelegate { - + static let shared = HealthKitManager() - + lazy var healthStore: HKHealthStore = HKHealthStore() - - fileprivate var queryLog = [String:Date]() + + fileprivate var queryLog = [String: Date]() fileprivate let queryLogMutex = NSLock() - fileprivate let timeBetweenQueries: TimeInterval = 60 //in seconds - - var userAuthorizedHKOnDevice : Bool? { + fileprivate let timeBetweenQueries: TimeInterval = 60 // in seconds + + var userAuthorizedHKOnDevice: Bool? { get { return UserDefaults.standard.value(forKey: Constants.UserDefaults.HKDataShare) as? Bool } set(newValue) { UserDefaults.standard.set(newValue, forKey: Constants.UserDefaults.HKDataShare) - // CKSession.putSecure(value: String(newValue ?? false), forKey: Constants.UserDefaults.HKDataShare) + // CKSession.putSecure(value: String(newValue ?? false), forKey: Constants.UserDefaults.HKDataShare) } } - + init() { NotificationCenter.default.addObserver(self, selector: #selector(HealthKitManager.syncData), name: .dataSyncRequest, object: nil) } - + deinit { NotificationCenter.default.removeObserver(self, name: .dataSyncRequest, object: nil) } - + public func getHealthKitAuth(forTypes types: Set, _ completion: @escaping (_ success: Bool, _ error: NSError?) -> Void) { - healthStore.requestAuthorization(toShare: nil, read: types) { - [weak self] success, error in - + healthStore.requestAuthorization(toShare: nil, read: types) { [weak self] success, error in + guard let strongSelf = self else { return } strongSelf.userAuthorizedHKOnDevice = success - + completion(success, error as NSError?) } } - + public func startBackgroundDelivery(forTypes types: Set, withFrequency frequency: HKUpdateFrequency, _ completion: ((_ success: Bool, _ error: Error?) -> Void)? = nil) { self.setUpBackgroundDeliveryForDataTypes(types: types, frequency: frequency, completion) } - + public func disableHealthKit(_ completion: ((_ success: Bool, _ error: Error?) -> Void)? = nil) { healthStore.disableAllBackgroundDelivery { (success, error) in if let error = error { @@ -93,31 +92,31 @@ class HealthKitManager: SyncDelegate { completion?(success, error) } } - + } extension HealthKitManager { - + fileprivate func setUpBackgroundDeliveryForDataTypes(types: Set, frequency: HKUpdateFrequency, _ completion: ((_ success: Bool, _ error: Error?) -> Void)? = nil) { let dispatchGroup = DispatchGroup() - + for type in types { - let query = HKObserverQuery(sampleType: type, predicate: nil, updateHandler: { [weak self] (query, completionHandler, error) in - + let query = HKObserverQuery(sampleType: type, predicate: nil, updateHandler: { [weak self] (_, completionHandler, _) in + guard let strongSelf = self else { completionHandler() return } - + dispatchGroup.enter() strongSelf.backgroundQuery(forType: type, completionHandler: { completionHandler() dispatchGroup.leave() }) - + }) - + healthStore.execute(query) healthStore.enableBackgroundDelivery(for: type, frequency: frequency, withCompletion: { (success, error) in if let error = error { @@ -125,76 +124,74 @@ extension HealthKitManager { } completion?(success, error) }) - + } - + dispatchGroup.notify(queue: .main) { OTFLog("Task finished.") } } - - //TODO: (delete) running the old data collection solution as a baseline to compare new values + @available(*, deprecated) - fileprivate func cumulativeBackgroundQuery(forType type: HKQuantityType, completionHandler: @escaping ()->Void) { - + fileprivate func cumulativeBackgroundQuery(forType type: HKQuantityType, completionHandler: @escaping () -> Void) { + let supportedTypes = [HKQuantityTypeIdentifier.stepCount.rawValue, HKQuantityTypeIdentifier.flightsClimbed.rawValue, HKQuantityTypeIdentifier.distanceWalkingRunning.rawValue] - if (!supportedTypes.contains(type.identifier)) { + if !supportedTypes.contains(type.identifier) { OTFLog("No cumulative query will run for type %@", type.identifier) completionHandler() return } - + guard canQuery(forType: type) else { OTFLog("Cannot yet query for %@, please try again in a minute.", type.identifier) completionHandler() return } - DispatchQueue.main.async { //run on main queue, which exists even if the app is 100% in the background. - + DispatchQueue.main.async { // run on main queue, which exists even if the app is 100% in the background. + OTFLog("[DEPRECATED] cumulative querying for type %@", type.identifier) - + } - + } - - fileprivate func backgroundQuery(forType type: HKQuantityType, completionHandler: @escaping ()->Void) { - + + fileprivate func backgroundQuery(forType type: HKQuantityType, completionHandler: @escaping () -> Void) { + guard canQuery(forType: type) else { OTFLog("Cannot yet query for %{public}@, please try again in a minute.", type.identifier) completionHandler() return } - - DispatchQueue.main.async { //run on main queue, which exists even if the app is 100% in the background. - + + DispatchQueue.main.async { // run on main queue, which exists even if the app is 100% in the background. + OTFLog("Querying for type %{public}@", type.identifier) - + } - + } fileprivate func canQuery(forType type: HKQuantityType) -> Bool { queryLogMutex.lock() defer { queryLogMutex.unlock() } - + let currentDate = Date() guard let lastQueryDate = queryLog[type.identifier] else { queryLog[type.identifier] = currentDate return true } - + if currentDate.addingTimeInterval(-timeBetweenQueries) >= lastQueryDate { queryLog[type.identifier] = currentDate return true } - + return false } - + @objc fileprivate func syncData(forHkTypes hkTypes: Set) { - + } - -} +} diff --git a/OTFMagicBox/Library/HealthRecordManager.swift b/OTFMagicBox/Library/HealthRecordManager.swift index ef4a6e12..b6df28b7 100644 --- a/OTFMagicBox/Library/HealthRecordManager.swift +++ b/OTFMagicBox/Library/HealthRecordManager.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -39,11 +39,11 @@ import OTFCareKitStore import OTFUtilities class HealthRecordsManager: NSObject { - + static let shared = HealthRecordsManager() - + lazy var healthStore = HKHealthStore() - + fileprivate let typesById: [HKClinicalTypeIdentifier] = [ .allergyRecord, // HKClinicalTypeIdentifierAllergyRecord .conditionRecord, // HKClinicalTypeIdentifierConditionRecord @@ -53,9 +53,9 @@ class HealthRecordsManager: NSObject { .procedureRecord, // HKClinicalTypeIdentifierProcedureRecord .vitalSignRecord // HKClinicalTypeIdentifierVitalSignRecord ] - + fileprivate var types = Set() - + override init() { super.init() for id in typesById { @@ -63,17 +63,17 @@ class HealthRecordsManager: NSObject { types.insert(record) } } - + func getAuth(_ completion: @escaping (_ success: Bool, _ error: Error?) -> Void) { healthStore.requestAuthorization(toShare: nil, read: types) { (success, error) in completion(success, error) } } - + func upload(_ onCompletion: ((Bool, Error?) -> Void)? = nil) { for type in types { - let query = HKSampleQuery(sampleType: type, predicate: nil, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (query, samples, error) in - + let query = HKSampleQuery(sampleType: type, predicate: nil, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (_, samples, error) in + guard let samples = samples as? [HKClinicalRecord] else { OTFError("An error occurred in uploading health record: %{public}@", error?.localizedDescription ?? "") onCompletion?(false, error) @@ -82,16 +82,15 @@ class HealthRecordsManager: NSObject { OTFLog("[HealthRecordsManager] upload() - sending %{public}@ sample(s)", samples.count) for sample in samples { guard let resource = sample.fhirResource else { continue } - _ = resource.data - _ = resource.resourceType.rawValue + "-" + resource.identifier + _ = resource.data + _ = resource.resourceType.rawValue + "-" + resource.identifier } - + UserDefaults.standard.set(Date(), forKey: Constants.prefHealthRecordsLastUploaded) onCompletion?(true, nil) } healthStore.execute(query) } } - -} +} diff --git a/OTFMagicBox/Library/KeychainCloudManager.swift b/OTFMagicBox/Library/KeychainCloudManager.swift index 444f6a27..fa9dcd8e 100644 --- a/OTFMagicBox/Library/KeychainCloudManager.swift +++ b/OTFMagicBox/Library/KeychainCloudManager.swift @@ -1,74 +1,83 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation import OTFUtilities import Sodium -class KeychainCloudManager { +enum KeychainCloudManager { static var getEmailAddress: String { let email = SwiftSodium().loadKey(keychainKey: KeychainKeys.emailKey) return String(decoding: email, as: UTF8.self) } - + static var getPassword: String { let password = SwiftSodium().loadKey(keychainKey: KeychainKeys.passwordKey) return String(decoding: password, as: UTF8.self) } - + static var getMasterKey: Bytes { let swiftSodium = SwiftSodium() let masterKey = swiftSodium.loadKey(keychainKey: KeychainKeys.masterKey) - return swiftSodium.getArrayOfBytesFromData(FileData: masterKey as NSData) + return swiftSodium.getArrayOfBytesFromData(fileData: masterKey as NSData) } - + static var getDefaultStorageKey: Bytes { let swiftSodium = SwiftSodium() let defaultStorageKey = swiftSodium.loadKey(keychainKey: KeychainKeys.defaultStorageKey) - return swiftSodium.getArrayOfBytesFromData(FileData: defaultStorageKey as NSData) + return swiftSodium.getArrayOfBytesFromData(fileData: defaultStorageKey as NSData) } - + static var getConfidentialStorageKey: Bytes { let swiftSodium = SwiftSodium() let confidentialStorageKey = swiftSodium.loadKey(keychainKey: KeychainKeys.confidentialStorageKey) - return swiftSodium.getArrayOfBytesFromData(FileData: confidentialStorageKey as NSData) + return swiftSodium.getArrayOfBytesFromData(fileData: confidentialStorageKey as NSData) } - - static func saveValuesInKeychain(email: String, password: String, masterKey: Bytes, publicKey: Bytes, secretKey: Bytes, defaultStorageKey: Bytes, confidentialStorageKey: Bytes) { + + static func saveUserCredentialsInKeychain(email: String, password: String) { let swiftSodium = SwiftSodium() swiftSodium.saveStringValue(key: email, keychainKey: KeychainKeys.emailKey) swiftSodium.saveStringValue(key: password, keychainKey: KeychainKeys.passwordKey) + } + + static func isKeyStored(key: String) -> Bool { + let swiftSodium = SwiftSodium() + return swiftSodium.isKeyStored(keychainKey: key) + } + + static func saveUserKeys(masterKey: Bytes, publicKey: Bytes, secretKey: Bytes, defaultStorageKey: Bytes, confidentialStorageKey: Bytes) { + let swiftSodium = SwiftSodium() swiftSodium.saveKey(key: publicKey, keychainKey: KeychainKeys.publicKey) swiftSodium.saveKey(key: secretKey, keychainKey: KeychainKeys.secretKey) swiftSodium.saveKey(key: masterKey, keychainKey: KeychainKeys.masterKey) @@ -77,7 +86,7 @@ class KeychainCloudManager { } } -struct KeychainKeys { +enum KeychainKeys { static let secretKey = "secretKey" static let publicKey = "publicKey" static let passwordKey = "passwordKey" diff --git a/OTFMagicBox/Library/LoaderView.swift b/OTFMagicBox/Library/LoaderView.swift new file mode 100644 index 00000000..b40bd149 --- /dev/null +++ b/OTFMagicBox/Library/LoaderView.swift @@ -0,0 +1,55 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI + +struct LoaderView: View { + var tintColor: Color = .black + var scaleSize: CGFloat = 1.0 + + var body: some View { + ProgressView() + .scaleEffect(scaleSize, anchor: .center) + .progressViewStyle(CircularProgressViewStyle(tint: tintColor)) + } +} + +extension View { + @ViewBuilder func hidden(_ shouldHide: Bool) -> some View { + switch shouldHide { + case true: self.hidden() + case false: self + } + } +} diff --git a/OTFMagicBox/Library/LocalAuthentication.swift b/OTFMagicBox/Library/LocalAuthentication.swift index 5268545f..b7a4d8ab 100644 --- a/OTFMagicBox/Library/LocalAuthentication.swift +++ b/OTFMagicBox/Library/LocalAuthentication.swift @@ -1,79 +1,77 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation import LocalAuthentication - - open class LocalAuthentication: NSObject { - + public static let shared = LocalAuthentication() - - private override init() {} - + + override private init() {} + var laContext = LAContext() - + func canAuthenticate() -> Bool { var error: NSError? let hasTouchId = laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) return hasTouchId } - + func hasTouchId() -> Bool { if canAuthenticate() && laContext.biometryType == .touchID { return true } return false } - + func hasFaceId() -> Bool { if canAuthenticate() && laContext.biometryType == .faceID { return true } return false } - - typealias AuthCompletion = (Bool) -> () + + typealias AuthCompletion = (Bool) -> Void func authenticationWithTouchID(completion: @escaping AuthCompletion) { let localAuthenticationContext = LAContext() localAuthenticationContext.localizedFallbackTitle = "Please use your Passcode" var authorizationError: NSError? - + let reason = "Authentication required to access the secure data" - + if localAuthenticationContext.canEvaluatePolicy(.deviceOwnerAuthentication, error: &authorizationError) { - + localAuthenticationContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { success, evaluateError in if success { completion(success) diff --git a/OTFMagicBox/Library/Metrics.swift b/OTFMagicBox/Library/Metrics.swift index 481c68b1..44571253 100644 --- a/OTFMagicBox/Library/Metrics.swift +++ b/OTFMagicBox/Library/Metrics.swift @@ -1,94 +1,94 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import UIKit -class Metrics { - -/// used for button padding +enum Metrics { + + /// used for button padding static let PADDING_HORIZONTAL_BUTTON: CGFloat = 15 static let PADDING_VERTICAL_BUTTON: CGFloat = 15 - -/// used for button text padding + + /// used for button text padding static let PADDING_BUTTON_LABEL: CGFloat = 15 - -/// used for button corner radius + + /// used for button corner radius static let RADIUS_CORNER_BUTTON: CGFloat = 4 - -/// used for row padding + + /// used for row padding static let PADDING_VERTICAL_ROW: CGFloat = 10 - -/// used for row width + + /// used for row width static let FRAME_ROW_WIDTH: CGFloat = 30 - -/// used for row height + + /// used for row height static let FRAME_ROW_HEIGHT: CGFloat = 30 - -/// used for HelpView and Passcode view height + + /// used for HelpView and Passcode view height static let MAIN_VIEW_HEIGHT: CGFloat = 70 - -/// used for title height + + /// used for title height static let TITLE_VIEW_HEIGHT: CGFloat = 60 - -/// used for image view height + + /// used for image view height static let IMAGE_VIEW_HEIGHT: CGFloat = 72 - -/// used for image view width + + /// used for image view width static let IMAGE_VIEW_WIDTH: CGFloat = 72 - -/// used for profile main view height + + /// used for profile main view height static let PROFILE_MAIN_VIEW_HEIGHT: CGFloat = 80 - -/// used for profile image view view height + + /// used for profile image view view height static let PROFILE_IMAGE_HEIGHT: CGFloat = 80 - -/// used for profile image view width + + /// used for profile image view width static let PROFILE_IMAGE_WIDTH: CGFloat = 80 - -/// used for task item height + + /// used for task item height static let TASK_ITEM_HEIGHT: CGFloat = 32 - -/// used for task item width + + /// used for task item width static let TASK_ITEM_WIDTH: CGFloat = 32 - -/// used for main task view height + + /// used for main task view height static let TASK_VIEW_HEIGHT: CGFloat = 65 - + static let BOTTOM_SPACER: CGFloat = 20 - + static let NETWORK_INDICATOR_WIDTH: CGFloat = 30 - + static let NETWORK_INDICATOR_ACCESSORY_WIDTH: CGFloat = 15 - + } diff --git a/OTFMagicBox/Library/OTFColor.swift b/OTFMagicBox/Library/OTFColor.swift index 9e283958..45beb8b0 100644 --- a/OTFMagicBox/Library/OTFColor.swift +++ b/OTFMagicBox/Library/OTFColor.swift @@ -9,31 +9,47 @@ import SwiftUI extension Color { static var otfTextColor: Color { - if let uiColor = YmlReader().appTheme?.textColor.color { + if let uiColor = YmlReader().appStyle.textColor.color { return Color(uiColor) } else { return Color(UIColor.label) } } - + static var otfHeaderColor: Color { - if let uiColor = YmlReader().appTheme?.headerColor.color { + if let uiColor = YmlReader().appStyle.headerColor.color { return Color(uiColor) } else { return Color(UIColor.secondaryLabel) } } - + static var otfCellBackground: Color { - if let uiColor = YmlReader().appTheme?.cellbackgroundColor.color { + if let uiColor = YmlReader().appStyle.cellbackgroundColor.color { return Color(uiColor) } else { return Color(UIColor.systemBackground) } } - + static var otfButtonColor: Color { - if let uiColor = YmlReader().appTheme?.buttonTextColor.color { + if let uiColor = YmlReader().appStyle.buttonTextColor.color { + return Color(uiColor) + } else { + return Color(UIColor.black) + } + } + + static var otfborderColor : Color { + if let uiColor = YmlReader().appStyle.borderColor.color { + return Color(uiColor) + } else { + return Color(UIColor.black) + } + } + + static var otfseparatorColor : Color { + if let uiColor = YmlReader().appStyle.separatorColor.color { return Color(uiColor) } else { return Color(UIColor.black) diff --git a/OTFMagicBox/Library/OTFFont.swift b/OTFMagicBox/Library/OTFFont.swift new file mode 100644 index 00000000..55763632 --- /dev/null +++ b/OTFMagicBox/Library/OTFFont.swift @@ -0,0 +1,46 @@ +// +// OTFFont.swift +// OTFMagicBox +// +// Created by Waqas Khadim on 25/10/2023. +// + +import SwiftUI + +extension Font { + static var otfAppFont : Font { + if let font = YmlReader().appStyle.textFont.appFont { + return font + } else { + return Font.system(size: 17.0) + } + } + + static var otfFontWeight : Font.Weight? { + return YmlReader().appStyle.textWeight.fontWeight + } + + static var otfscreenTitleFont : Font { + if let font = YmlReader().appStyle.screenTitleFont.appFont { + return font + } else { + return Font.system(size: 17.0) + } + } + + static var otfscreenTitleFontWeight : Font.Weight? { + return YmlReader().appStyle.screenTitleFont.fontWeight + } + + static var otfheaderTitleFont : Font { + if let font = YmlReader().appStyle.headerTitleFont.appFont { + return font + } else { + return Font.system(size: 17.0) + } + } + + static var otfheaderTitleWeight : Font.Weight? { + return YmlReader().appStyle.headerTitleWeight.fontWeight + } +} diff --git a/OTFMagicBox/Library/OTFHealthKitManager.swift b/OTFMagicBox/Library/OTFHealthKitManager.swift index d19aafad..9d378b4d 100644 --- a/OTFMagicBox/Library/OTFHealthKitManager.swift +++ b/OTFMagicBox/Library/OTFHealthKitManager.swift @@ -1,47 +1,47 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation import HealthKit -class OTFHealthKitManager : NSObject { - +class OTFHealthKitManager: NSObject { + public static let shared = OTFHealthKitManager() - + fileprivate var hkTypesToReadInBackground: Set = [] - - private override init() { + + override private init() { let healthKitData = ModuleAppYmlReader().healthKitDataToRead as Array for requestedHKType in healthKitData { let id = HKQuantityTypeIdentifier(rawValue: "HKQuantityTypeIdentifier" + requestedHKType.type) @@ -49,7 +49,7 @@ class OTFHealthKitManager : NSObject { hkTypesToReadInBackground.insert(hkType!) } } - + /// Query for HealthKit Authorization /// - Parameter completion: (success, error) func getHealthAuthorization(_ completion: @escaping (_ success: Bool, _ error: Error?) -> Void) { @@ -58,10 +58,10 @@ class OTFHealthKitManager : NSObject { * in the background. Choose from any HKQuantityType: * https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier * *************************************************************/ - + // handle authorization from the OS ActivityManager.shared.getHealthAuthorizaton(forTypes: hkTypesToReadInBackground) { (success, error) in - if (success) { + if success { let frequency = ModuleAppYmlReader().backgroundReadFrequency if frequency == HKUpdateFrequency.daily.stringValue { @@ -78,20 +78,18 @@ class OTFHealthKitManager : NSObject { } } } - - extension HKUpdateFrequency { var stringValue: String { switch self { case .hourly: return "hourly" - + case .daily: return "daily" - + case .weekly: return "weekly" - + default: return "immediate" } diff --git a/OTFMagicBox/Library/UIColor.swift b/OTFMagicBox/Library/UIColor.swift index c08a77a2..81cb3e6d 100644 --- a/OTFMagicBox/Library/UIColor.swift +++ b/OTFMagicBox/Library/UIColor.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -37,33 +37,29 @@ import UIKit import SwiftUI extension UIColor { - var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { var red: CGFloat = 0 var green: CGFloat = 0 var blue: CGFloat = 0 var alpha: CGFloat = 0 getRed(&red, green: &green, blue: &blue, alpha: &alpha) - return (red, green, blue, alpha) } - /// Returns UIcolor for a given type of hex color. func getColor(colorValue: String) -> UIColor { let hex = colorValue - var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() - - if (cString.hasPrefix("#")) { + var cString: String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() + + if cString.hasPrefix("#") { cString.remove(at: cString.startIndex) } - - if ((cString.count) != 6) { + if (cString.count) != 6 { return UIColor.gray } - - var rgbValue:UInt64 = 0 + + var rgbValue: UInt64 = 0 Scanner(string: cString).scanHexInt64(&rgbValue) - + return UIColor( red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, @@ -72,12 +68,10 @@ extension UIColor { ) } } - - public extension Color { - + private typealias PlatformColor = UIColor - + static var systemBlue: Color { Color(PlatformColor.systemBlue) } static var systemBrown: Color { Color(PlatformColor.systemBrown) } @available(iOS 15.0, macOS 12.0, tvOS 15.0, *) @@ -92,27 +86,27 @@ public extension Color { static var systemRed: Color { Color(PlatformColor.systemRed) } static var systemTeal: Color { Color(PlatformColor.systemTeal) } static var systemYellow: Color { Color(PlatformColor.systemYellow) } - + static var systemGray2: Color { Color(PlatformColor.systemGray2) } static var systemGray3: Color { Color(PlatformColor.systemGray3) } static var systemGray4: Color { Color(PlatformColor.systemGray4) } static var systemGray5: Color { Color(PlatformColor.systemGray5) } static var systemGray6: Color { Color(PlatformColor.systemGray6) } - + static var darkGray: Color { Color(PlatformColor.darkGray) } static var lightGray: Color { Color(PlatformColor.lightGray) } static var magenta: Color { Color(PlatformColor.magenta) } - + static var systemFill: Color { Color(PlatformColor.systemFill) } static var secondarySystemFill: Color { Color(PlatformColor.secondarySystemFill) } static var tertiarySystemFill: Color { Color(PlatformColor.tertiarySystemFill) } static var quaternarySystemFill: Color { Color(PlatformColor.quaternarySystemFill) } - + static var placeholderText: Color { Color(PlatformColor.placeholderText) } static var systemBackground: Color { Color(PlatformColor.systemBackground) } static var secondarySystemBackground: Color { Color(PlatformColor.secondarySystemBackground) } static var tertiarySystemBackground: Color { Color(PlatformColor.tertiarySystemBackground) } - + static var systemGroupedBackground: Color { Color(PlatformColor.systemGroupedBackground) } static var secondarySystemGroupedBackground: Color { Color(PlatformColor.secondarySystemGroupedBackground) } static var tertiarySystemGroupedBackground: Color { Color(PlatformColor.tertiarySystemGroupedBackground) } diff --git a/OTFMagicBox/Library/UploadDocumentManager.swift b/OTFMagicBox/Library/UploadDocumentManager.swift index 4555d21c..869f4d34 100644 --- a/OTFMagicBox/Library/UploadDocumentManager.swift +++ b/OTFMagicBox/Library/UploadDocumentManager.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -38,14 +38,14 @@ import OTFUtilities import Sodium final class UploadDocumentManager { - + private var disposables = Set() let swiftSodium = SwiftSodium() - + func encryptDocument(document: Data, fileName: String) { - let bytesImage = swiftSodium.getArrayOfBytesFromData(FileData: document as NSData) + let bytesImage = swiftSodium.getArrayOfBytesFromData(fileData: document as NSData) let defaultStorageKey = KeychainCloudManager.getDefaultStorageKey - + let fileKeyPushStream = swiftSodium.getPushStream(secretKey: defaultStorageKey)! let fileKey = swiftSodium.generateDeriveKey(key: defaultStorageKey) let eFileKey = swiftSodium.encryptFile(pushStream: fileKeyPushStream, fileBytes: fileKey) @@ -53,42 +53,38 @@ final class UploadDocumentManager { return element }) let encryptedFileKeyHex = encryptedFileKey.bytesToHex(spacing: "").lowercased() - + let documentPushStream = swiftSodium.getPushStream(secretKey: fileKey)! let fileencryption = swiftSodium.encryptFile(pushStream: documentPushStream, fileBytes: bytesImage) let newFile = [documentPushStream.header(), fileencryption].flatMap({ (element: [UInt8]) -> [UInt8] in return element }) - + let hashKeyFile = swiftSodium.generateGenericHashWithKey(message: newFile, fileKey: fileKey) let hashKeyFileHex = hashKeyFile.bytesToHex(spacing: "").lowercased() let encryptedFileData = Data(newFile) - + uploadFile(data: encryptedFileData, fileName: fileName, encryptedFileKey: encryptedFileKeyHex, hashFileKey: hashKeyFileHex) } - func decryptedFile(file: Data, hashFileKey: String) -> Data { - let dataToBytes = swiftSodium.getArrayOfBytesFromData(FileData: file as NSData) + let dataToBytes = swiftSodium.getArrayOfBytesFromData(fileData: file as NSData) let defaultStorageKey = KeychainCloudManager.getDefaultStorageKey let fileKey = swiftSodium.generateDeriveKey(key: defaultStorageKey) - + let hashKey = swiftSodium.generateGenericHashWithKey(message: dataToBytes, fileKey: fileKey) let hashKeyHex = hashKey.bytesToHex(spacing: "").lowercased() - + if hashKeyHex.contains(hashFileKey) { let (header, encryptedFile) = dataToBytes.splitFile() let encryption = swiftSodium.decryptFile(secretKey: fileKey, header: header, encryptedFile: encryptedFile) guard let (file, _) = encryption else { return Data() } let decryptedFile = Data(file) return decryptedFile - } else { - - } + } return Data() - } - + func uploadFile(data: Data, fileName: String, encryptedFileKey: String, hashFileKey: String) { OTFTheraforgeNetwork.shared.uploadFile(data: data, fileName: fileName, type: .consentForm, encryptedFileKey: encryptedFileKey, hashFileKey: hashFileKey) .receive(on: DispatchQueue.main) diff --git a/OTFMagicBox/Library/UserDefaultsManager.swift b/OTFMagicBox/Library/UserDefaultsManager.swift index cf7210e9..bd9970bb 100644 --- a/OTFMagicBox/Library/UserDefaultsManager.swift +++ b/OTFMagicBox/Library/UserDefaultsManager.swift @@ -1,54 +1,53 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation -class UserDefaultsManager { +enum UserDefaultsManager { static var onboardingDidComplete: Bool { return UserDefaults.standard.bool(forKey: Constants.onboardingDidComplete) } - + static func setOnboardingCompleted(_ completed: Bool) { UserDefaults.standard.setValue(completed, forKey: Constants.onboardingDidComplete) } - + static func setIsConsentDocumentViewed(_ completed: Bool) { UserDefaults.standard.setValue(completed, forKey: Constants.isConsentDocumentViewed) } - + static var isConsentDocumentViewed: Bool { return UserDefaults.standard.bool(forKey: Constants.isConsentDocumentViewed) } - } diff --git a/OTFMagicBox/Library/Yaml/DataModel.swift b/OTFMagicBox/Library/Yaml/DataModel.swift index 3b9e3887..e05eb53a 100644 --- a/OTFMagicBox/Library/Yaml/DataModel.swift +++ b/OTFMagicBox/Library/Yaml/DataModel.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -41,7 +41,7 @@ struct Login: Codable { let failedLoginTitle: String let failedLoginText: String } - + struct Passcode: Codable { let enable: String let passcodeOnReturnText: String @@ -54,7 +54,7 @@ struct DesignConfig: Codable { let textValue: String } -struct DefaultConfig: Codable{ +struct DefaultConfig: Codable { let apiKey: String let en: DataModel let fr: DataModel @@ -67,7 +67,8 @@ struct DefaultConfig: Codable{ let showCheckupScreen: String let showStaticUIScreen: String let useCareKit: String - let appTheme: ThemeCustomization + var selectedStyle: String + var styles: [ThemeCustomization] } struct DataModel: Codable { @@ -76,7 +77,10 @@ struct DataModel: Codable { let copyright: String } -struct ThemeCustomization: Codable{ +struct ThemeCustomization: Codable { + let name: String + + // Colors let backgroundColor: String let textColor: String let separatorColor: String @@ -84,6 +88,8 @@ struct ThemeCustomization: Codable{ let buttonTextColor: String let borderColor: String let headerColor: String + + // Font let textWeight: String let textFont: String let screenTitleFont: String diff --git a/OTFMagicBox/Library/Yaml/ModuleAppYmlReader+DataModel/ModuleAppYmlReader+DataModel.swift b/OTFMagicBox/Library/Yaml/ModuleAppYmlReader+DataModel/ModuleAppYmlReader+DataModel.swift index d130d34d..f346a467 100644 --- a/OTFMagicBox/Library/Yaml/ModuleAppYmlReader+DataModel/ModuleAppYmlReader+DataModel.swift +++ b/OTFMagicBox/Library/Yaml/ModuleAppYmlReader+DataModel/ModuleAppYmlReader+DataModel.swift @@ -1,9 +1,36 @@ -// -// ModuleAppYmlReader+DataModel.swift -// OTFMagicBox -// -// Created by Arsalan Raza on 17/05/2022. -// +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. + */ import Foundation import UIKit @@ -12,36 +39,28 @@ import Yams import OTFUtilities public class ModuleAppYmlReader { - /// Yaml file name. private let fileName = Constants.YamlDefaults.moduleAppFileName - - var onBoardingDataModel : OnBoardingScreen? - + var onBoardingDataModel: OnBoardingScreen? init() { let fileUrlString = Bundle.main.path(forResource: fileName, ofType: nil)! let fileUrl = URL(fileURLWithPath: fileUrlString) do { - if let dataSet = try? Data(contentsOf: fileUrl) { - guard let data = try? YAMLDecoder().decode([String: OnBoardingScreen].self, from: dataSet) else { - OTFLog("Yaml decode error") - return - } - if data["DataModel"] != nil { - onBoardingDataModel = data["DataModel"] - } - } + let dataSet = try Data(contentsOf: fileUrl) + let data = try YAMLDecoder().decode(ConfigDataModel.self, from: dataSet) + onBoardingDataModel = data.dataModel + } catch { + OTFLog("Error $public{%@}", error.localizedDescription) } } - func getPreferredLocale() -> Locale { guard let preferredIdentifier = Locale.preferredLanguages.first else { return Locale.current } return Locale(identifier: preferredIdentifier) } - + var onboardingData: [Onboarding]? { switch getPreferredLocale().languageCode { case "fr": @@ -51,314 +70,314 @@ public class ModuleAppYmlReader { } } - var primaryColor: UIColor { + var registration: Registration? { switch getPreferredLocale().languageCode { case "fr": - let valueSet = (onBoardingDataModel?.fr.onboarding ?? []) - for item in valueSet{ - return item.color.color ?? UIColor.black - } + return onBoardingDataModel?.fr.registration default: - let valueSet = (onBoardingDataModel?.en.onboarding ?? []) - for item in valueSet{ - return item.color.color ?? UIColor.black - } + return onBoardingDataModel?.en.registration } - return UIColor.black } - - var reasonForConsentText: String { + var showGender: Bool { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.consent.reasonForConsentText ?? Constants.YamlDefaults.TeamWebsite + guard let showGender = onBoardingDataModel?.fr.registration.showGender else { return false } + return showGender == Constants.true default: - return onBoardingDataModel?.en.consent.reasonForConsentText ?? Constants.YamlDefaults.TeamWebsite + guard let showGender = onBoardingDataModel?.en.registration.showGender else { return false } + return showGender == Constants.true } } - - var consentFileName: String { + var showDateOfBirth: Bool { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.consent.fileName ?? Constants.YamlDefaults.ConsentFileName + guard let showDOB = onBoardingDataModel?.fr.registration.showDateOfBirth else { return false } + return showDOB == Constants.true default: - return onBoardingDataModel?.en.consent.fileName ?? Constants.YamlDefaults.ConsentFileName + guard let showDOB = onBoardingDataModel?.en.registration.showDateOfBirth else { return false } + return showDOB == Constants.true } } - - var consentTitle: String? { + var completionStepTitle: String? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.consent.title ?? Constants.YamlDefaults.ConsentTitle + return onBoardingDataModel?.fr.completionStep.title ?? Constants.YamlDefaults.CompletionStepTitle default: - return onBoardingDataModel?.en.consent.title ?? Constants.YamlDefaults.ConsentTitle + return onBoardingDataModel?.en.completionStep.title ?? Constants.YamlDefaults.CompletionStepTitle } } - - var consent: Consent? { + var completionStepText: String? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.consent + return onBoardingDataModel?.fr.completionStep.text ?? Constants.YamlDefaults.CompletionStepText default: - return onBoardingDataModel?.en.consent + return onBoardingDataModel?.en.completionStep.text ?? Constants.YamlDefaults.CompletionStepText } } - var registration: Registration? { + var profileData: ProfileModel? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.registration + return onBoardingDataModel?.fr.profileDataModel default: - return onBoardingDataModel?.en.registration + return onBoardingDataModel?.en.profileDataModel } } - - var showGender: Bool { + var researchKitModel: ResearchKitModel? { switch getPreferredLocale().languageCode { case "fr": - guard let showGender = onBoardingDataModel?.fr.registration.showGender else { return false } - return showGender == Constants.true + return onBoardingDataModel?.fr.researchKitView default: - guard let showGender = onBoardingDataModel?.en.registration.showGender else { return false } - return showGender == Constants.true + return onBoardingDataModel?.en.researchKitView } } - - var showDateOfBirth: Bool { + var surverysTaskModel: SurverysTask? { switch getPreferredLocale().languageCode { case "fr": - guard let showDOB = onBoardingDataModel?.fr.registration.showDateOfBirth else { return false } - return showDOB == Constants.true + return onBoardingDataModel?.fr.surverysTask default: - guard let showDOB = onBoardingDataModel?.en.registration.showDateOfBirth else { return false } - return showDOB == Constants.true + return onBoardingDataModel?.en.surverysTask } } - - var completionStepTitle: String? { + var careKitModel: CarekitModel? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.completionStep.title ?? Constants.YamlDefaults.CompletionStepTitle + return onBoardingDataModel?.fr.carekitView default: - return onBoardingDataModel?.en.completionStep.title ?? Constants.YamlDefaults.CompletionStepTitle + return onBoardingDataModel?.en.carekitView } } - - var completionStepText: String? { + var healthRecords: HealthRecords? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.completionStep.text ?? Constants.YamlDefaults.CompletionStepText + return onBoardingDataModel?.fr.healthRecords default: - return onBoardingDataModel?.en.completionStep.text ?? Constants.YamlDefaults.CompletionStepText + return onBoardingDataModel?.en.healthRecords } } - - var isPasscodeEnabled: Bool { + var healthPermissionsTitle: String? { switch getPreferredLocale().languageCode { case "fr": - guard let passcode = onBoardingDataModel?.fr.passcode.enable else { return true } - return passcode != Constants.false + return onBoardingDataModel?.fr.healthKitData.healthPermissionsTitle ?? Constants.YamlDefaults.HealthPermissionsTitle default: - guard let passcode = onBoardingDataModel?.en.passcode.enable else { return true } - return passcode != Constants.false + return onBoardingDataModel?.en.healthKitData.healthPermissionsTitle ?? Constants.YamlDefaults.HealthPermissionsTitle } } - - var failedLoginText: String? { + var healthPermissionsText: String? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.login.failedLoginText ?? Constants.YamlDefaults.FailedLoginText + return onBoardingDataModel?.fr.healthKitData.healthPermissionsText ?? Constants.YamlDefaults.HealthPermissionsText default: - return onBoardingDataModel?.en.login.failedLoginText ?? Constants.YamlDefaults.FailedLoginText + return onBoardingDataModel?.en.healthKitData.healthPermissionsText ?? Constants.YamlDefaults.HealthPermissionsText } } - - var failedLoginTitle: String? { + var backgroundReadFrequency: String? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.login.failedLoginTitle ?? Constants.YamlDefaults.FailedLoginTitle + return onBoardingDataModel?.fr.healthKitData.backgroundReadFrequency ?? "immediate" default: - return onBoardingDataModel?.en.login.failedLoginTitle ?? Constants.YamlDefaults.FailedLoginTitle + return onBoardingDataModel?.en.healthKitData.backgroundReadFrequency ?? "immediate" } } - - - var passcodeOnReturnText: String { + var healthKitDataToRead: [HealthKitTypes] { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.passcode.passcodeOnReturnText ?? Constants.YamlDefaults.PasscodeOnReturnText + return onBoardingDataModel?.fr.healthKitData.healthKitTypes ?? [HealthKitTypes(type: "stepCount"), HealthKitTypes(type: "distanceSwimming")] default: - return onBoardingDataModel?.en.passcode.passcodeOnReturnText ?? Constants.YamlDefaults.PasscodeOnReturnText + return onBoardingDataModel?.en.healthKitData.healthKitTypes ?? [HealthKitTypes(type: "stepCount"), HealthKitTypes(type: "distanceSwimming")] } } - - var passcodeType: String { + var withdrawl: Withdrawal? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.passcode.passcodeType ?? Constants.Passcode.lengthFour + return onBoardingDataModel?.fr.withdrawal default: - return onBoardingDataModel?.en.passcode.passcodeType ?? Constants.Passcode.lengthFour + return onBoardingDataModel?.en.withdrawal } } - - - var loginPasswordless: Bool { +} + +// MARK: - Consent +extension ModuleAppYmlReader { + var reasonForConsentText: String { switch getPreferredLocale().languageCode { case "fr": - guard let passwordless = onBoardingDataModel?.fr.login.loginPasswordless else { return false } - return passwordless == Constants.true + return onBoardingDataModel?.fr.consent.reasonForConsentText ?? Constants.YamlDefaults.TeamWebsite default: - guard let passwordless = onBoardingDataModel?.en.login.loginPasswordless else { return false } - return passwordless == Constants.true + return onBoardingDataModel?.en.consent.reasonForConsentText ?? Constants.YamlDefaults.TeamWebsite } } - var loginStepTitle: String { + var consentFileName: String { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.login.loginStepTitle ?? Constants.YamlDefaults.LoginStepTitle + return onBoardingDataModel?.fr.consent.fileName ?? Constants.YamlDefaults.ConsentFileName default: - return onBoardingDataModel?.en.login.loginStepTitle ?? Constants.YamlDefaults.LoginStepTitle + return onBoardingDataModel?.en.consent.fileName ?? Constants.YamlDefaults.ConsentFileName } } - var loginStepText: String { + var consentTitle: String? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.login.loginStepText ?? Constants.YamlDefaults.LoginStepText + return onBoardingDataModel?.fr.consent.title ?? Constants.YamlDefaults.ConsentTitle default: - return onBoardingDataModel?.en.login.loginStepText ?? Constants.YamlDefaults.LoginStepText + return onBoardingDataModel?.en.consent.title ?? Constants.YamlDefaults.ConsentTitle } } - var passcodeText: String { + var consent: Consent? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.passcode.passcodeText ?? Constants.YamlDefaults.PasscodeText + return onBoardingDataModel?.fr.consent default: - return onBoardingDataModel?.en.passcode.passcodeText ?? Constants.YamlDefaults.PasscodeText + return onBoardingDataModel?.en.consent } } - var loginOptionsText: String { +} + +// MARK: - Theme +extension ModuleAppYmlReader { + var primaryColor: UIColor { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.loginOptionsInfo.text ?? Constants.YamlDefaults.LoginOptionsText + let valueSet = (onBoardingDataModel?.fr.onboarding ?? []) + for item in valueSet { + return item.color.color ?? UIColor.black + } default: - return onBoardingDataModel?.en.loginOptionsInfo.text ?? Constants.YamlDefaults.LoginOptionsText + let valueSet = (onBoardingDataModel?.en.onboarding ?? []) + for item in valueSet { + return item.color.color ?? UIColor.black + } } + return UIColor.black } - var loginOptionsIcon: String { - switch getPreferredLocale().languageCode { + var backgroundColor: UIColor { + guard let langStr = Locale.current.languageCode else { fatalError("language not found") } + + switch langStr { case "fr": - return onBoardingDataModel?.fr.loginOptionsInfo.icon ?? Constants.YamlDefaults.LoginOptionsIcon + return onBoardingDataModel?.fr.profileDataModel.backgroundColor.color ?? UIColor.black default: - return onBoardingDataModel?.en.loginOptionsInfo.icon ?? Constants.YamlDefaults.LoginOptionsIcon + return onBoardingDataModel?.en.profileDataModel.backgroundColor.color ?? UIColor.black } } - - var profileData: ProfileModel? { +} + +// MARK: - Login +extension ModuleAppYmlReader { + var failedLoginText: String? { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.profileDataModel + return onBoardingDataModel?.fr.login.failedLoginText ?? Constants.YamlDefaults.FailedLoginText default: - return onBoardingDataModel?.en.profileDataModel + return onBoardingDataModel?.en.login.failedLoginText ?? Constants.YamlDefaults.FailedLoginText } } - var backgroundColor: UIColor { - guard let langStr = Locale.current.languageCode else { fatalError("language not found") } - - switch langStr { + var failedLoginTitle: String? { + switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.profileDataModel.backgroundColor.color ?? UIColor.black + return onBoardingDataModel?.fr.login.failedLoginTitle ?? Constants.YamlDefaults.FailedLoginTitle default: - return onBoardingDataModel?.en.profileDataModel.backgroundColor.color ?? UIColor.black + return onBoardingDataModel?.en.login.failedLoginTitle ?? Constants.YamlDefaults.FailedLoginTitle } } - var researchKitModel: ResearchKitModel? { + var loginStepTitle: String { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.researchKitView + return onBoardingDataModel?.fr.login.loginStepTitle ?? Constants.YamlDefaults.LoginStepTitle default: - return onBoardingDataModel?.en.researchKitView + return onBoardingDataModel?.en.login.loginStepTitle ?? Constants.YamlDefaults.LoginStepTitle } } - var surverysTaskModel: SurverysTask? { + var loginOptionsText: String { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.surverysTask + return onBoardingDataModel?.fr.loginOptionsInfo.text ?? Constants.YamlDefaults.LoginOptionsText default: - return onBoardingDataModel?.en.surverysTask + return onBoardingDataModel?.en.loginOptionsInfo.text ?? Constants.YamlDefaults.LoginOptionsText } } - var careKitModel: CarekitModel? { + var loginOptionsIcon: String { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.carekitView + return onBoardingDataModel?.fr.loginOptionsInfo.icon ?? Constants.YamlDefaults.LoginOptionsIcon default: - return onBoardingDataModel?.en.carekitView + return onBoardingDataModel?.en.loginOptionsInfo.icon ?? Constants.YamlDefaults.LoginOptionsIcon } } - var healthRecords: HealthRecords? { + var loginStepText: String { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.healthRecords + return onBoardingDataModel?.fr.login.loginStepText ?? Constants.YamlDefaults.LoginStepText default: - return onBoardingDataModel?.en.healthRecords + return onBoardingDataModel?.en.login.loginStepText ?? Constants.YamlDefaults.LoginStepText } } - - var healthPermissionsTitle: String? { +} + +// MARK: - Passcode +extension ModuleAppYmlReader { + var isPasscodeEnabled: Bool { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.healthKitData.healthPermissionsTitle ?? Constants.YamlDefaults.HealthPermissionsTitle + guard let passcode = onBoardingDataModel?.fr.passcode.enable else { + return true + } + return passcode != Constants.false default: - return onBoardingDataModel?.en.healthKitData.healthPermissionsTitle ?? Constants.YamlDefaults.HealthPermissionsTitle + guard let passcode = onBoardingDataModel?.en.passcode.enable else { + return true + } + return passcode != Constants.false } } - var healthPermissionsText: String? { + var passcodeOnReturnText: String { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.healthKitData.healthPermissionsText ?? Constants.YamlDefaults.HealthPermissionsText + return onBoardingDataModel?.fr.passcode.passcodeOnReturnText ?? Constants.YamlDefaults.PasscodeOnReturnText default: - return onBoardingDataModel?.en.healthKitData.healthPermissionsText ?? Constants.YamlDefaults.HealthPermissionsText + return onBoardingDataModel?.en.passcode.passcodeOnReturnText ?? Constants.YamlDefaults.PasscodeOnReturnText } } - - - var backgroundReadFrequency: String? { + + var passcodeType: String { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.healthKitData.backgroundReadFrequency ?? "immediate" + return onBoardingDataModel?.fr.passcode.passcodeType ?? Constants.Passcode.lengthFour default: - return onBoardingDataModel?.en.healthKitData.backgroundReadFrequency ?? "immediate" + return onBoardingDataModel?.en.passcode.passcodeType ?? Constants.Passcode.lengthFour } } - var healthKitDataToRead: [HealthKitTypes] { + var loginPasswordless: Bool { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.healthKitData.healthKitTypes ?? [HealthKitTypes(type: "stepCount"), HealthKitTypes(type: "distanceSwimming")] + guard let passwordless = onBoardingDataModel?.fr.login.loginPasswordless else { return false } + return passwordless == Constants.true default: - return onBoardingDataModel?.en.healthKitData.healthKitTypes ?? [HealthKitTypes(type: "stepCount"), HealthKitTypes(type: "distanceSwimming")] + guard let passwordless = onBoardingDataModel?.en.login.loginPasswordless else { return false } + return passwordless == Constants.true } } - var withdrawl: Withdrawal? { + var passcodeText: String { switch getPreferredLocale().languageCode { case "fr": - return onBoardingDataModel?.fr.withdrawal + return onBoardingDataModel?.fr.passcode.passcodeText ?? Constants.YamlDefaults.PasscodeText default: - return onBoardingDataModel?.en.withdrawal + return onBoardingDataModel?.en.passcode.passcodeText ?? Constants.YamlDefaults.PasscodeText } } - } struct Consent: Codable { @@ -395,7 +414,15 @@ struct CompletionStep: Codable { let text: String } -struct OnBoardingScreen: Codable{ +struct ConfigDataModel: Codable { + let dataModel: OnBoardingScreen + + enum CodingKeys: String, CodingKey { + case dataModel = "DataModel" + } +} + +struct OnBoardingScreen: Codable { let en: OnBoardingDataModel let fr: OnBoardingDataModel } @@ -405,7 +432,7 @@ struct LoginOptionsInfo: Codable { let icon: String } -struct OnBoardingDataModel: Codable{ +struct OnBoardingDataModel: Codable { let onboarding: [Onboarding] let consent: Consent let registration: Registration @@ -442,11 +469,11 @@ struct HealthKitData: Codable { let healthKitTypes: [HealthKitTypes] } -struct HealthKitTypes: Codable, Equatable { +struct HealthKitTypes: Codable, Equatable { let type: String } -struct ProfileModel: Codable{ +struct ProfileModel: Codable { let title: String let profileImage: String let help: String @@ -454,7 +481,7 @@ struct ProfileModel: Codable{ let reportProblemText: String let supportText: String let consentText: String - let WithdrawStudyText: String + let withdrawStudyText: String let profileInfoHeader: String let firstName: String let lastName: String @@ -466,7 +493,7 @@ struct ProfileModel: Codable{ let backgroundColor: String } -struct ResearchKitModel: Codable{ +struct ResearchKitModel: Codable { let surveysHeaderTitle: String let formSurveyExample: String let groupedFormSurveyExample: String @@ -529,11 +556,9 @@ struct ResearchKitModel: Codable{ let miscellaneousHeaderTitle: String let webView: String let researchKit: String - } - -struct SurverysTask: Codable{ +struct SurverysTask: Codable { let title: String let additionalText: String let itemQuestion: String @@ -553,10 +578,10 @@ struct SurverysTask: Codable{ let learnMoreTitle: String let learnMoreText: String let birthdayText: String - + } -struct CarekitModel: Codable{ +struct CarekitModel: Codable { let simple: String let instruction: String let buttonLog: String @@ -569,4 +594,3 @@ struct CarekitModel: Codable{ let detailed: String let careKit: String } - diff --git a/OTFMagicBox/Library/Yaml/YmlReader.swift b/OTFMagicBox/Library/Yaml/YmlReader.swift index be198765..681772ee 100644 --- a/OTFMagicBox/Library/Yaml/YmlReader.swift +++ b/OTFMagicBox/Library/Yaml/YmlReader.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -42,12 +42,12 @@ import OTFUtilities YmlReader decodes the Yaml values from the given file. */ public class YmlReader { - + /// Yaml file name. private let fileName = Constants.YamlDefaults.FileName - - var dataModel : DefaultConfig? - + + var dataModel: DefaultConfig? + init() { let fileUrlString = Bundle.main.path(forResource: fileName, ofType: nil)! let fileUrl = URL(fileURLWithPath: fileUrlString) @@ -63,45 +63,35 @@ public class YmlReader { } } } - func getPreferredLocale() -> Locale { guard let preferredIdentifier = Locale.preferredLanguages.first else { return Locale.current } return Locale(identifier: preferredIdentifier) } - + // Returns primary color. var primaryColor: UIColor { - let valueSet = (dataModel?.designConfig ?? []) - - for value in valueSet where value.name == "label" { - return value.textValue.color ?? UIColor.black + guard let labelColor = appStyle.textColor.color else { + return .label } - return .black + return labelColor } - - // Returns tint color. var tintColor: UIColor { - let valueSet = (dataModel?.designConfig ?? []) - - for value in valueSet where value.name == "tintColor" { - return value.textValue.color ?? UIColor.black + guard let buttonTextColor = appStyle.buttonTextColor.color else { + return .black } - return .black + return buttonTextColor } - var apiKey: String { guard let apiKey = dataModel?.apiKey else { return Constants.YamlDefaults.APIKey } return apiKey } - - var appTitle: String { - switch getPreferredLocale().languageCode { + switch getPreferredLocale().languageCode { case "fr": if let title = dataModel?.fr.appTitle { return title @@ -113,7 +103,6 @@ public class YmlReader { } return Constants.YamlDefaults.TeamName } - var teamName: String { switch getPreferredLocale().languageCode { case "fr": @@ -122,17 +111,17 @@ public class YmlReader { return dataModel?.en.teamName ?? Constants.YamlDefaults.TeamName } } - + var teamEmail: String { return dataModel?.teamEmail ?? Constants.YamlDefaults.TeamEmail } - + var teamPhone: String { return dataModel?.teamPhone ?? Constants.YamlDefaults.TeamPhone } - + var teamCopyright: String { - + switch getPreferredLocale().languageCode { case "fr": return dataModel?.fr.copyright ?? Constants.YamlDefaults.TeamCopyright @@ -140,49 +129,49 @@ public class YmlReader { return dataModel?.en.copyright ?? Constants.YamlDefaults.TeamCopyright } } - + var teamWebsite: String { return dataModel?.teamWebsite ?? Constants.YamlDefaults.TeamWebsite } - + var showAppleLogin: Bool { guard let showSocialLogin = dataModel?.showAppleSignin else { return false } return showSocialLogin == Constants.true } - + var showGoogleLogin: Bool { guard let showSocialLogin = dataModel?.showGoogleSignin else { return false } return showSocialLogin == Constants.true } - -// var healthPermissionsTitle: String? { -// switch getPreferredLocale().languageCode { -// case "fr": -// return dataModel?.fr.healthKitData.healthPermissionsTitle ?? Constants.YamlDefaults.HealthPermissionsTitle -// default: -// return dataModel?.en.healthKitData.healthPermissionsTitle ?? Constants.YamlDefaults.HealthPermissionsTitle -// } -// } -// -// var healthPermissionsText: String? { -// switch getPreferredLocale().languageCode { -// case "fr": -// return dataModel?.fr.healthKitData.healthPermissionsText ?? Constants.YamlDefaults.HealthPermissionsText -// default: -// return dataModel?.en.healthKitData.healthPermissionsText ?? Constants.YamlDefaults.HealthPermissionsText -// } -// } - + + // var healthPermissionsTitle: String? { + // switch getPreferredLocale().languageCode { + // case "fr": + // return dataModel?.fr.healthKitData.healthPermissionsTitle ?? Constants.YamlDefaults.HealthPermissionsTitle + // default: + // return dataModel?.en.healthKitData.healthPermissionsTitle ?? Constants.YamlDefaults.HealthPermissionsTitle + // } + // } + // + // var healthPermissionsText: String? { + // switch getPreferredLocale().languageCode { + // case "fr": + // return dataModel?.fr.healthKitData.healthPermissionsText ?? Constants.YamlDefaults.HealthPermissionsText + // default: + // return dataModel?.en.healthKitData.healthPermissionsText ?? Constants.YamlDefaults.HealthPermissionsText + // } + // } + var useCareKit: Bool { guard let useCareKit = dataModel?.useCareKit else { return false } return useCareKit == Constants.true } - + var showCheckupScreen: Bool { guard let showCheckupScreen = dataModel?.showCheckupScreen else { return false } return showCheckupScreen == Constants.true } - + var showStaticUIScreen: Bool { guard let showStaticUIScreen = dataModel?.showStaticUIScreen else { return false } return showStaticUIScreen == Constants.true @@ -206,10 +195,6 @@ public class YmlReader { // } // } - var appTheme: ThemeCustomization? { - return dataModel?.appTheme - } - // var withdrawl: Withdrawal? { // switch getPreferredLocale().languageCode { // case "fr": @@ -228,3 +213,33 @@ public class YmlReader { // } // } } + +extension YmlReader { + internal var defaultStyle: ThemeCustomization { + return ThemeCustomization( + name: "defaultStyle", + backgroundColor: "systemBackground", + textColor: "label", + separatorColor: "separator", + cellbackgroundColor: "secondarySystemGroupedBackground", + buttonTextColor: "Teal", + borderColor: "Black", + headerColor: "label", + textWeight: "", + textFont: "Inherited", + screenTitleFont: "Header", + screenTitleWeight: "", + headerTitleFont: "HeaderInherited", + headerTitleWeight: "Bold", + appTitleSize: "Large Title" + ) + } + + var appStyle: ThemeCustomization { + guard let styleName = dataModel?.selectedStyle, + let style = dataModel?.styles.first(where: { $0.name == styleName }) else { + return defaultStyle + } + return style + } +} diff --git a/OTFMagicBox/Login/LoginCustomWaitStep.swift b/OTFMagicBox/Login/LoginCustomWaitStep.swift index 08a68879..3cb28d9e 100644 --- a/OTFMagicBox/Login/LoginCustomWaitStep.swift +++ b/OTFMagicBox/Login/LoginCustomWaitStep.swift @@ -1,50 +1,50 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation import OTFResearchKit class LoginCustomWaitStep: ORKStep { - + static let identifier = "LoginCustomWaitStep" - + override init(identifier: String) { super.init(identifier: identifier) } - + required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - + } diff --git a/OTFMagicBox/Login/LoginExistingUserViewController.swift b/OTFMagicBox/Login/LoginExistingUserViewController.swift index 57fd07ad..8ab78484 100644 --- a/OTFMagicBox/Login/LoginExistingUserViewController.swift +++ b/OTFMagicBox/Login/LoginExistingUserViewController.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -39,22 +39,22 @@ import OTFResearchKit enum AuthMethod: String, CaseIterable, Codable { case email, apple - + var signinTitle: String { switch self { case .email: return Constants.CustomiseStrings.signinWithEmail - + case .apple: return Constants.CustomiseStrings.signinWithApple } } - + var signupTitle: String { switch self { case .email: return Constants.CustomiseStrings.signUpWithEmail - + case .apple: return Constants.CustomiseStrings.signUpWithApple } @@ -62,40 +62,38 @@ enum AuthMethod: String, CaseIterable, Codable { } struct LoginExistingUserViewController: UIViewControllerRepresentable { - + func makeCoordinator() -> OnboardingTaskCoordinator { OnboardingTaskCoordinator(authType: .login) } - + typealias UIViewControllerType = ORKTaskViewController - + func updateUIViewController(_ taskViewController: ORKTaskViewController, context: Context) {} - + func makeUIViewController(context: Context) -> ORKTaskViewController { - + var loginSteps: [ORKStep] let signInButtons = OnboardingOptionsStep(identifier: "SignInButtons") let loginUserPassword = ORKLoginStep(identifier: "LoginExistingStep", title: Constants.CustomiseStrings.login, text: Constants.Login.Text, loginViewControllerClass: LoginViewController.self) loginSteps = [signInButtons, loginUserPassword] - - //add consent if user dont have consent in cloud + + // add consent if user dont have consent in cloud let config = ModuleAppYmlReader() let consentDocument = ConsentDocument() /* ************************************************************** - **************************************************************/ + **************************************************************/ // use the `ORKConsentReviewStep` from ResearchKit let signature = consentDocument.signatures?.first let reviewConsentStep = ORKConsentReviewStep(identifier: "ConsentReviewStep", signature: signature, in: consentDocument) reviewConsentStep.text = YmlReader().teamWebsite reviewConsentStep.reasonForConsent = config.reasonForConsentText - + // create a task with each step if !UserDefaultsManager.isConsentDocumentViewed { UserDefaultsManager.setIsConsentDocumentViewed(true) loginSteps += [reviewConsentStep] } - - // use the `ORKPasscodeStep` from ResearchKit. if config.isPasscodeEnabled { let passcodeStep = ORKPasscodeStep(identifier: "Passcode") @@ -107,16 +105,16 @@ struct LoginExistingUserViewController: UIViewControllerRepresentable { } else { passcodeStep.passcodeType = .type4Digit } - + loginSteps += [passcodeStep] } - + // set completion step let completionStep = ORKCompletionStep(identifier: Constants.Identifier.CompletionStep) completionStep.title = ModuleAppYmlReader().completionStepTitle completionStep.text = ModuleAppYmlReader().completionStepText loginSteps += [completionStep] - + let navigableTask = ORKNavigableOrderedTask(identifier: "StudyLoginTask", steps: loginSteps) let resultSelector = ORKResultSelector(resultIdentifier: "SignInButtons") let booleanAnswerType = ORKResultPredicate.predicateForBooleanQuestionResult(with: resultSelector, expectedAnswer: true) @@ -125,24 +123,23 @@ struct LoginExistingUserViewController: UIViewControllerRepresentable { defaultStepIdentifier: "ConsentReviewStep", validateArrays: true) navigableTask.setNavigationRule(predicateRule, forTriggerStepIdentifier: "SignInButtons") - + // ADD New navigation Rule (if has or not consentDocument) // Consent Rule let resultConsent = ORKResultSelector(resultIdentifier: "ConsentReview") let booleanAnswerConsent = ORKResultPredicate.predicateForBooleanQuestionResult(with: resultConsent, expectedAnswer: true) let predicateRuleConsent = ORKPredicateStepNavigationRule(resultPredicates: [booleanAnswerConsent], - destinationStepIdentifiers: ["HealthKit"], - defaultStepIdentifier: "ConsentReviewStep", - validateArrays: true) + destinationStepIdentifiers: ["HealthKit"], + defaultStepIdentifier: "ConsentReviewStep", + validateArrays: true) navigableTask.setNavigationRule(predicateRuleConsent, forTriggerStepIdentifier: "ConsentReview") - + // wrap that task on a view controller let taskViewController = ORKTaskViewController(task: navigableTask, taskRun: nil) taskViewController.delegate = context.coordinator // enables `ORKTaskViewControllerDelegate` below - + // & present the VC! return taskViewController } - -} +} diff --git a/OTFMagicBox/Login/LoginSteps.swift b/OTFMagicBox/Login/LoginSteps.swift index b2b3db6b..082fd647 100644 --- a/OTFMagicBox/Login/LoginSteps.swift +++ b/OTFMagicBox/Login/LoginSteps.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -41,63 +41,63 @@ protocol LoginSteps { struct EmailLoginSteps: LoginSteps { let steps: [ORKStep] - + public init() { var loginSteps: [ORKStep] - + let loginStep = ORKLoginStep(identifier: Constants.Login.Identifier, title: Constants.Login.Title, text: Constants.Login.Text, loginViewControllerClass: LoginViewController.self) - + loginSteps = [loginStep] - + // use the `ORKPasscodeStep` from ResearchKit. if ModuleAppYmlReader().isPasscodeEnabled { let passcodeStep = ORKPasscodeStep(identifier: "Passcode") - + let type = ModuleAppYmlReader().passcodeType - + if type == Constants.Passcode.lengthSix { passcodeStep.passcodeType = .type6Digit } else { passcodeStep.passcodeType = .type4Digit } - + passcodeStep.text = Constants.CustomiseStrings.enterPasscode - + loginSteps += [passcodeStep] } - + self.steps = loginSteps } } struct AppleLoginSteps: LoginSteps { let steps: [ORKStep] - + public init() { var loginSteps: [ORKStep] - + let appleLoginStep = SignInWithAppleStep(identifier: "SignInWithApple") - + loginSteps = [appleLoginStep] - + // use the `ORKPasscodeStep` from ResearchKit. if ModuleAppYmlReader().isPasscodeEnabled { let passcodeStep = ORKPasscodeStep(identifier: "Passcode") - + let type = ModuleAppYmlReader().passcodeType - + if type == Constants.Passcode.lengthSix { passcodeStep.passcodeType = .type6Digit } else { passcodeStep.passcodeType = .type4Digit } - + passcodeStep.text = Constants.CustomiseStrings.enterPasscode - + loginSteps += [passcodeStep] } - + self.steps = loginSteps } } diff --git a/OTFMagicBox/Login/LoginViewController.swift b/OTFMagicBox/Login/LoginViewController.swift index da2494cf..efa54b2a 100644 --- a/OTFMagicBox/Login/LoginViewController.swift +++ b/OTFMagicBox/Login/LoginViewController.swift @@ -1,50 +1,51 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation import OTFResearchKit import OTFUtilities import Combine +import WatchConnectivity /** The LoginViewController provides the default login view from ResearchKit. */ class LoginViewController: ORKLoginStepViewController { - + var subscriptions = Set() var disposables: AnyCancellable? - + lazy var authButton: UIButton = { let button = UIButton() button.translatesAutoresizingMaskIntoConstraints = false @@ -58,30 +59,30 @@ class LoginViewController: ORKLoginStepViewController { } return button }() - + override func viewDidLoad() { super.viewDidLoad() authButton.addTarget(self, action: #selector(customButtonTapped), for: .touchUpInside) view.addSubview(authButton) addAuthButtonConstraints() - NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(sender:)), name: UIResponder.keyboardWillShowNotification, object: nil); - - NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(sender:)), name: UIResponder.keyboardWillHideNotification, object: nil); + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(sender:)), name: UIResponder.keyboardWillShowNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(sender:)), name: UIResponder.keyboardWillHideNotification, object: nil) } - + @objc func keyboardWillShow(sender: NSNotification) { authButton.removeFromSuperview() } - + @objc func keyboardWillHide(sender: NSNotification) { view.addSubview(authButton) addAuthButtonConstraints() } - + func getSubviewsOfView(view: UIView) -> [T] { var subviewArray = [T]() - if view.subviews.count == 0 { + if view.subviews.isEmpty { return subviewArray } for subview in view.subviews { @@ -92,7 +93,7 @@ class LoginViewController: ORKLoginStepViewController { } return subviewArray } - + @objc func customButtonTapped() { LocalAuthentication.shared.authenticationWithTouchID { success in if success { @@ -108,13 +109,13 @@ class LoginViewController: ORKLoginStepViewController { item.text = emailFromKeychain } } - + let button: [UIButton] = self.getSubviewsOfView(view: self.view) - for item in button { - if item.currentTitle == "Login" { + for item in button where item.currentTitle == "Login" { +// if item.currentTitle == "Login" { item.isEnabled = true item.isUserInteractionEnabled = true - } +// } } } } else { @@ -129,9 +130,9 @@ class LoginViewController: ORKLoginStepViewController { } } } - + override func goForward() { - + var emailAddress = String() var password = String() let textFields: [UITextField] = self.getSubviewsOfView(view: self.view) @@ -142,20 +143,20 @@ class LoginViewController: ORKLoginStepViewController { emailAddress = item.text ?? "" } } - + loginRequest(email: emailAddress, password: password) } - + func loginRequest(email: String, password: String) { - + let alert = UIAlertController(title: nil, message: Constants.CustomiseStrings.loginingIn, preferredStyle: .alert) - + let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50)) loadingIndicator.hidesWhenStopped = true loadingIndicator.style = UIActivityIndicatorView.Style.medium loadingIndicator.startAnimating() alert.view.addSubview(loadingIndicator) - + taskViewController?.present(alert, animated: true, completion: nil) disposables = OTFTheraforgeNetwork.shared.loginRequest(email: email, password: password) .receive(on: DispatchQueue.main) @@ -166,59 +167,71 @@ class LoginViewController: ORKLoginStepViewController { alert.dismiss(animated: true) { self.showAlert(title: Constants.CustomiseStrings.loginInError, message: error.error.message ) } - default: break; + default: break } } receiveValue: { result in - self.saveValuesToLocal(email: email, password: password, encryptedDefaultStorageKeyHex: result.data.encryptedDefaultStorageKey, encryptedconfidentialStorageKeyHex: result.data.encryptedConfidentialStorageKey) + self.saveUserCrredentials(email: email, password: password) + if let encryptedDefaultStorageKeyHex = result.data.encryptedDefaultStorageKey, let encryptedconfidentialStorageKeyHex = result.data.encryptedConfidentialStorageKey { + self.saveUserKeysToLocal(email: email, + password: password, + encryptedDefaultStorageKeyHex: encryptedDefaultStorageKeyHex, + encryptedconfidentialStorageKeyHex: encryptedconfidentialStorageKeyHex) + } + self.synchronizedDatabase { _ in - alert.dismiss(animated: false, completion: { + WCSession.default.sendMessage(["databaseSynced": "true"]) { _ in } + alert.dismiss(animated: false, completion: { super.goForward() - }) + }) } - + } } - - func synchronizedDatabase(completion: ((Error?) -> Void)?){ + + func synchronizedDatabase(completion: ((Error?) -> Void)?) { DispatchQueue.main.async { - CloudantSyncManager.shared.syncCloudantStore(notifyWhenDone: true) { - result in + CloudantSyncManager.shared.syncCloudantStore(notifyWhenDone: true) { result in completion?(result) } } - - } - func saveValuesToLocal(email: String, password: String, encryptedDefaultStorageKeyHex: String, encryptedconfidentialStorageKeyHex: String){ + func saveUserCrredentials(email: String, password: String) { + KeychainCloudManager.saveUserCredentialsInKeychain(email: email, password: password) + } + + func saveUserKeysToLocal(email: String, password: String, encryptedDefaultStorageKeyHex: String, encryptedconfidentialStorageKeyHex: String) { let swiftSodium = SwiftSodium() let masterKey = swiftSodium.generateMasterKey(password: password, email: email) let keyPair = swiftSodium.sodium.box.keyPair(seed: masterKey) - - - if let keyPair = keyPair { - let encryptedDefaultStorageKey = swiftSodium.getArrayOfBytesFromData(FileData: swiftSodium.hexStringToData(string: encryptedDefaultStorageKeyHex) as NSData) - let defaultStorageKey = swiftSodium.decryptKey(bytes: encryptedDefaultStorageKey, publicKey: keyPair.publicKey, secretKey: keyPair.secretKey) - let encryptedconfidentialStorageKey = swiftSodium.getArrayOfBytesFromData(FileData: swiftSodium.hexStringToData(string: encryptedconfidentialStorageKeyHex) as NSData) + let encryptedDefaultStorageKey = swiftSodium.getArrayOfBytesFromData(fileData: swiftSodium.hexStringToData(string: encryptedDefaultStorageKeyHex) as NSData) + let defaultStorageKey = swiftSodium.decryptKey(bytes: encryptedDefaultStorageKey, publicKey: keyPair.publicKey, secretKey: keyPair.secretKey) + + let encryptedconfidentialStorageKey = swiftSodium.getArrayOfBytesFromData(fileData: swiftSodium.hexStringToData(string: encryptedconfidentialStorageKeyHex) as NSData) let confidentialStorageKey = swiftSodium.decryptKey(bytes: encryptedconfidentialStorageKey, publicKey: keyPair.publicKey, secretKey: keyPair.secretKey) - - KeychainCloudManager.saveValuesInKeychain(email: email, password: password, masterKey: masterKey, publicKey: keyPair.publicKey, secretKey: keyPair.secretKey, defaultStorageKey: defaultStorageKey, confidentialStorageKey: confidentialStorageKey) + + KeychainCloudManager.saveUserKeys( + masterKey: masterKey, + publicKey: keyPair.publicKey, + secretKey: keyPair.secretKey, + defaultStorageKey: defaultStorageKey, + confidentialStorageKey: confidentialStorageKey) } } // Forgot password. override func forgotPasswordButtonTapped() { let alert = UIAlertController(title: Constants.CustomiseStrings.resetPassword, message: Constants.CustomiseStrings.enterYourEmailToGetLink, preferredStyle: .alert) - + alert.addTextField { (textField) in textField.placeholder = Constants.CustomiseStrings.enterYourEmail } - + alert.addAction(UIAlertAction(title: Constants.CustomiseStrings.submit, style: .default) { (_) in - guard let email = alert.textFields![0].text else{ return } + guard let email = alert.textFields![0].text else { return } if email.isValidEmail { - + self.disposables = OTFTheraforgeNetwork.shared.forgotPassword(email: email) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { response in @@ -228,36 +241,36 @@ class LoginViewController: ORKLoginStepViewController { DispatchQueue.main.async { self.showAlert(title: Constants.CustomiseStrings.forgotPassword, message: error.error.message) } - default: break; + default: break } - }, receiveValue: { result in + }, receiveValue: { _ in DispatchQueue.main.async { self.resetPassword(email: email) } }) - - }else { + + } else { self.showAlert(title: Constants.CustomiseStrings.resetPassword, message: Constants.CustomiseStrings.enterValidEmail) } }) - + alert.addAction(UIAlertAction(title: Constants.CustomiseStrings.cancel, style: .cancel, handler: nil)) - + self.present(alert, animated: true) } - + // Reset password for the givem email. func resetPassword(email: String) { let alert = UIAlertController(title: Constants.CustomiseStrings.resetPassword, message: Constants.CustomiseStrings.enterTheCode, preferredStyle: .alert) - + alert.addTextField { (textField) in textField.placeholder = "Code " } - + alert.addTextField { (textField) in textField.placeholder = Constants.CustomiseStrings.newPassword textField.isSecureTextEntry = true - + } alert.addAction(UIAlertAction(title: Constants.CustomiseStrings.submit, style: .default) { _ in guard let code = alert.textFields![0].text else { @@ -266,7 +279,7 @@ class LoginViewController: ORKLoginStepViewController { guard let newPassword = alert.textFields![1].text else { fatalError("Invalid password") } - + self.disposables = OTFTheraforgeNetwork.shared.resetPassword(email: email, code: code, newPassword: newPassword) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { response in @@ -276,21 +289,21 @@ class LoginViewController: ORKLoginStepViewController { DispatchQueue.main.async { self.showAlert(title: Constants.CustomiseStrings.passwordResetError, message: error.error.message) } - default: break; + default: break } - }, receiveValue: { result in + }, receiveValue: { _ in DispatchQueue.main.async { self.showAlert(title: Constants.CustomiseStrings.passwordUpdated, message: "") } }) }) alert.addAction(UIAlertAction(title: Constants.CustomiseStrings.cancel, style: .cancel, handler: nil)) - + self.present(alert, animated: true) } - + func addAuthButtonConstraints() { - + NSLayoutConstraint.activate([ authButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), authButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -150), @@ -300,4 +313,3 @@ class LoginViewController: ORKLoginStepViewController { ]) } } - diff --git a/OTFMagicBox/Login/SignInWithAppleStepViewController.swift b/OTFMagicBox/Login/SignInWithAppleStepViewController.swift index cd3207ab..ed084240 100644 --- a/OTFMagicBox/Login/SignInWithAppleStepViewController.swift +++ b/OTFMagicBox/Login/SignInWithAppleStepViewController.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 AuthenticationServices @@ -43,10 +43,10 @@ public class SignInWithAppleStep: ORKInstructionStep { public var requestedScopes: [ASAuthorization.Scope] public init(identifier: String, - title: String! = nil, - text: String! = nil, - requestedScopes: [ASAuthorization.Scope] = [.email]) { - + title: String! = nil, + text: String! = nil, + requestedScopes: [ASAuthorization.Scope] = [.email]) { + self.requestedScopes = requestedScopes super.init(identifier: identifier) self.title = Constants.CustomiseStrings.signinWithApple @@ -61,36 +61,36 @@ public class SignInWithAppleStep: ORKInstructionStep { public class SignInWithAppleStepViewController: ORKInstructionStepViewController, ASAuthorizationControllerDelegate { - + let authType: AuthType var disposables: AnyCancellable? - + /// The step presented by the step view controller. public var signInWithAppleStep: SignInWithAppleStep! { return step as? SignInWithAppleStep } - + init(authType: AuthType, step: ORKStep?) { self.authType = authType - + super.init(step: step) } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - - public override func viewDidLoad() { + + override public func viewDidLoad() { super.viewDidLoad() - + continueButtonTitle = NSLocalizedString( Constants.CustomiseStrings.signinWithApple, comment: "Please use Apple's official translations" ) - + } - public override func goForward() { + override public func goForward() { let appleIDProvider = ASAuthorizationAppleIDProvider() let request = appleIDProvider.createRequest() request.requestedScopes = signInWithAppleStep?.requestedScopes ?? [.email] @@ -110,7 +110,7 @@ public class SignInWithAppleStepViewController: ORKInstructionStepViewController OTFLog("Unable to fetch identity token") return } - + // We are using this identity token to get other required fields e.g. email of the user. // The JWT token's payload is decided by Apple itself. We should be cautious that Apple // may change the format/composition of the token in the future. @@ -122,15 +122,15 @@ public class SignInWithAppleStepViewController: ORKInstructionStepViewController let alert = UIAlertController(title: nil, message: authType == .login ? Constants.CustomiseStrings.signingIn : Constants.CustomiseStrings.signingUp, preferredStyle: .alert) - + let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50)) loadingIndicator.hidesWhenStopped = true loadingIndicator.style = UIActivityIndicatorView.Style.medium loadingIndicator.startAnimating() alert.view.addSubview(loadingIndicator) - + taskViewController?.present(alert, animated: true) - + disposables = OTFTheraforgeNetwork.shared.socialLoginRequest(userType: .patient, socialType: .apple, authType: authType, idToken: idTokenString) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { response in @@ -142,9 +142,9 @@ public class SignInWithAppleStepViewController: ORKInstructionStepViewController self.taskViewController?.present(alert, animated: true) self.showError(error) } - default: break; + default: break } - }, receiveValue: { result in + }, receiveValue: { _ in alert.dismiss(animated: true, completion: nil) super.goForward() }) @@ -163,4 +163,3 @@ public class SignInWithAppleStepViewController: ORKInstructionStepViewController ) } } - diff --git a/OTFMagicBox/ModuleAppSysParameter.yml b/OTFMagicBox/ModuleAppSysParameter.yml index a190cb08..a49940bd 100644 --- a/OTFMagicBox/ModuleAppSysParameter.yml +++ b/OTFMagicBox/ModuleAppSysParameter.yml @@ -53,7 +53,7 @@ # Key and Value: # Text written on left side of the punctuation (:) is called as Key and text written on right side is called as Value. -# Example: teamEmail: "", here "teamEmail" is the Key and whatever is displayed after punctuation (:) within the quotes is the value assigned for that Key. +# Example: teamEmail: "", here "teamEmail" is the Key and whatever is displayed after punctuation (:) within the colon "" is the value assigned for that Key. # Default Values:- @@ -192,7 +192,7 @@ DataModel: summary: "This is custom section." content: "Custom consent section. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem." title: "Custom consent section" - image: "online-agreement1" + image: "online-agreement" registration: showDateOfBirth: "true" @@ -283,7 +283,7 @@ DataModel: reportProblemHeader: "Report a Problem" supportText: "Support" consentText: "Consent Documents" - WithdrawStudyText: "Withdraw from Study" + withdrawStudyText: "Withdraw from Study" profileInfoHeader: "Basic Information" firstName: "First Name" lastName: "Last Name" @@ -619,7 +619,7 @@ DataModel: reportProblemHeader: "Signaler un problème" supportText: "Soutien" consentText: "Documents de consentement" - WithdrawStudyText: "Se retirer de l'étude" + withdrawStudyText: "Se retirer de l'étude" profileInfoHeader: "Informations De Base" firstName: "Prénom" lastName: "nom de famille" @@ -729,11 +729,3 @@ DataModel: taskHeader: "Tâche" detailed: "détaillée" careKit: "Kit de soins" - - - #ProfileScreenSetup - - - - - diff --git a/OTFMagicBox/OCKStore + SampleData.swift b/OTFMagicBox/OCKStore + SampleData.swift index 603ac1b7..e60ae86d 100644 --- a/OTFMagicBox/OCKStore + SampleData.swift +++ b/OTFMagicBox/OCKStore + SampleData.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -41,33 +41,33 @@ import HealthKit #endif internal extension OCKStore { - + enum Tasks: String, CaseIterable { case doxylamine case nausea case kegels } - + enum Contacts: String, CaseIterable { case jane case matthew } - + // Adds tasks and contacts into the store func populateSampleData() { - + let thisMorning = Calendar.current.startOfDay(for: Date()) let beforeBreakfast = Calendar.current.date(byAdding: .hour, value: 8, to: thisMorning)! let afterLunch = Calendar.current.date(byAdding: .hour, value: 14, to: thisMorning)! - + let schedule = OCKSchedule(composing: [ OCKScheduleElement(start: beforeBreakfast, end: nil, interval: DateComponents(day: 1)), - + OCKScheduleElement(start: afterLunch, end: nil, interval: DateComponents(day: 2)) ]) - + var doxylamine = OCKTask(id: Tasks.doxylamine.rawValue, title: "Take Doxylamine", carePlanUUID: nil, schedule: schedule) doxylamine.instructions = "Take 25mg of doxylamine when you experience nausea." @@ -76,20 +76,20 @@ internal extension OCKStore { OCKScheduleElement(start: beforeBreakfast, end: nil, interval: DateComponents(day: 1), text: "Anytime throughout the day", targetValues: [], duration: .allDay) ]) - + var nausea = OCKTask(id: Tasks.nausea.rawValue, title: "Track your nausea", carePlanUUID: nil, schedule: nauseaSchedule) nausea.impactsAdherence = false nausea.instructions = "Tap the button below anytime you experience nausea." - + let kegelElement = OCKScheduleElement(start: beforeBreakfast, end: nil, interval: DateComponents(day: 2)) let kegelSchedule = OCKSchedule(composing: [kegelElement]) var kegels = OCKTask(id: Tasks.kegels.rawValue, title: "Kegel Exercises", carePlanUUID: nil, schedule: kegelSchedule) kegels.impactsAdherence = true kegels.instructions = "Perform kegel exercies" - + addTasks([nausea, doxylamine, kegels], callbackQueue: .main, completion: nil) - + var contact1 = OCKContact(id: Contacts.jane.rawValue, givenName: "Jane", familyName: "Daniels", carePlanUUID: nil) contact1.asset = "JaneDaniels" @@ -98,7 +98,7 @@ internal extension OCKStore { contact1.emailAddresses = [OCKLabeledValue(label: CNLabelEmailiCloud, value: "janedaniels@icloud.com")] contact1.phoneNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(324) 555-7415")] contact1.messagingNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(324) 555-7415")] - + contact1.address = { let address = OCKPostalAddress() address.street = "2598 Reposa Way" @@ -107,7 +107,7 @@ internal extension OCKStore { address.postalCode = "94127" return address }() - + var contact2 = OCKContact(id: Contacts.matthew.rawValue, givenName: "Matthew", familyName: "Reiff", carePlanUUID: nil) contact2.asset = "MatthewReiff" @@ -123,19 +123,19 @@ internal extension OCKStore { address.postalCode = "94127" return address }() - + addContacts([contact1, contact2]) } } extension OCKHealthKitPassthroughStore { -#if HEALTH + #if HEALTH func populateSampleData() { - + let schedule = OCKSchedule.dailyAtTime( hour: 8, minutes: 0, start: Date(), end: nil, text: nil, duration: .hours(12), targetValues: [OCKOutcomeValue(2000.0, units: "Steps")]) - + let steps = OCKHealthKitTask( id: "steps", title: "Steps", @@ -145,7 +145,7 @@ extension OCKHealthKitPassthroughStore { quantityIdentifier: .stepCount, quantityType: .cumulative, unit: .count())) - + addTasks([steps]) { result in switch result { case .success: @@ -155,28 +155,26 @@ extension OCKHealthKitPassthroughStore { } } } -#endif + #endif } - - #if DEBUG extension OTFCloudantStore { // Adds tasks and contacts into the store func populateSampleData() { - + let thisMorning = Calendar.current.startOfDay(for: Date()) let aFewDaysAgo = Calendar.current.date(byAdding: .day, value: -4, to: thisMorning)! let beforeBreakfast = Calendar.current.date(byAdding: .hour, value: 8, to: aFewDaysAgo)! let afterLunch = Calendar.current.date(byAdding: .hour, value: 14, to: aFewDaysAgo)! - + let schedule = OCKSchedule(composing: [ OCKScheduleElement(start: beforeBreakfast, end: nil, interval: DateComponents(day: 1)), - + OCKScheduleElement(start: afterLunch, end: nil, interval: DateComponents(day: 2)) ]) - + var doxylamine = OCKTask(id: "doxylamine", title: "Take Doxylamine", carePlanUUID: nil, schedule: schedule) doxylamine.instructions = "Take 25mg of doxylamine when you experience nausea." @@ -185,43 +183,43 @@ extension OTFCloudantStore { OCKScheduleElement(start: beforeBreakfast, end: nil, interval: DateComponents(day: 1), text: "Anytime throughout the day", targetValues: [], duration: .allDay) ]) - + var nausea = OCKTask(id: "nausea", title: "Track your nausea", carePlanUUID: nil, schedule: nauseaSchedule) nausea.impactsAdherence = false nausea.instructions = "Tap the button below anytime you experience nausea." - + let kegelElement = OCKScheduleElement(start: beforeBreakfast, end: nil, interval: DateComponents(day: 2)) let kegelSchedule = OCKSchedule(composing: [kegelElement]) var kegels = OCKTask(id: "kegels", title: "Kegel Exercises", carePlanUUID: nil, schedule: kegelSchedule) kegels.impactsAdherence = true kegels.instructions = "Perform kegel exercies" - + let checkInSchedule = OCKSchedule.dailyAtTime( hour: 8, minutes: 0, start: Date(), end: nil, text: nil ) - + let checkInTask = OCKTask( id: "checkIn", title: "Check In", carePlanUUID: nil, schedule: checkInSchedule ) - + let nextWeek = Calendar.current.date( byAdding: .weekOfYear, value: 1, to: Date() )! - + let nextMonth = Calendar.current.date( byAdding: .month, value: 1, to: thisMorning ) - + let dailyElement = OCKScheduleElement( start: thisMorning, end: nextWeek, @@ -230,7 +228,7 @@ extension OTFCloudantStore { targetValues: [], duration: .allDay ) - + let weeklyElement = OCKScheduleElement( start: nextWeek, end: nextMonth, @@ -239,21 +237,21 @@ extension OTFCloudantStore { targetValues: [], duration: .allDay ) - + let rangeOfMotionCheckSchedule = OCKSchedule( composing: [dailyElement, weeklyElement] ) - + let rangeOfMotionCheckTask = OCKTask( id: "rangeOfMotionCheck", title: "Range Of Motion", carePlanUUID: nil, schedule: rangeOfMotionCheckSchedule ) - + addAnyTasks([nausea, doxylamine, kegels, checkInTask, rangeOfMotionCheckTask], callbackQueue: .main, completion: nil) - + var contact1 = OCKContact(id: "jane", givenName: "Jane", familyName: "Daniels", carePlanUUID: nil) contact1.asset = "JaneDaniels" @@ -262,7 +260,7 @@ extension OTFCloudantStore { contact1.emailAddresses = [OCKLabeledValue(label: CNLabelEmailiCloud, value: "janedaniels@icloud.com")] contact1.phoneNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(324) 555-7415")] contact1.messagingNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(324) 555-7415")] - + contact1.address = { let address = OCKPostalAddress() address.street = "2598 Reposa Way" @@ -271,7 +269,7 @@ extension OTFCloudantStore { address.postalCode = "94127" return address }() - + var contact2 = OCKContact(id: "matthew", givenName: "Matthew", familyName: "Reiff", carePlanUUID: nil) contact2.asset = "MatthewReiff" @@ -287,10 +285,10 @@ extension OTFCloudantStore { address.postalCode = "94127" return address }() - + addContacts([contact1, contact2]) } - + @discardableResult func convertUserToPatient(user: Response.User) -> OCKPatient? { var patient = OCKPatient(id: user.id, givenName: user.firstName ?? "", familyName: user.lastName ?? "") patient.uuid = UUID() @@ -302,7 +300,7 @@ extension OTFCloudantStore { } } -extension CareKitManager { +extension CareKitStoreManager { func populateSampleData() { OCKStoreManager.shared.coreDataStore.fetchTasks { result in switch result { @@ -324,7 +322,7 @@ extension OTFCloudantStore { completion(.failure(.fetchFailed(reason: "User not logged in."))) return } - CareKitManager.shared.cloudantStore?.fetchPatient(withID: user.id, completion: { result in + CareKitStoreManager.shared.cloudantStore?.fetchPatient(withID: user.id, completion: { result in completion(result) }) } diff --git a/OTFMagicBox/Onboarding/OnboardingItemView.swift b/OTFMagicBox/Onboarding/OnboardingItemView.swift index be033e5a..7296fcb7 100644 --- a/OTFMagicBox/Onboarding/OnboardingItemView.swift +++ b/OTFMagicBox/Onboarding/OnboardingItemView.swift @@ -1,48 +1,48 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI /// The onboarding items view elements. struct OnboardingItemView: View { - + /// The onboarding items view controller. var viewControllers: [UIHostingController] - + /// The current onboarding item. @State var currentOnboardingItem = 0 - + /// Creates the onboarding item view. init(_ views: [OnboardingItem]) { self.viewControllers = views.map { @@ -61,20 +61,20 @@ struct OnboardingItemView: View { OnboardingItemControl(numberOfOnboardingItems: viewControllers.count, currentOnboardingItem: $currentOnboardingItem) .background(Color.clear) .offset(x: 0, y: -80) - + } } .ignoresSafeArea() } - + } /// The onboarding items view controller. struct OnboardingItemViewController: UIViewControllerRepresentable { - + /// The controllers for the onboarding items. var controllers: [UIViewController] - + /// The current page. @Binding var currentPage: Int @@ -100,7 +100,7 @@ struct OnboardingItemViewController: UIViewControllerRepresentable { /// Documentation is in UIViewControllerRepresentable. func updateUIViewController(_ onboardingItemViewController: UIPageViewController, context: Context) { onboardingItemViewController.setViewControllers( - [self.controllers[self.currentPage]], direction: .forward, animated: true) + [self.controllers[self.currentPage]], direction: .forward, animated: true) } class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate { @@ -109,10 +109,9 @@ struct OnboardingItemViewController: UIViewControllerRepresentable { var parent: OnboardingItemViewController /// Creates onboarding items view controller. - init(_ OnboardingItemViewController: OnboardingItemViewController) { - self.parent = OnboardingItemViewController + init(_ onboardingItemViewController: OnboardingItemViewController) { + self.parent = onboardingItemViewController } - /// Documentation is in UIPageViewControllerDataSource. func pageViewController( _ pageViewController: UIPageViewController, @@ -125,7 +124,7 @@ struct OnboardingItemViewController: UIViewControllerRepresentable { } return parent.controllers[index - 1] } - + /// Documentation is in UIPageViewControllerDataSource. func pageViewController( _ pageViewController: UIPageViewController, @@ -142,8 +141,8 @@ struct OnboardingItemViewController: UIViewControllerRepresentable { /// Documentation is in UIPageViewControllerDelegate. func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { if completed, - let visibleViewController = pageViewController.viewControllers?.first, - let index = parent.controllers.firstIndex(of: visibleViewController) { + let visibleViewController = pageViewController.viewControllers?.first, + let index = parent.controllers.firstIndex(of: visibleViewController) { parent.currentPage = index } } @@ -152,13 +151,13 @@ struct OnboardingItemViewController: UIViewControllerRepresentable { /// The onboarding item control. struct OnboardingItemControl: UIViewRepresentable { - + /// The number of onboarding items. var numberOfOnboardingItems: Int - + /// The current onboarding item. @Binding var currentOnboardingItem: Int - + /// Documentation is in UIViewRepresentable. func makeCoordinator() -> Coordinator { Coordinator(self) @@ -185,7 +184,7 @@ struct OnboardingItemControl: UIViewRepresentable { } class Coordinator: NSObject { - + /// Control of the onboarding item controller. var control: OnboardingItemControl @@ -193,7 +192,7 @@ struct OnboardingItemControl: UIViewRepresentable { init(_ control: OnboardingItemControl) { self.control = control } - + /// Updates the on boarding item. @objc func updateCurrentOnboardingItem(sender: UIPageControl) { control.currentOnboardingItem = sender.currentPage diff --git a/OTFMagicBox/Onboarding/OnboardingOptionsViewController.swift b/OTFMagicBox/Onboarding/OnboardingOptionsViewController.swift index 80af8984..69593e94 100644 --- a/OTFMagicBox/Onboarding/OnboardingOptionsViewController.swift +++ b/OTFMagicBox/Onboarding/OnboardingOptionsViewController.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -40,43 +40,43 @@ import OTFUtilities import Combine public class OnboardingOptionsStep: ORKQuestionStep { - public override init( + override public init( identifier: String ) { super.init(identifier: identifier) self.answerFormat = ORKAnswerFormat.booleanAnswerFormat() } - + @available(*, unavailable) public required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + } public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASAuthorizationControllerDelegate { let authType: AuthType var disposables: AnyCancellable? - - public var CKMultipleSignInStep: OnboardingOptionsStep!{ + + public var CKMultipleSignInStep: OnboardingOptionsStep! { return step as? OnboardingOptionsStep } - + init(authType: AuthType, step: ORKStep?) { self.authType = authType - + super.init(step: step) } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - - public override func viewDidLoad() { - + + override public func viewDidLoad() { + setupViews() } - + public func customButton( title: String, backGroundColor: UIColor, @@ -89,27 +89,27 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA ) -> UIButton { let button = UIButton(frame: CGRect(x: 200, y: 200, width: 350, height: 50)) button.setTitle(title, for: .normal) - - button.setTitleColor(textColor,for: .normal) - button.addTarget(self,action: action,for: .touchUpInside) + + button.setTitleColor(textColor, for: .normal) + button.addTarget(self, action: action, for: .touchUpInside) button.layer.cornerRadius = 10 button.backgroundColor = backGroundColor - + if let borderColor=borderColor { button.layer.borderWidth = 2 button.layer.borderColor = borderColor.cgColor } - - if (image != "") { + + if !image.isEmpty { button.setImage(UIImage(named: image), for: .normal) button.imageEdgeInsets.left = -imageOffset } - + return button } - + private func setupViews() { - + let verticalStack = UIStackView() verticalStack.translatesAutoresizingMaskIntoConstraints = false verticalStack.spacing = 10 @@ -117,11 +117,11 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA verticalStack.distribution = .fillEqually verticalStack.backgroundColor = .clear view.addSubview(verticalStack) - + var stackViewHeight = CGFloat(0) - + let config = ModuleAppYmlReader() - + if YmlReader().showAppleLogin { stackViewHeight += 60 let buttonApple = customButton(title: Constants.CustomiseStrings.signinWithApple, backGroundColor: .black, textColor: .white, borderColor: nil, @@ -129,7 +129,7 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA buttonApple.translatesAutoresizingMaskIntoConstraints = false verticalStack.addArrangedSubview(buttonApple) } - + if YmlReader().showGoogleLogin { stackViewHeight += 60 let buttonGoogle = customButton(title: Constants.CustomiseStrings.signinWithGoogle, backGroundColor: .white, textColor: .black, @@ -138,14 +138,14 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA buttonGoogle.translatesAutoresizingMaskIntoConstraints = false verticalStack.addArrangedSubview(buttonGoogle) } - + stackViewHeight += 50 let buttonUserPassWord = customButton(title: Constants.CustomiseStrings.signinWithEmail, backGroundColor: .white, textColor: .black, borderColor: .black, reference: nil, action: #selector(loginEmailAndPaswwordAction)) buttonUserPassWord.translatesAutoresizingMaskIntoConstraints = false verticalStack.addArrangedSubview(buttonUserPassWord) - - ///Sign in label + + /// Sign in label let signInLabel = UILabel(frame: CGRect(x: 0, y: 320, width: 450, height: 50 )) signInLabel.translatesAutoresizingMaskIntoConstraints = false signInLabel.center.x = view.center.x @@ -156,13 +156,12 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA signInLabel.textAlignment = NSTextAlignment.center signInLabel.numberOfLines = 4 self.view.addSubview(signInLabel) - + var optionsIcon: UIImage? if let image = UIImage(systemName: config.loginOptionsIcon) { optionsIcon = image - } - else { + } else { optionsIcon = UIImage(systemName: Constants.YamlDefaults.LoginOptionsIcon) } @@ -173,35 +172,35 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA iconImage.contentMode = .scaleAspectFit iconImage.center.x = view.center.x view.addSubview(iconImage) - + NSLayoutConstraint.activate([ iconImage.centerXAnchor.constraint(equalTo: view.centerXAnchor), iconImage.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), iconImage.heightAnchor.constraint(equalToConstant: 120), iconImage.widthAnchor.constraint(equalToConstant: 120), - + signInLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), signInLabel.topAnchor.constraint(equalTo: iconImage.bottomAnchor), signInLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), signInLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - + verticalStack.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), verticalStack.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), verticalStack.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20), verticalStack.heightAnchor.constraint(equalToConstant: stackViewHeight) ]) - + self.view.backgroundColor = .white } - + @objc func loginEmailAndPaswwordAction() { self.setAnswer(true) super.goForward() } - + private var currentNonce: String! - + @objc func loginAppleAction() { currentNonce = .makeRandomNonce() @@ -209,12 +208,12 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA let request = appleIDProvider.createRequest() request.requestedScopes = [.email] request.nonce = currentNonce.sha256 - + let authorizationController = ASAuthorizationController(authorizationRequests: [request]) authorizationController.delegate = self authorizationController.performRequests() } - + public func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential else { @@ -225,7 +224,7 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA OTFLog("Unable to fetch identity token") return } - + // We are using this identity token to get other required fields e.g. email of the user. // The JWT token's payload is decided by Apple itself. We should be cautious that Apple // may change the format/composition of the token in the future. @@ -233,20 +232,18 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA OTFLog("Unable to serialize token string from data:", appleIDToken.debugDescription) return } - + let alert = UIAlertController(title: nil, message: authType == .login ? Constants.CustomiseStrings.signingIn : Constants.CustomiseStrings.signingUp, preferredStyle: .alert) - + let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50)) loadingIndicator.hidesWhenStopped = true loadingIndicator.style = UIActivityIndicatorView.Style.medium loadingIndicator.startAnimating() alert.view.addSubview(loadingIndicator) - + taskViewController?.present(alert, animated: true) - - disposables = OTFTheraforgeNetwork.shared.socialLoginRequest(userType: .patient, socialType: .apple, authType: authType, idToken: idTokenString) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { response in @@ -257,51 +254,48 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA self.showAlert(title: "Ok", message: error.error.message) self.showError(error) } - default: break; + default: break } - }, receiveValue: { result in + }, receiveValue: { _ in alert.dismiss(animated: true, completion: nil) self.setAnswer(false) super.goForward() }) } - + @objc func loginGoogleAction() { - + GIDSignIn.sharedInstance.signIn(withPresenting: self) { user, error in - + if let error = error { self.showError(error) return } - + // If sign in succeeded, display the app's main content View. - + guard let user = user?.user, let idToken = user.idToken?.tokenString else { self.showError(ForgeError.empty) return } - + self.signInToTheraForgeWith(idToken: idToken) } } - + func signInToTheraForgeWith(idToken: String) { let alert = UIAlertController(title: nil, message: authType == .login ? Constants.CustomiseStrings.signingIn : Constants.CustomiseStrings.signingUp, preferredStyle: .alert) - + let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50)) loadingIndicator.hidesWhenStopped = true loadingIndicator.style = UIActivityIndicatorView.Style.medium loadingIndicator.startAnimating() alert.view.addSubview(loadingIndicator) - + taskViewController?.present(alert, animated: true) - - - disposables = OTFTheraforgeNetwork.shared.socialLoginRequest(userType: .patient, socialType: .gmail, authType: authType, idToken: idToken) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { response in @@ -312,15 +306,15 @@ public class OnboardingOptionsViewController: ORKQuestionStepViewController, ASA self.showAlert(title: Constants.CustomiseStrings.okay, message: error.error.message) self.showError(error) } - default: break; + default: break } - }, receiveValue: { result in + }, receiveValue: { _ in alert.dismiss(animated: true, completion: nil) self.setAnswer(false) super.goForward() }) } - + private func showError(_ error: Error) { // with your request to Google. Alerts.showInfo( @@ -338,14 +332,14 @@ fileprivate extension String { .compactMap { String(format: "%02x", $0) } .joined() } - + /// Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce static func makeRandomNonce(ofLength length: Int = 32) -> String { precondition(length > 0) let charset = Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._") var result = "" var remainingLength = length - + while remainingLength > 0 { let randoms: [UInt8] = (0 ..< 16).map { _ in var random: UInt8 = 0 @@ -355,12 +349,12 @@ fileprivate extension String { } return random } - + for random in randoms { if remainingLength == 0 { break } - + if random < charset.count { result.append(charset[Int(random)]) remainingLength -= 1 diff --git a/OTFMagicBox/Onboarding/OnboardingTaskCoordinator.swift b/OTFMagicBox/Onboarding/OnboardingTaskCoordinator.swift index 72e2eb8e..393e97f7 100644 --- a/OTFMagicBox/Onboarding/OnboardingTaskCoordinator.swift +++ b/OTFMagicBox/Onboarding/OnboardingTaskCoordinator.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -36,18 +36,19 @@ import OTFResearchKit import OTFUtilities import Combine import Sodium +import OTFCloudClientAPI final class OnboardingTaskCoordinator: NSObject { - + let authType: AuthType var disposeables: AnyCancellable? let documentManager = UploadDocumentManager() let swiftSodium = SwiftSodium() - + /// Change this value to true when registration step completes successfully private var registrationCompleted = false private var navigationDirection = ORKStepViewControllerNavigationDirection.forward - + init(authType: AuthType) { self.authType = authType } @@ -58,76 +59,88 @@ extension OnboardingTaskCoordinator: ORKTaskViewControllerDelegate { guard authType == .signup else { return true } - + let config = ModuleAppYmlReader() - + var checkRegistrationStatusFirst = false if config.isPasscodeEnabled, step.identifier == Constants.Identifier.PasscodeStep { checkRegistrationStatusFirst = true - } - else if step.identifier == Constants.Identifier.CompletionStep { + } else if step.identifier == Constants.Identifier.CompletionStep { checkRegistrationStatusFirst = true } - + if checkRegistrationStatusFirst, navigationDirection == .forward, !registrationCompleted { let stepResult = taskViewController.result.stepResult(forStepIdentifier: Constants.Registration.Identifier) - + let emailRes = stepResult?.results?.first as? ORKTextQuestionResult guard let email = emailRes?.textAnswer else { return false } - + let passwordRes = stepResult?.results?[1] as? ORKTextQuestionResult guard let pass = passwordRes?.textAnswer else { return false } let givenName = stepResult?.results?[3] as? ORKTextQuestionResult let familyName = stepResult?.results?[4] as? ORKTextQuestionResult - + let genderResult = stepResult?.results?[5] as? ORKChoiceQuestionResult let dobResult = stepResult?.results?[6] as? ORKDateQuestionResult - + guard let gender = genderResult?.choiceAnswers?.first as? String else { return false } - + guard let dob = dobResult?.dateAnswer?.toString else { return false } - + let masterKey = swiftSodium.generateMasterKey(password: pass, email: email) - + guard let keyPair = swiftSodium.sodium.box.keyPair(seed: masterKey) else { return false } - - let encryptkey : Bytes? = swiftSodium.encryptKey(bytes: masterKey, publicKey: keyPair.publicKey) - + + let encryptkey: Bytes? = swiftSodium.encryptKey(bytes: masterKey, publicKey: keyPair.publicKey) + guard let encryptedMasterKey = encryptkey else { return false } - + let defaultStorageKey = swiftSodium.generateDefaultStorageKey(masterKey: masterKey) let confidentialStorageKey = swiftSodium.generateConfidentialStorageKey(masterKey: masterKey) - + let encryptedDefaultStorageKey = swiftSodium.encryptKey(bytes: defaultStorageKey, publicKey: keyPair.publicKey) let encryptedconfidentialStorageKey = swiftSodium.encryptKey(bytes: confidentialStorageKey, publicKey: keyPair.publicKey) - + let encryptedDefaultStorageKeyHex = encryptedDefaultStorageKey.bytesToHex(spacing: "").lowercased() let encryptedconfidentialStorageKeyHex = encryptedconfidentialStorageKey.bytesToHex(spacing: "").lowercased() let encryptedMasterKeyHex = encryptedMasterKey.bytesToHex(spacing: "").lowercased() let publicKeyHex = keyPair.publicKey.bytesToHex(spacing: "").lowercased() - + let alert = UIAlertController(title: nil, message: Constants.CustomiseStrings.creatingAccount, preferredStyle: .alert) let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50)) loadingIndicator.hidesWhenStopped = true loadingIndicator.style = UIActivityIndicatorView.Style.medium loadingIndicator.startAnimating() - + alert.view.addSubview(loadingIndicator) taskViewController.present(alert, animated: false, completion: nil) - - disposeables = OTFTheraforgeNetwork.shared.signUpRequest(firstName: givenName?.textAnswer ?? Constants.patientFirstName, lastName: familyName?.textAnswer ?? Constants.patientLastName, type: Constants.userType, email: email, password: pass, dob: dob, gender: gender, encryptedMasterKey: encryptedMasterKeyHex, publicKey: publicKeyHex, encryptedDefaultStorageKey: encryptedDefaultStorageKeyHex, encryptedConfidentialStorageKey: encryptedconfidentialStorageKeyHex) + let signup = OTFCloudClientAPI.Request.SignUp( + email: email, + password: pass, + first_name: givenName?.textAnswer ?? Constants.patientFirstName, + last_name: familyName?.textAnswer ?? Constants.patientLastName, + type: .patient, + dob: dob, + gender: gender, + phoneNo: "", + encryptedMasterKey: encryptedMasterKeyHex, + publicKey: publicKeyHex, + encryptedDefaultStorageKey: encryptedDefaultStorageKeyHex, + encryptedConfidentialStorageKey: encryptedconfidentialStorageKeyHex) + disposeables = OTFTheraforgeNetwork.shared.signUpRequest( + signupRequest: signup) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { response in switch response { @@ -138,70 +151,81 @@ extension OnboardingTaskCoordinator: ORKTaskViewControllerDelegate { alert.addAction(UIAlertAction(title: Constants.CustomiseStrings.okay, style: .cancel)) taskViewController.present(alert, animated: false) } - default: break; + default: break } }, receiveValue: { result in OTFLog("Successfully revrived", result.message ?? "") alert.dismiss(animated: false) { - KeychainCloudManager.saveValuesInKeychain(email: email, password: pass, masterKey: masterKey, publicKey: keyPair.publicKey, secretKey: keyPair.secretKey, defaultStorageKey: defaultStorageKey, confidentialStorageKey: confidentialStorageKey) + KeychainCloudManager.saveUserKeys( + masterKey: masterKey, + publicKey: keyPair.publicKey, + secretKey: keyPair.secretKey, + defaultStorageKey: defaultStorageKey, + confidentialStorageKey: confidentialStorageKey) self.registrationCompleted = true taskViewController.goForward() } }) - + return false } - + return true } - - func generateMasterKey(email: String, password: String) -> Array { + + func generateMasterKey(email: String, password: String) -> [UInt8] { let masterKey = swiftSodium.generateMasterKey(password: KeychainCloudManager.getPassword, email: KeychainCloudManager.getEmailAddress) return masterKey } - + func taskViewController(_ taskViewController: ORKTaskViewController, stepViewControllerWillDisappear stepViewController: ORKStepViewController, navigationDirection direction: ORKStepViewControllerNavigationDirection) { navigationDirection = direction } - - public func taskViewController(_ taskViewController: ORKTaskViewController, - didFinishWith reason: ORKTaskViewControllerFinishReason, error: Error?) { + + public func taskViewController( + _ taskViewController: ORKTaskViewController, + didFinishWith reason: ORKTaskViewControllerFinishReason, + error: Error?) { switch reason { case .completed: - + DispatchQueue.main.async { UserDefaultsManager.setOnboardingCompleted(true) NotificationCenter.default.post(name: .onboardingDidComplete, object: true) } - + if let signatureResult = taskViewController.result.stepResult(forStepIdentifier: "ConsentReviewStep")?.results?.first as? ORKConsentSignatureResult { - + let consentDocument = ConsentDocument() signatureResult.apply(to: consentDocument) - + consentDocument.makePDF { (data, error) -> Void in - + var docURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last as NSURL? docURL = docURL?.appendingPathComponent("\(ModuleAppYmlReader().consentFileName).pdf") as NSURL? - + do { let url = docURL! as URL - - self.documentManager.encryptDocument(document: data!, fileName: "\(ModuleAppYmlReader().consentFileName).pdf") - + if KeychainCloudManager.isKeyStored(key: KeychainKeys.defaultStorageKey) && + KeychainCloudManager.isKeyStored(key: KeychainKeys.defaultStorageKey) { + self.documentManager.encryptDocument(document: data!, fileName: "\(ModuleAppYmlReader().consentFileName).pdf") + } else { + self.documentManager.uploadFile(data: data!, fileName: "\(ModuleAppYmlReader().consentFileName).pdf", encryptedFileKey: "", hashFileKey: "") + } + try data?.write(to: url) - + UserDefaults.standard.set(url.path, forKey: Constants.UserDefaults.ConsentDocumentURL) - + } catch let error { OTFError("error in writting data in pdf %{public}@", error.localizedDescription) } } } fallthrough - + default: // Dismiss onboarding without proceeding. DispatchQueue.main.async { @@ -209,7 +233,7 @@ extension OnboardingTaskCoordinator: ORKTaskViewControllerDelegate { } } } - + func taskViewController(_ taskViewController: ORKTaskViewController, viewControllerFor step: ORKStep) -> ORKStepViewController? { switch step { @@ -223,5 +247,5 @@ extension OnboardingTaskCoordinator: ORKTaskViewControllerDelegate { return nil } } - + } diff --git a/OTFMagicBox/Onboarding/OnboardingView.swift b/OTFMagicBox/Onboarding/OnboardingView.swift index 1e1ac4a2..a734ebb1 100644 --- a/OTFMagicBox/Onboarding/OnboardingView.swift +++ b/OTFMagicBox/Onboarding/OnboardingView.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -38,33 +38,36 @@ import OTFUtilities /// The onboarding view. struct OnboardingView: View { - + /// The list of the onboarding view elements. let color: Color var onboardingElements: [Onboarding] = [] - var onComplete: (() -> Void)? = nil - + var onComplete: (() -> Void)? + @State var showingOnboard = false @State var showingLogin = false - + @State private var selectedAuthMethod = AuthMethod.email - + /// Creates the on boarding view. init(onComplete: (() -> Void)? = nil) { - - // TODO: Add the actual default image, if the user doesnt enter any image. let config = ModuleAppYmlReader() let onboardingdata: [Onboarding] = { - config.onboardingData ?? [Onboarding(image: Constants.CustomiseStrings.splashImage, icon: Constants.CustomiseStrings.splashIcon, title: Constants.CustomiseStrings.welcome, color: "black", description: Constants.CustomiseStrings.defaultDescription)] + config.onboardingData ?? [Onboarding( + image: Constants.CustomiseStrings.splashImage, + icon: Constants.CustomiseStrings.splashIcon, + title: Constants.CustomiseStrings.welcome, + color: "black", + description: Constants.CustomiseStrings.defaultDescription)] }() - + onboardingElements = onboardingdata - + self.color = Color(config.primaryColor) - + self.onComplete = onComplete } - + /// Onboarding view. var body: some View { ZStack { @@ -74,11 +77,11 @@ struct OnboardingView: View { description: $0.description, color: Color($0.color.color ?? .black)) }) - + GeometryReader { geometry in VStack { Spacer() - + HStack { Button(action: { self.showingOnboard = true @@ -89,17 +92,17 @@ struct OnboardingView: View { .foregroundColor(.white) .background(self.color) .cornerRadius(Metrics.RADIUS_CORNER_BUTTON) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(Font.otfAppFont) }) .padding(.leading, Metrics.PADDING_HORIZONTAL_BUTTON) .padding(.trailing, Metrics.PADDING_HORIZONTAL_BUTTON / 2) - + Button(action: { self.showingLogin = true }, label: { Text(Constants.CustomiseStrings.signIn) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) .frame(maxWidth: .infinity) .padding(.vertical, Metrics.PADDING_VERTICAL_ROW) .foregroundColor(.white) @@ -109,7 +112,7 @@ struct OnboardingView: View { .padding(.trailing, Metrics.PADDING_HORIZONTAL_BUTTON) .padding(.leading, Metrics.PADDING_HORIZONTAL_BUTTON / 2) } - + Spacer() .frame(height: geometry.safeAreaInsets.bottom > 0 ? 0 : Metrics.BOTTOM_SPACER) } @@ -134,22 +137,22 @@ struct OnboardingView: View { /// The onboarding detailed view. struct OnboardingDetailsView: View { - + /// Image of the onboarding item. let icon: String - + /// Image of the onboarding item. let image: String - + /// Title of the onboarding item. let title: String - + /// Description of the onboarding item. let description: String - + /// Color of the onboarding item. let color: Color - + /// Onboarding detailed view. var body: some View { ZStack { @@ -157,7 +160,7 @@ struct OnboardingDetailsView: View { .resizable() .ignoresSafeArea() .accessibilityHidden(true) - + VStack { Image(systemName: icon) .imageScale(.large) @@ -166,15 +169,15 @@ struct OnboardingDetailsView: View { .padding(.top, Metrics.PADDING_VERTICAL_BUTTON * 2) .padding(.bottom, Metrics.PADDING_VERTICAL_BUTTON) .accessibilityHidden(true) - + Text(title) .multilineTextAlignment(.center) - .font(YmlReader().appTheme?.appTitleSize.appFont ?? Constants.YamlDefaults.AppTitleSize.appFont) + .font(YmlReader().appStyle.appTitleSize.appFont ?? Constants.YamlDefaults.AppTitleSize.appFont) .foregroundColor(color) .shadow(color: .black, radius: 15) .padding([.horizontal, .bottom], Metrics.PADDING_VERTICAL_BUTTON) - + Text(description) .multilineTextAlignment(.center) .font(.body) @@ -182,13 +185,13 @@ struct OnboardingDetailsView: View { .shadow(radius: 5) .padding(.horizontal, Metrics.PADDING_HORIZONTAL_BUTTON) - + Spacer() } .frame(maxWidth: .infinity) } } - + } struct OnboardingView_Previews: PreviewProvider { @@ -196,4 +199,3 @@ struct OnboardingView_Previews: PreviewProvider { OnboardingView() } } - diff --git a/OTFMagicBox/Onboarding/OnboardingViewController.swift b/OTFMagicBox/Onboarding/OnboardingViewController.swift index 3e8304b8..39da5c89 100644 --- a/OTFMagicBox/Onboarding/OnboardingViewController.swift +++ b/OTFMagicBox/Onboarding/OnboardingViewController.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -42,56 +42,61 @@ import OTFCareKitStore User activities to create a Digital Health Application. */ struct OnboardingViewController: UIViewControllerRepresentable { - + func makeCoordinator() -> OnboardingTaskCoordinator { OnboardingTaskCoordinator(authType: .signup) } - + typealias UIViewControllerType = ORKTaskViewController - + func updateUIViewController(_ taskViewController: ORKTaskViewController, context: Context) {} - + func makeUIViewController(context: Context) -> ORKTaskViewController { let config = ModuleAppYmlReader() - + // * STEP (1): get user consent // use the `ORKVisualConsentStep` from ResearchKit let consentDocument = ConsentDocument() let consentStep = ORKVisualConsentStep(identifier: "VisualConsentStep", document: consentDocument) - + // * STEP (2): ask user to review and sign consent document // use the `ORKConsentReviewStep` from ResearchKit let signature = consentDocument.signatures?.first let reviewConsentStep = ORKConsentReviewStep(identifier: "ConsentReviewStep", signature: signature, in: consentDocument) reviewConsentStep.text = YmlReader().teamWebsite reviewConsentStep.reasonForConsent = config.reasonForConsentText - + // * STEP (3): ask user to enter their email address for login // the `LoginStep` collects and email address, and // the `LoginCustomWaitStep` waits for email verification. var loginSteps: [ORKStep] let signInButtons = OnboardingOptionsStep(identifier: "SignInButtons") - + var regOption = ORKRegistrationStepOption() - + if config.showDateOfBirth { regOption.insert(.includeDOB) } - + if config.showGender { regOption.insert(.includeGender) } regOption.insert( .includeGivenName) regOption.insert( .includeFamilyName) - let regexp = try! NSRegularExpression(pattern: "^.{10,}$") - + let regexp: NSRegularExpression + do { + regexp = try NSRegularExpression(pattern: "^.{10,}$") + } catch { + fatalError("Unable to create regular expression") + } + let registerStep = ORKRegistrationStep(identifier: Constants.Registration.Identifier, title: Constants.CustomiseStrings.registration, text: Constants.CustomiseStrings.studySignup, passcodeValidationRegularExpression: regexp, passcodeInvalidMessage: Constants.CustomiseStrings.notMeetCriteria, options: regOption) loginSteps = [signInButtons, registerStep] - + // * STEP (4): ask the user to create a security passcode // * that will be required to use this app! // use the `ORKPasscodeStep` from ResearchKit. @@ -105,21 +110,21 @@ struct OnboardingViewController: UIViewControllerRepresentable { } else { passcodeStep.passcodeType = .type4Digit } - + loginSteps += [passcodeStep] } - + // * STEP (5.1): get permission to collect HealthKit data // see `HealthDataStep` to configure! -// #if HEALTH || CAREHEALTH + // #if HEALTH || CAREHEALTH let healthDataStep = HealthDataStep(identifier: "Healthkit") - + // * STEP (5.2): get permission to collect HealthKit health records data let healthRecordsStep = HealthRecordsStep(identifier: "HealthRecords") - + loginSteps += [healthDataStep, healthRecordsStep] -// #endif - + // #endif + // * STEP (6): inform the user that they are done with sign-up! // use the `ORKCompletionStep` from ResearchKit // to set completion step @@ -127,11 +132,11 @@ struct OnboardingViewController: UIViewControllerRepresentable { completionStep.title = config.completionStepTitle completionStep.text = config.completionStepText loginSteps += [completionStep] - + // * finally, CREATE an array with the steps to show the user // given intro steps that the user should review and consent to let introSteps: [ORKStep] = [consentStep, reviewConsentStep] - + // guide the user through ALL steps let fullSteps: [ORKStep] if UserDefaultsManager.isConsentDocumentViewed { @@ -140,11 +145,11 @@ struct OnboardingViewController: UIViewControllerRepresentable { UserDefaultsManager.setIsConsentDocumentViewed(true) fullSteps = introSteps + loginSteps } - + // * and SHOW the user these steps! // create a task with each step let navigableTask = ORKNavigableOrderedTask(identifier: "StudyOnboardingTask", steps: fullSteps) - + let resultSelector = ORKResultSelector(resultIdentifier: "SignInButtons") let booleanAnswerType = ORKResultPredicate.predicateForBooleanQuestionResult(with: resultSelector, expectedAnswer: true) let predicateRule = ORKPredicateStepNavigationRule(resultPredicates: [booleanAnswerType], @@ -152,13 +157,13 @@ struct OnboardingViewController: UIViewControllerRepresentable { defaultStepIdentifier: "Passcode", validateArrays: true) navigableTask.setNavigationRule(predicateRule, forTriggerStepIdentifier: "SignInButtons") - + // wrap that task on a view controller let taskViewController = ORKTaskViewController(task: navigableTask, taskRun: nil) taskViewController.delegate = context.coordinator - + // & present the VC! return taskViewController } - + } diff --git a/OTFMagicBox/Onboarding/PasscodeViewController.swift b/OTFMagicBox/Onboarding/PasscodeViewController.swift index af68aa4c..d85432c2 100644 --- a/OTFMagicBox/Onboarding/PasscodeViewController.swift +++ b/OTFMagicBox/Onboarding/PasscodeViewController.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import UIKit @@ -37,53 +37,46 @@ import SwiftUI import OTFResearchKit struct PasscodeViewController: UIViewControllerRepresentable { - + func makeCoordinator() -> Coordinator { Coordinator() - } - + } + typealias UIViewControllerType = ORKPasscodeViewController - + func updateUIViewController(_ uiViewController: ORKPasscodeViewController, context: Context) {} func updateUIViewController(_ taskViewController: ORKTaskViewController, context: Context) {} func makeUIViewController(context: Context) -> ORKPasscodeViewController { - - - let editPasscodeViewController = ORKPasscodeViewController.passcodeEditingViewController(withText: "", delegate: context.coordinator, passcodeType:.type4Digit) - + let editPasscodeViewController = ORKPasscodeViewController.passcodeEditingViewController(withText: "", delegate: context.coordinator, passcodeType: .type4Digit) return editPasscodeViewController } - + class Coordinator: NSObject, ORKPasscodeDelegate { func passcodeViewControllerDidCancel(_ viewController: UIViewController) { - + } - + func passcodeViewControllerDidFinish(withSuccess viewController: UIViewController) { viewController.dismiss(animated: true, completion: nil) } - + func passcodeViewControllerDidFailAuthentication(_ viewController: UIViewController) { viewController.dismiss(animated: true, completion: nil) - + Alerts.showInfo(title: Constants.CustomiseStrings.wrongPasscode, message: Constants.CustomiseStrings.okay) } } - } +public enum Alerts { -import UIKit - -public class Alerts { - - public class func showInfo(_ vc: UIViewController? = .none, title: String, message: String) { + public static func showInfo(_ vc: UIViewController? = .none, title: String, message: String) { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - + let cancelAction = UIAlertAction(title: Constants.CustomiseStrings.okay, style: .default, handler: nil) alert.addAction(cancelAction) - + vc?.present(alert, animated: true, completion: nil) } - + } diff --git a/OTFMagicBox/Onboarding/PasswordlessLoginStep.swift b/OTFMagicBox/Onboarding/PasswordlessLoginStep.swift index a26330b6..59287b74 100644 --- a/OTFMagicBox/Onboarding/PasswordlessLoginStep.swift +++ b/OTFMagicBox/Onboarding/PasswordlessLoginStep.swift @@ -1,73 +1,73 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFResearchKit class PasswordlessLoginStep: ORKFormStep { - + static let identifier = "Login" - + static let idStepIdentifier = "IdStep" static let idConfirmStepIdentifier = "ConfirmIdStep" - + override init(identifier: String) { super.init(identifier: identifier) - + title = ModuleAppYmlReader().loginStepTitle text = ModuleAppYmlReader().loginStepText - + formItems = createFormItems() isOptional = false } - + required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + /** This function creates a form with the exact email question to ask. - + - Returns a `ORKFormItem` array with questions to show. - */ + */ fileprivate func createFormItems() -> [ORKFormItem] { let idStepTitle = "Email:" - + let titleStep = ORKFormItem(sectionTitle: "✉️ 🌎") - + let idQuestionStep = ORKFormItem(identifier: PasswordlessLoginStep.idStepIdentifier, text: idStepTitle, answerFormat: ORKEmailAnswerFormat(), optional: false) - + return [titleStep, idQuestionStep] } - + } diff --git a/OTFMagicBox/Profile/ProfileUIView.swift b/OTFMagicBox/Profile/ProfileUIView.swift index efc169e0..d5cfca70 100644 --- a/OTFMagicBox/Profile/ProfileUIView.swift +++ b/OTFMagicBox/Profile/ProfileUIView.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -37,7 +37,7 @@ import OTFCareKitStore import Sodium struct ProfileUIView: View { - + @State private(set) var user: OCKPatient? @State var isLoading = true @State private var isPresenting = false @@ -45,7 +45,7 @@ struct ProfileUIView: View { let manager = UploadDocumentManager() @StateObject private var viewModel = UpdateUserViewModel() @State private var isPresentingEditUser: Bool = false - var hint : String? + var hint: String? var userName: String { guard let givenName = user?.name.givenName, @@ -54,136 +54,149 @@ struct ProfileUIView: View { } return "\(givenName) \(familyName)" } - + var body: some View { - + NavigationView { VStack { Text(ModuleAppYmlReader().profileData?.title ?? Constants.CustomiseStrings.profile) - .foregroundColor(Color(YmlReader().appTheme?.textColor.color ?? UIColor.black)) - .font(YmlReader().appTheme?.screenTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - - - List { - Section { - if let user = user { - UpdateUserProfileView(user: user, backgroudColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, tColor: YmlReader().appTheme?.textColor.color ?? .black, cellBackgroundColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, headerColor: YmlReader().appTheme?.headerColor.color ?? .black, buttonColor: YmlReader().appTheme?.buttonTextColor.color ?? .black, borderColor: YmlReader().appTheme?.borderColor.color ?? .black, sepratorColor: YmlReader().appTheme?.separatorColor.color ?? .black) - } else { - LoadingView(username: "") - } + .foregroundColor(.otfTextColor) + .font(Font.otfscreenTitleFont) + .fontWeight(Font.otfFontWeight) + + List { + Section { + if let user = user { + UpdateUserProfileView(user: user) + } else { + LoadingView(username: "") } - .listRowBackground(Color.otfCellBackground) - + } + .listRowBackground(Color.otfCellBackground) + + Section { + if ModuleAppYmlReader().isPasscodeEnabled { + ChangePasscodeView() + } + HelpView(site: YmlReader().teamWebsite, title: ModuleAppYmlReader().profileData?.help ?? Constants.CustomiseStrings.help) + } + .listRowBackground(Color.otfCellBackground) + + if let email = user?.remoteID { Section { - if ModuleAppYmlReader().isPasscodeEnabled { - ChangePasscodeView() - } - HelpView(site: YmlReader().teamWebsite, title: ModuleAppYmlReader().profileData?.help ?? Constants.CustomiseStrings.help, textColor: Color(YmlReader().appTheme?.textColor.color ?? .black)) + ChangePasswordView(email: email, resetPassword: ModuleAppYmlReader().profileData?.resetPasswordText ?? Constants.CustomiseStrings.resetPassword) } .listRowBackground(Color.otfCellBackground) - - if let email = user?.remoteID { - Section { - ChangePasswordView(email: email, resetPassword: ModuleAppYmlReader().profileData?.resetPasswordText ?? Constants.CustomiseStrings.resetPassword) - } - .listRowBackground(Color.otfCellBackground) - } - - Section(header: Text(ModuleAppYmlReader().profileData?.reportProblemHeader ?? Constants.CustomiseStrings.reportProblem) - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(.otfHeaderColor)) { - ReportView(email: YmlReader().teamEmail, title: ModuleAppYmlReader().profileData?.reportProblemText ?? Constants.CustomiseStrings.reportProblem) - SupportView(phone: YmlReader().teamPhone, title: ModuleAppYmlReader().profileData?.supportText ?? Constants.CustomiseStrings.support) - } - .listRowBackground(Color.otfCellBackground) - - - if let user = user { - if let attachmentID = user.attachments?.ConsentForm?.attachmentID, let hashFileKey = user.attachments?.ConsentForm?.hashFileKey { - let doc = document.retriveFile(fileName: attachmentID) - if doc != nil { - Section { - NavigationLink(destination: PDFViewer(pdfData: manager.decryptedFile(file: doc!, hashFileKey: hashFileKey)) - ,label: { - ConsentDocumentView(title: ModuleAppYmlReader().profileData?.consentText ?? Constants.CustomiseStrings.consetDocument) - }) - .buttonStyle(PlainButtonStyle()).foregroundColor(Color.clear) - }.listRowBackground(Color.otfCellBackground) - + } + + Section(header: Text(ModuleAppYmlReader().profileData?.reportProblemHeader ?? Constants.CustomiseStrings.reportProblem) + .font(.otfheaderTitleFont) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(.otfHeaderColor)) { + ReportView(email: YmlReader().teamEmail, title: ModuleAppYmlReader().profileData?.reportProblemText ?? Constants.CustomiseStrings.reportProblem) + SupportView(phone: YmlReader().teamPhone, title: ModuleAppYmlReader().profileData?.supportText ?? Constants.CustomiseStrings.support) + } + .listRowBackground(Color.otfCellBackground) + + if let user = user { + if let attachmentID = user.attachments?.consentForm?.attachmentID, let hashFileKey = user.attachments?.consentForm?.hashFileKey { + let doc = document.retriveFile(fileName: attachmentID) + if doc != nil { + Section { + ZStack { + NavigationLink(destination: PDFViewer( + pdfData: + KeychainCloudManager.isKeyStored(key: KeychainKeys.defaultStorageKey) ? manager.decryptedFile(file: doc!, hashFileKey: hashFileKey) : doc!), label: { + EmptyView() + }).opacity(0.0) + ConsentDocumentView(title: ModuleAppYmlReader().profileData?.consentText ?? Constants.CustomiseStrings.consetDocument) } - } + }.listRowBackground(Color.otfCellBackground) } - - - Section { - WithdrawView(title: ModuleAppYmlReader().profileData?.WithdrawStudyText ?? Constants.CustomiseStrings.withdrawFromStudy, textColor: Color(YmlReader().appTheme?.textColor.color ?? UIColor.black)) - } - .listRowBackground(Color.otfCellBackground) - Section { - Text(YmlReader().teamCopyright) - .foregroundColor(Color(YmlReader().appTheme?.textColor.color ?? UIColor.black)) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - } - .listRowBackground(Color.otfCellBackground) - Section { - LogoutView() } - .listRowBackground(Color.otfCellBackground) + } - Section { - if let user = user{ - DeleteAccountView(user: user, textColor: Color(YmlReader().appTheme?.buttonTextColor.color ?? UIColor.black)) - } - } - .listRowBackground(Color.otfCellBackground) + Section { + WithdrawView(title: ModuleAppYmlReader().profileData?.withdrawStudyText ?? Constants.CustomiseStrings.withdrawFromStudy) + } + .listRowBackground(Color.otfCellBackground) + Section { + Text(YmlReader().teamCopyright) + .foregroundColor(.otfTextColor) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } - .listStyle(.insetGrouped) - .onLoad { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { - fetchUserFromDB() + .listRowBackground(Color.otfCellBackground) + + Section { + LogoutView() + }.listRowBackground(Color.otfCellBackground) + + Section { + if let user = user { + DeleteAccountView(user: user) } - UITableView.appearance().backgroundColor = YmlReader().appTheme?.backgroundColor.color - UITableViewCell.appearance().backgroundColor = YmlReader().appTheme?.backgroundColor.color - UITableView.appearance().separatorColor = YmlReader().appTheme?.separatorColor.color } - .onReceive(NotificationCenter.default.publisher(for: .databaseSuccessfllySynchronized)) { notification in + .listRowBackground(Color.otfCellBackground) + } + .listStyle(.insetGrouped) + .onLoad { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { fetchUserFromDB() } - .onReceive(NotificationCenter.default.publisher(for: .deleteUserAccount)) { notification in - isPresenting = true - } - + UITableView.appearance().backgroundColor = YmlReader().appStyle.backgroundColor.color + UITableViewCell.appearance().backgroundColor = YmlReader().appStyle.backgroundColor.color + UITableView.appearance().separatorColor = YmlReader().appStyle.separatorColor.color + } + .onReceive(NotificationCenter.default.publisher(for: .databaseSuccessfllySynchronized)) { _ in + fetchUserFromDB() + } + .onReceive(NotificationCenter.default.publisher(for: .deleteUserAccount)) { _ in + isPresenting = true + } } - .background(Color(YmlReader().appTheme?.backgroundColor.color ?? UIColor.black)) + .background(Color(YmlReader().appStyle.backgroundColor.color ?? UIColor.black)) .alert(isPresented: $isPresenting) { Alert( title: Text(Constants.CustomiseStrings.accountDeleted) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), message: Text(Constants.deleteAccount), dismissButton: .default(Text(Constants.CustomiseStrings.okay), action: { OTFTheraforgeNetwork.shared.moveToOnboardingView() }) ) } + .onAppear { + +// let careKitManager = CareKitManager.shared +// careKitManager.cloudantStore?.populateSampleData() +// +// careKitManager.cloudantStore?.fetchTasks(completion: { result in +// switch result { +// case .success(let tasks): +// print(tasks) +// +// case .failure(_): +// print("Error ==> ") +// } +// }) + } .onDisappear { NotificationCenter.default.removeObserver(self, name: .deleteUserAccount, object: nil) } - .background(Color.otfCellBackground) + .background(Color.otfCellBackground) } } - + func fetchUserFromDB() { - CareKitManager.shared.cloudantStore?.getThisPatient({ result in + CareKitStoreManager.shared.cloudantStore?.getThisPatient({ result in if case .success(let patient) = result { self.user = patient - if let attachmentID = self.user?.attachments?.Profile?.attachmentID { + if let attachmentID = self.user?.attachments?.profile?.attachmentID { viewModel.downloadFile(attachmentID: attachmentID, isProfile: true) } - if let consentFormId = self.user?.attachments?.ConsentForm?.attachmentID { + if let consentFormId = self.user?.attachments?.consentForm?.attachmentID { viewModel.downloadFile(attachmentID: consentFormId, isProfile: false) } } diff --git a/OTFMagicBox/Profile/ViewModel/ChangePasswordViewModel.swift b/OTFMagicBox/Profile/ViewModel/ChangePasswordViewModel.swift index dca8b589..f23aa342 100644 --- a/OTFMagicBox/Profile/ViewModel/ChangePasswordViewModel.swift +++ b/OTFMagicBox/Profile/ViewModel/ChangePasswordViewModel.swift @@ -9,20 +9,15 @@ import Foundation import OTFCloudClientAPI import OTFUtilities import Combine - - final class ChangePasswordViewModel: ObservableObject { - @Published var showFailureAlert = false @Published var errorMessage = String() @Published var oldPassword: String = "" @Published var newPassword: String = "" @Published var email: String - init(email: String) { self.email = email } - var error: ForgeError? var viewDismissModePublisher = PassthroughSubject() private var disposables = Set() @@ -31,8 +26,7 @@ final class ChangePasswordViewModel: ObservableObject { viewDismissModePublisher.send(shouldDismissView) } } - -// MARK: chnage password request + // MARK: chnage password request func changePassword() { OTFTheraforgeNetwork.shared.changePassword(email: email, oldPassword: oldPassword, newPassword: newPassword) .receive(on: DispatchQueue.main) @@ -51,4 +45,3 @@ final class ChangePasswordViewModel: ObservableObject { .store(in: &disposables) } } - diff --git a/OTFMagicBox/Profile/ViewModel/DeleteAccountViewModel.swift b/OTFMagicBox/Profile/ViewModel/DeleteAccountViewModel.swift index 53f5245d..0c12f91e 100644 --- a/OTFMagicBox/Profile/ViewModel/DeleteAccountViewModel.swift +++ b/OTFMagicBox/Profile/ViewModel/DeleteAccountViewModel.swift @@ -11,13 +11,13 @@ import OTFUtilities import Combine final class DeleteAccountViewModel: ObservableObject { - + @Published var showingAlert = false @Published var showingOptions = false - + private var disposables = Set() - -// MARK: delete account request + + // MARK: delete account request func deleteUserAccount(userId: String) { OTFTheraforgeNetwork.shared.deleteUser(userId: userId) .receive(on: DispatchQueue.main) diff --git a/OTFMagicBox/Profile/ViewModel/LogoutViewModel.swift b/OTFMagicBox/Profile/ViewModel/LogoutViewModel.swift index c635b542..9083b9f3 100644 --- a/OTFMagicBox/Profile/ViewModel/LogoutViewModel.swift +++ b/OTFMagicBox/Profile/ViewModel/LogoutViewModel.swift @@ -9,17 +9,17 @@ import Foundation import OTFCloudClientAPI import OTFUtilities import Combine +import WatchConnectivity final class LogoutViewModel: ObservableObject { - - // MARK: - PROPERTY - + + // MARK: - PROPERTY @Published var showingAlert = false @Published var showingOptions = false - + private var disposables = Set() - -// MARK: signout request + + // MARK: signout request func signout() { OTFTheraforgeNetwork.shared.signOut() .receive(on: DispatchQueue.main) @@ -28,12 +28,13 @@ final class LogoutViewModel: ObservableObject { case .failure(let error): self.showingAlert = true OTFError("error in signout request -> %{public}s.", error.error.message) + default: break } - } receiveValue: { data in - OTFLog("data retrieved -> %{public}s.", data.message) + } receiveValue: { _ in + WCSession.default.sendMessage(["userNotLoggedIn": "true"]) { _ in } + OTFTheraforgeNetwork.shared.moveToOnboardingView() } .store(in: &disposables) } } - diff --git a/OTFMagicBox/Profile/ViewModel/UpdateUserViewModel.swift b/OTFMagicBox/Profile/ViewModel/UpdateUserViewModel.swift index 73d29b83..b2b82b36 100644 --- a/OTFMagicBox/Profile/ViewModel/UpdateUserViewModel.swift +++ b/OTFMagicBox/Profile/ViewModel/UpdateUserViewModel.swift @@ -16,68 +16,66 @@ struct ProfileDetaiDataModel { var showGenderPicker = false var showDatePicker = false } - - final class UpdateUserViewModel: ObservableObject { - + @Published var profileDetaiDataModel: ProfileDetaiDataModel = ProfileDetaiDataModel() private var disposables = Set() var patientPublisher = PassthroughSubject() var profileImageData = PassthroughSubject() var hideLoader = PassthroughSubject() let swiftSodium = SwiftSodium() - + private var shouldDismissView = false { didSet { hideLoader.send(shouldDismissView) } } - + private var patient: OCKPatient? { didSet { patientPublisher.send(patient!) } } - + private var profileData: Data? { didSet { profileImageData.send(profileData!) } } - -// MARK: Fetch OCKPatient + + // MARK: Fetch OCKPatient func fetchPatient(userId: String) { - - CareKitManager.shared.cloudantStore?.fetchPatient(withID: userId, completion: { result in + + CareKitStoreManager.shared.cloudantStore?.fetchPatient(withID: userId, completion: { _ in self.profileDataPublisher(userId: userId) .receive(on: DispatchQueue.main) - .sink(receiveCompletion: {print ("Received completion: \($0).")}, + .sink(receiveCompletion: { print("Received completion: \($0).") }, receiveValue: {patient in - self.patient = patient - }) + self.patient = patient + }) .store(in: &self.disposables) }) } - + func profileDataPublisher(userId: String) -> AnyPublisher { - return Future { promise in - CareKitManager.shared.cloudantStore?.fetchPatient(withID: userId, completion: { result in - if case .success(let patient) = result { - return promise(.success(patient)) - } - }) - } - .receive(on: RunLoop.main) - .eraseToAnyPublisher() - } - -// MARK: update OCKPatient + return Future { promise in + CareKitStoreManager.shared.cloudantStore?.fetchPatient(withID: userId, completion: { result in + if case .success(let patient) = result { + return promise(.success(patient)) + } + }) + } + .receive(on: RunLoop.main) + .eraseToAnyPublisher() + } + + // MARK: update OCKPatient func updatePatient(user: OCKPatient) { - CareKitManager.shared.cloudantStore?.updatePatient(user) + CareKitStoreManager.shared.cloudantStore?.updatePatient(user) } - -// MARK: upload file request - func uploadFile(data: Data, fileName: String, encryptedFileKey: String? = nil , hashFileKey: String) { + + // MARK: upload file request + func uploadFile(data: Data, fileName: String, encryptedFileKey: String? = nil, hashFileKey: String) { OTFTheraforgeNetwork.shared.uploadFile(data: data, fileName: fileName, type: .profile, encryptedFileKey: encryptedFileKey, hashFileKey: hashFileKey) .receive(on: DispatchQueue.main) .sink { res in @@ -94,20 +92,20 @@ final class UpdateUserViewModel: ObservableObject { } .store(in: &disposables) } - - func showProfileImage(user : OCKPatient, imageData: Data) -> UIImage { - - if let encryptedFileKey = user.attachments?.Profile?.encryptedFileKey, let hashFileKey = user.attachments?.Profile?.hashFileKey, !encryptedFileKey.isEmpty { + + func showProfileImage(user: OCKPatient, imageData: Data) -> UIImage { + + if let encryptedFileKey = user.attachments?.profile?.encryptedFileKey, let hashFileKey = user.attachments?.profile?.hashFileKey, !encryptedFileKey.isEmpty { let image = dataToImage(data: imageData, hashFileKey: hashFileKey) - return image + return image } else { - let image = dataToImageWithoutDecryption(data: imageData, key: user.attachments?.Profile?.hashFileKey) + let image = dataToImageWithoutDecryption(data: imageData, key: user.attachments?.profile?.hashFileKey) return image } } - -//MARK: downlaod file request - func downloadFile(attachmentID: String, isProfile : Bool = false) { + + // MARK: downlaod file request + func downloadFile(attachmentID: String, isProfile: Bool = false) { OTFTheraforgeNetwork.shared.downloadFile(attachmentID: attachmentID, type: .profile) .receive(on: DispatchQueue.main) .sink { res in @@ -120,21 +118,21 @@ final class UpdateUserViewModel: ObservableObject { let fileData = data.data fileData.saveFileToDocument(data: fileData, filename: data.metadata.attachmentID) if isProfile { - let dataDict:[String: Data] = ["imageData": fileData] + let dataDict: [String: Data] = ["imageData": fileData] NotificationCenter.default.post(name: .imageDownloaded, object: dataDict) } } .store(in: &disposables) } - - //MARK: decrypt encrypted data + + // MARK: decrypt encrypted data func decryptedFile(file: Data, hashFileKey: String) -> Data { - let dataToBytes = swiftSodium.getArrayOfBytesFromData(FileData: file as NSData) + let dataToBytes = swiftSodium.getArrayOfBytesFromData(fileData: file as NSData) let fileKey = swiftSodium.generateDeriveKey(key: KeychainCloudManager.getDefaultStorageKey) - + let hashKey = swiftSodium.generateGenericHashWithKey(message: dataToBytes, fileKey: fileKey) let hashKeyHex = hashKey.bytesToHex(spacing: "").lowercased() - + if hashKeyHex.contains(hashFileKey) { let (header, encryptedFile) = dataToBytes.splitFile() let encryption = swiftSodium.decryptFile(secretKey: fileKey, header: header, encryptedFile: encryptedFile) @@ -145,11 +143,9 @@ final class UpdateUserViewModel: ObservableObject { } return Data() - + } - - -//MARK: decrypt data and convert data to UIImage + // MARK: decrypt data and convert data to UIImage func dataToImage(data: Data, hashFileKey: String) -> UIImage { let decryptedData = decryptedFile(file: data, hashFileKey: hashFileKey) if let image = UIImage(data: decryptedData) { @@ -157,46 +153,42 @@ final class UpdateUserViewModel: ObservableObject { } return UIImage() } - + func dataToImageWithoutDecryption(data: Data, key: String?) -> UIImage { - let imageToBytes = swiftSodium.getArrayOfBytesFromData(FileData: data as NSData) + let imageToBytes = swiftSodium.getArrayOfBytesFromData(fileData: data as NSData) let hashFileKey = swiftSodium.generateGenericHashWithoutKey(message: imageToBytes) - + let hashFileKeyHex = hashFileKey.bytesToHex(spacing: "").lowercased() if let keyhex = key, hashFileKeyHex.contains(keyhex), - let image = UIImage(data: data) { + let image = UIImage(data: data) { return image } return UIImage() } - -//MARK: Delete file request + + // MARK: Delete file request func deleteAttachment(attachmentID: String) { OTFTheraforgeNetwork.shared.deleteFile(attachmentID: attachmentID) .receive(on: DispatchQueue.main) .sink { res in switch res { case .failure: - self.shouldDismissView = true + self.shouldDismissView = true default: break } - } receiveValue: { data in + } receiveValue: { _ in self.synchronizeDatabase() self.shouldDismissView = true } .store(in: &disposables) } - -//MARK: delete file from document directory + + // MARK: delete file from document directory func deleteFileFromDocument(fileName: String) { - deleteFile(filename: fileName) + try? FileManager.deleteFile(filename: fileName) } - + public func synchronizeDatabase() { NotificationCenter.default.post(name: .databaseSuccessfllySynchronized, object: nil) } } - - - - diff --git a/OTFMagicBox/Profile/Views/ChangePasscodeView.swift b/OTFMagicBox/Profile/Views/ChangePasscodeView.swift index a6ef7967..1bd59fb0 100644 --- a/OTFMagicBox/Profile/Views/ChangePasscodeView.swift +++ b/OTFMagicBox/Profile/Views/ChangePasscodeView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI @@ -37,23 +37,23 @@ import OTFResearchKit struct ChangePasscodeView: View { @State var showPasscode = false - + var body: some View { HStack { Text(Constants.CustomiseStrings.changePasscode) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) Spacer() Image(systemName: "chevron.right") - .foregroundColor(Color(UIColor.tertiaryLabel)) - .font(.footnote.weight(.semibold)) + .foregroundColor(Color(UIColor.tertiaryLabel)) + .font(.footnote.weight(.semibold)) }.frame(height: Metrics.MAIN_VIEW_HEIGHT).contentShape(Rectangle()) - .gesture(TapGesture().onEnded({ - if ORKPasscodeViewController.isPasscodeStoredInKeychain() { - self.showPasscode.toggle() - } + .gesture(TapGesture().onEnded({ + if ORKPasscodeViewController.isPasscodeStoredInKeychain() { + self.showPasscode.toggle() + } })).sheet(isPresented: $showPasscode, onDismiss: { - + }, content: { PasscodeViewController() }) diff --git a/OTFMagicBox/Profile/Views/ChangePasswordView.swift b/OTFMagicBox/Profile/Views/ChangePasswordView.swift index ddd4770a..98a099a2 100644 --- a/OTFMagicBox/Profile/Views/ChangePasswordView.swift +++ b/OTFMagicBox/Profile/Views/ChangePasswordView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -38,21 +38,21 @@ import OTFUtilities // This view creates the section in the Profile view, which navigates to the another page where we can reset the password. struct ChangePasswordView: View { - + let email: String let resetPassword: String @State var showResetPassword = false - + var body: some View { HStack { Text(resetPassword) .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) Spacer() Image(systemName: "chevron.right") - .foregroundColor(Color(UIColor.tertiaryLabel)) - .font(.footnote.weight(.semibold)) + .foregroundColor(Color(UIColor.tertiaryLabel)) + .font(.footnote.weight(.semibold)) }.frame(height: Metrics.TITLE_VIEW_HEIGHT) .contentShape(Rectangle()) .gesture(TapGesture().onEnded { @@ -67,37 +67,26 @@ struct ChangePasswordView: View { // View where we can reset the password. struct ChangePasswordDeatilsView: View { - @Environment(\.presentationMode) var presentationMode: Binding @StateObject var viewModel: ChangePasswordViewModel - - var body: some View { VStack { - + Spacer() - Image.theraforgeLogo.logoStyle() - Spacer() - TextField(Constants.CustomiseStrings.email, text: $viewModel.email) .style(.emailField) .foregroundColor(.otfTextColor) .disabled(true) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - - + .font(Font.otfAppFont) SecureField(ModuleAppYmlReader().profileData?.oldPassword ?? Constants.CustomiseStrings.oldPassword, text: $viewModel.oldPassword) .style(.secureField) .foregroundColor(.otfTextColor) - SecureField(ModuleAppYmlReader().profileData?.newPassword ?? Constants.CustomiseStrings.newPassword, text: $viewModel.newPassword) .style(.secureField) .foregroundColor(.otfTextColor) - Spacer() - Button(action: { viewModel.changePassword() }, label: { @@ -112,15 +101,17 @@ struct ChangePasswordDeatilsView: View { }) .padding() .alert(isPresented: $viewModel.showFailureAlert, content: ({ - Alert(title: Text(Constants.CustomiseStrings.passwordResetError).font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), message: Text(viewModel.errorMessage), dismissButton: .default(Text(Constants.CustomiseStrings.okay))) + Alert(title: Text(Constants.CustomiseStrings.passwordResetError).font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), + message: Text(viewModel.errorMessage), + dismissButton: .default(Text(Constants.CustomiseStrings.okay))) })) - + Spacer() } .background(Color.otfCellBackground) .onReceive(viewModel.viewDismissModePublisher) { shouldDismiss in - if shouldDismiss{ + if shouldDismiss { self.presentationMode.wrappedValue.dismiss() } } diff --git a/OTFMagicBox/Profile/Views/ConsentDocumentView.swift b/OTFMagicBox/Profile/Views/ConsentDocumentView.swift index 79d106cb..8f48a484 100644 --- a/OTFMagicBox/Profile/Views/ConsentDocumentView.swift +++ b/OTFMagicBox/Profile/Views/ConsentDocumentView.swift @@ -1,61 +1,60 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI import OTFUtilities struct ConsentDocumentView: View { - + let title: String init(title: String) { self.title = title } - + var body: some View { HStack { - Text(title) - .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - Spacer() - Image(systemName: "chevron.right") - .foregroundColor(Color(UIColor.tertiaryLabel)) - .font(.footnote.weight(.semibold)) - } - .frame(height: Metrics.TITLE_VIEW_HEIGHT) - .contentShape(Rectangle()) - + Text(title) + .foregroundColor(.otfTextColor) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) + Spacer() + Image(systemName: "chevron.right") + .foregroundColor(Color(UIColor.tertiaryLabel)) + .font(.footnote.weight(.semibold)) + } + .frame(maxWidth: .infinity, minHeight: Metrics.TITLE_VIEW_HEIGHT) + .contentShape(Rectangle()) } } diff --git a/OTFMagicBox/Profile/Views/DeleteAccountView.swift b/OTFMagicBox/Profile/Views/DeleteAccountView.swift index 7ebdf9fd..42a44e52 100644 --- a/OTFMagicBox/Profile/Views/DeleteAccountView.swift +++ b/OTFMagicBox/Profile/Views/DeleteAccountView.swift @@ -13,8 +13,7 @@ import OTFUtilities struct DeleteAccountView: View { @StateObject private var viewModel = DeleteAccountViewModel() @State private(set) var user: OCKPatient? - let textColor: Color - + var body: some View { HStack { Spacer() @@ -24,38 +23,38 @@ struct DeleteAccountView: View { Text(Constants.CustomiseStrings.deleteAccount) .font(.basicFontStyle) .foregroundColor(Color.red) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) }) .actionSheet(isPresented: $viewModel.showingOptions) { ActionSheet( title: Text(Constants.CustomiseStrings.removeInformation) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), buttons: [ .destructive(Text(Constants.CustomiseStrings.deleteAccount), action: { viewModel.deleteUserAccount(userId: user?.id ?? "") }), .cancel(Text(Constants.CustomiseStrings.cancel) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont)) ] ) } .alert(isPresented: $viewModel.showingAlert) { Alert(title: Text(Constants.CustomiseStrings.faliedToDeleteAccount) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), message: nil, dismissButton: .default(Text(Constants.CustomiseStrings.okay))) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), message: nil, dismissButton: .default(Text(Constants.CustomiseStrings.okay))) } - + Spacer() } - + } } struct DeleteAccountView_Previews: PreviewProvider { static var previews: some View { - DeleteAccountView(user: nil, textColor: Color.red) + DeleteAccountView(user: nil) } } diff --git a/OTFMagicBox/Profile/Views/DocumentPreviewViewController.swift b/OTFMagicBox/Profile/Views/DocumentPreviewViewController.swift index e7d177d2..b204f742 100644 --- a/OTFMagicBox/Profile/Views/DocumentPreviewViewController.swift +++ b/OTFMagicBox/Profile/Views/DocumentPreviewViewController.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import UIKit @@ -38,7 +38,7 @@ import SwiftUI struct DocumentPreviewViewController: UIViewControllerRepresentable { private var isActive: Binding private let viewController = UIViewController() - private var docController: UIDocumentInteractionController? = nil + private var docController: UIDocumentInteractionController? init(_ isActive: Binding, url: URL?) { self.isActive = isActive @@ -77,4 +77,3 @@ struct DocumentPreviewViewController: UIViewControllerRepresentable { } } } - diff --git a/OTFMagicBox/Profile/Views/HelpView.swift b/OTFMagicBox/Profile/Views/HelpView.swift index c765d13c..32bed57d 100644 --- a/OTFMagicBox/Profile/Views/HelpView.swift +++ b/OTFMagicBox/Profile/Views/HelpView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI @@ -37,26 +37,24 @@ import SwiftUI struct HelpView: View { var site = "" var title = "" - var textColor: Color - init(site: String, title: String, textColor: Color) { + init(site: String, title: String) { self.site = site self.title = title - self.textColor = textColor } - + var body: some View { HStack { Text(title) - .foregroundColor(textColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .foregroundColor(.otfTextColor) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) Spacer() Image(systemName: "chevron.right") - .foregroundColor(Color(UIColor.tertiaryLabel)) - .font(.footnote.weight(.semibold)) + .foregroundColor(Color(UIColor.tertiaryLabel)) + .font(.footnote.weight(.semibold)) }.frame(height: Metrics.MAIN_VIEW_HEIGHT).contentShape(Rectangle()) - .gesture(TapGesture().onEnded({ - if let url = URL(string: self.site) { + .gesture(TapGesture().onEnded({ + if let url = URL(string: self.site) { UIApplication.shared.open(url) } })) @@ -65,6 +63,6 @@ struct HelpView: View { struct HelpView_Previews: PreviewProvider { static var previews: some View { - HelpView(site: "", title: "Help", textColor: Color(YmlReader().appTheme?.textColor.color ?? UIColor.black)) + HelpView(site: "", title: "Help") } } diff --git a/OTFMagicBox/Profile/Views/LogoutView.swift b/OTFMagicBox/Profile/Views/LogoutView.swift index d17589dd..bc225221 100644 --- a/OTFMagicBox/Profile/Views/LogoutView.swift +++ b/OTFMagicBox/Profile/Views/LogoutView.swift @@ -1,47 +1,48 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation import SwiftUI import OTFUtilities +import WatchConnectivity struct LogoutView: View { - - // MARK: - PROPERTY - @StateObject private var viewModel = LogoutViewModel() - - // MARK: - BODY + + // MARK: - PROPERTY + @StateObject private var viewModel = LogoutViewModel() + + // MARK: - BODY var body: some View { HStack { Spacer() @@ -51,28 +52,28 @@ struct LogoutView: View { Text(Constants.CustomiseStrings.logout) .font(.basicFontStyle) .foregroundColor(.otfButtonColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) }) .actionSheet(isPresented: $viewModel.showingOptions) { ActionSheet( title: Text(Constants.CustomiseStrings.areYouSure) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), buttons: [ .destructive(Text(Constants.CustomiseStrings.logout), action: { viewModel.signout() }), .cancel(Text(Constants.CustomiseStrings.cancel) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont)) ] ) } .alert(isPresented: $viewModel.showingAlert) { Alert(title: Text(Constants.CustomiseStrings.failedToLogout) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), message: nil, dismissButton: .default(Text(Constants.CustomiseStrings.okay))) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), message: nil, dismissButton: .default(Text(Constants.CustomiseStrings.okay))) } Spacer() } diff --git a/OTFMagicBox/Profile/Views/PDFKitRepresentedView.swift b/OTFMagicBox/Profile/Views/PDFKitRepresentedView.swift index 23cc51cc..361942cb 100644 --- a/OTFMagicBox/Profile/Views/PDFKitRepresentedView.swift +++ b/OTFMagicBox/Profile/Views/PDFKitRepresentedView.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -55,4 +55,3 @@ struct PDFKitRepresentedView: UIViewRepresentable { pdfView.document = PDFDocument(data: data) } } - diff --git a/OTFMagicBox/Profile/Views/PDFViewer.swift b/OTFMagicBox/Profile/Views/PDFViewer.swift index f66739f7..eda22b76 100644 --- a/OTFMagicBox/Profile/Views/PDFViewer.swift +++ b/OTFMagicBox/Profile/Views/PDFViewer.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -38,10 +38,10 @@ import UniformTypeIdentifiers import MobileCoreServices struct PDFViewer: View { - + let pdfData: Data @State private var isActionSheetPresented = false - + var body: some View { PDFKitRepresentedView(pdfData) .navigationBarTitle("TheraForge Consent", displayMode: .inline) @@ -49,19 +49,19 @@ struct PDFViewer: View { isActionSheetPresented = true }) .sheet(isPresented: $isActionSheetPresented) { - ShareSheet(activityItems: [pdfData]) + ShareSheet(activityItems: [pdfData]) } } } struct ShareSheet: UIViewControllerRepresentable { typealias Callback = (_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ error: Error?) -> Void - + let activityItems: [Any] let applicationActivities: [UIActivity]? = nil let excludedActivityTypes: [UIActivity.ActivityType]? = nil let callback: Callback? = nil - + func makeUIViewController(context: Context) -> UIActivityViewController { let controller = UIActivityViewController( activityItems: activityItems, @@ -70,6 +70,6 @@ struct ShareSheet: UIViewControllerRepresentable { controller.completionWithItemsHandler = callback return controller } - + func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {} } diff --git a/OTFMagicBox/Profile/Views/ReportView.swift b/OTFMagicBox/Profile/Views/ReportView.swift index 3e3433e3..e6b48bd0 100644 --- a/OTFMagicBox/Profile/Views/ReportView.swift +++ b/OTFMagicBox/Profile/Views/ReportView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI @@ -37,23 +37,23 @@ import SwiftUI struct ReportView: View { var email = "" var title = "" - + init(email: String, title: String) { self.email = email self.title = title } - + var body: some View { HStack { Text(title) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .fontWeight(Font.otfFontWeight) .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(Font.otfAppFont) Spacer() Text(self.email) .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) .lineLimit(1) } .frame(maxWidth: .infinity, minHeight: Metrics.TITLE_VIEW_HEIGHT) @@ -65,7 +65,7 @@ struct ReportView: View { .accessibilityAddTraits(.isButton) .accessibilityLabel("Report a problem to \(email)") .accessibilityInputLabels([ModuleAppYmlReader().profileData?.reportProblemText ?? Constants.CustomiseStrings.reportProblem]) - + } } @@ -83,27 +83,26 @@ import MessageUI class EmailHelper: NSObject, MFMailComposeViewControllerDelegate { public static let shared = EmailHelper() - func sendEmail(subject:String, body:String, to:String){ + func sendEmail(subject: String, body: String, to: String) { if !MFMailComposeViewController.canSendMail() { return } - + let picker = MFMailComposeViewController() - + picker.setSubject(subject) picker.setMessageBody(body, isHTML: true) picker.setToRecipients([to]) picker.mailComposeDelegate = self - + EmailHelper.getRootViewController()?.present(picker, animated: true, completion: nil) } - + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { EmailHelper.getRootViewController()?.dismiss(animated: true, completion: nil) } - + static func getRootViewController() -> UIViewController? { (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController } } - diff --git a/OTFMagicBox/Profile/Views/SupportView.swift b/OTFMagicBox/Profile/Views/SupportView.swift index fbf51437..f8bff37e 100644 --- a/OTFMagicBox/Profile/Views/SupportView.swift +++ b/OTFMagicBox/Profile/Views/SupportView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI @@ -41,23 +41,23 @@ struct SupportView: View { self.phone = phone self.title = title } - + var body: some View { HStack { Text(title) .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) Spacer() Text(self.phone).foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } .frame(maxWidth: .infinity, minHeight: Metrics.TITLE_VIEW_HEIGHT) .contentShape(Rectangle()) .gesture(TapGesture().onEnded({ let telephone = "tel://" - let formattedString = telephone + self.phone + let formattedString = telephone + self.phone guard let url = URL(string: formattedString) else { return } UIApplication.shared.open(url) })) diff --git a/OTFMagicBox/Profile/Views/UpdateUserProfileDetailView.swift b/OTFMagicBox/Profile/Views/UpdateUserProfileDetailView.swift index 956d0a29..4ca256e9 100644 --- a/OTFMagicBox/Profile/Views/UpdateUserProfileDetailView.swift +++ b/OTFMagicBox/Profile/Views/UpdateUserProfileDetailView.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -39,21 +39,14 @@ import OTFCloudClientAPI import OTFUtilities struct UpdateUserProfileDetailView: View { - let backgroudColor: UIColor - let textColor: UIColor - let cellBackgroundColor: UIColor - let headerColor: UIColor - let buttonColor: UIColor - let borderColor: UIColor - let sepratorColor: UIColor let genderValues = GenderType.allCases @StateObject private var viewModel = UpdateUserViewModel() @Environment(\.colorScheme) var colorScheme private var selectedDate: Binding { Binding( - get: { self.birthday}, - set : { + get: { self.birthday }, + set: { self.birthday = $0 self.setDateString() }) @@ -61,42 +54,31 @@ struct UpdateUserProfileDetailView: View { @State private(set) var user: OCKPatient @State var firstName: String - @State var lastName:String + @State var lastName: String @State var dob: String @State private var image: UIImage? @State var profileImageData = Data() @State var isHideLoader: Bool = true @Environment(\.presentationMode) var presentationMode: Binding - @State var birthday: Date @State var gender: GenderType - - init(user: OCKPatient, backgroudColor: UIColor, textColor: UIColor, cellBackgroundColor: UIColor, headerColor: UIColor, buttonColor: UIColor, borderColor: UIColor, sepratorColor: UIColor) { - _user = State(initialValue: user) - _firstName = State(initialValue: user.name.givenName ?? "") - _lastName = State(initialValue: user.name.familyName ?? "") - _dob = State(initialValue: user.birthday?.toString ?? "") - self.backgroudColor = backgroudColor - self.buttonColor = buttonColor - self.borderColor = borderColor - self.textColor = textColor - self.cellBackgroundColor = cellBackgroundColor - self.headerColor = headerColor - self.sepratorColor = sepratorColor - + init(user: OCKPatient) { + self._user = State(initialValue: user) + self._firstName = State(initialValue: user.name.givenName ?? "") + self._lastName = State(initialValue: user.name.familyName ?? "") + self._dob = State(initialValue: user.birthday?.toString ?? "") self._birthday = State(initialValue: user.birthday ?? Date()) self._gender = State(initialValue: user.sex?.genderType ?? .other) - let navBarAppearance = UINavigationBar.appearance() - navBarAppearance.largeTitleTextAttributes = [.foregroundColor: YmlReader().appTheme?.textColor.color ?? UIColor.black] + navBarAppearance.largeTitleTextAttributes = [.foregroundColor: YmlReader().appStyle.textColor.color ?? UIColor.black] } var body: some View { NavigationView { Form { VStack { - IconView(image: $image, hashFileKey: user.attachments?.Profile?.hashFileKey ?? "", fileName: user.attachments?.Profile?.attachmentID ?? "", viewModel: viewModel) + IconView(image: $image, hashFileKey: user.attachments?.profile?.hashFileKey ?? "", fileName: user.attachments?.profile?.attachmentID ?? "", viewModel: viewModel) .frame(width: Metrics.PROFILE_IMAGE_WIDTH, height: Metrics.PROFILE_IMAGE_HEIGHT ) Text(name) .font(.title.weight(.bold)) @@ -105,128 +87,124 @@ struct UpdateUserProfileDetailView: View { .listRowInsets(EdgeInsets()) .listRowBackground(Color.clear) .accessibilityElement(children: .ignore) - Section { HStack { Text(firstNameTitle) - .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .foregroundColor(Color.otfTextColor) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) .accessibilityHidden(true) TextField(firstNameTitle, text: $firstName) .style(.textField) - .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .foregroundColor(Color.otfTextColor) + .font(Font.otfAppFont) .accessibilityLabel("First Name") } HStack { Text(ModuleAppYmlReader().profileData?.lastName ?? Constants.CustomiseStrings.lastName) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .foregroundColor(.otfTextColor) + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont) + .foregroundColor(Color.otfTextColor) .accessibilityHidden(true) TextField(lastNameTitle, text: $lastName) .style(.textField) - .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .foregroundColor(Color.otfTextColor) + .font(Font.otfAppFont) .accessibilityLabel("Last Name") } } header: { Text(infoHeader) - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(.otfHeaderColor) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) + .foregroundColor(Color.otfHeaderColor) .textCase(nil) } - + Section { Picker(Constants.CustomiseStrings.selectGender, selection: $gender) { ForEach(GenderType.allCases, id: \.self) { Text($0.rawValue) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } .accessibilityLabel("Edit the gender set on your profile") .accessibilityInputLabels(["Edit Gender"]) } - + DatePicker("Birthdate", selection: $birthday, displayedComponents: .date) .accessibilityLabel("Edit the birthdate set on your profile") .accessibilityInputLabels(["Edit Birthdate"]) } header: { Text(otherInfoHeader) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(.otfHeaderColor) - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(Color.otfHeaderColor) + .font(.otfheaderTitleFont) .textCase(nil) } - Button(action: { updatePatient() if let image = image { isHideLoader = false if let imageData = image.pngData() { - let bytesImage = viewModel.swiftSodium.getArrayOfBytesFromData(FileData: imageData as NSData) + let bytesImage = viewModel.swiftSodium.getArrayOfBytesFromData(fileData: imageData as NSData) let hashKeyFile = viewModel.swiftSodium.generateGenericHashWithoutKey(message: bytesImage) let hashKeyFileHex = hashKeyFile.bytesToHex(spacing: "").lowercased() let uuid = UUID().uuidString + ".png" - viewModel.uploadFile(data: imageData, fileName: uuid , hashFileKey: hashKeyFileHex) - + viewModel.uploadFile(data: imageData, fileName: uuid, hashFileKey: hashKeyFileHex) + } } }, label: { Text(Constants.CustomiseStrings.save) .padding(Metrics.PADDING_BUTTON_LABEL) .frame(maxWidth: .infinity) - .foregroundColor(.otfButtonColor) + .foregroundColor(Color.otfButtonColor) .font(.system(size: 20, weight: .bold, design: .default)) .overlay( RoundedRectangle(cornerRadius: Metrics.RADIUS_CORNER_BUTTON) .stroke(Color.otfButtonColor, lineWidth: 2) ) }) - + } } - .listRowBackground(Color.otfCellBackground) - .navigationBarTitleDisplayMode(.inline) - .navigationBarTitle(Text(ModuleAppYmlReader().profileData?.title ?? "Profile")) - .overlay(LoaderView(tintColor: .black, scaleSize: 2.0).padding(.bottom,50).hidden(isHideLoader)) - - .onReceive(NotificationCenter.default.publisher(for: .databaseSuccessfllySynchronized)) { notification in - viewModel.fetchPatient(userId: user.id) - } - .onReceive(viewModel.patientPublisher) { patient in - patientData(patient: patient) - } - .onReceive(viewModel.profileImageData) { data in - let dataDict:[String: Data] = ["imageData": data] - NotificationCenter.default.post(name: .imageUploaded, object: dataDict) - presentationMode.wrappedValue.dismiss() - } - - .onReceive(NotificationCenter.default.publisher(for: .deleteProfile)) { notification in - if let fileName = user.attachments?.Profile?.attachmentID { - isHideLoader = false - viewModel.deleteAttachment(attachmentID: fileName) - viewModel.deleteFileFromDocument(fileName: fileName) - } - } - .onReceive(viewModel.hideLoader) { value in - isHideLoader = true - NotificationCenter.default.post(name: .imageUploaded, object: nil) - presentationMode.wrappedValue.dismiss() + .listRowBackground(Color.otfCellBackground) + .navigationBarTitleDisplayMode(.inline) + .navigationBarTitle(Text(ModuleAppYmlReader().profileData?.title ?? "Profile")) + .overlay(LoaderView(tintColor: .black, scaleSize: 2.0).padding(.bottom, 50).hidden(isHideLoader)) + + .onReceive(NotificationCenter.default.publisher(for: .databaseSuccessfllySynchronized)) { _ in + viewModel.fetchPatient(userId: user.id) + } + .onReceive(viewModel.patientPublisher) { patient in + patientData(patient: patient) + } + .onReceive(viewModel.profileImageData) { data in + let dataDict: [String: Data] = ["imageData": data] + NotificationCenter.default.post(name: .imageUploaded, object: dataDict) + presentationMode.wrappedValue.dismiss() + } + + .onReceive(NotificationCenter.default.publisher(for: .deleteProfile)) { _ in + if let fileName = user.attachments?.profile?.attachmentID { + isHideLoader = false + viewModel.deleteAttachment(attachmentID: fileName) + viewModel.deleteFileFromDocument(fileName: fileName) } - .onAppear { - if let attachmentID = user.attachments?.Profile?.attachmentID { - if profileImageData.retriveFile(fileName: attachmentID) != nil {} else { - viewModel.downloadFile(attachmentID: attachmentID) - } + } + .onReceive(viewModel.hideLoader) { _ in + isHideLoader = true + NotificationCenter.default.post(name: .imageUploaded, object: nil) + presentationMode.wrappedValue.dismiss() + } + .onAppear { + if let attachmentID = user.attachments?.profile?.attachmentID { + if profileImageData.retriveFile(fileName: attachmentID) != nil {} else { + viewModel.downloadFile(attachmentID: attachmentID) } } } - - + } func patientData(patient: OCKPatient) { self.user = patient @@ -238,7 +216,6 @@ struct UpdateUserProfileDetailView: View { } func updatePatient() { - // TODO: - Update user's profile here var name = PersonNameComponents() name.givenName = firstName name.familyName = lastName @@ -247,15 +224,14 @@ struct UpdateUserProfileDetailView: View { user.sex = gender.carekitGender viewModel.updatePatient(user: user) } - + private func setDateString() { - let formatter = DateFormatter() - formatter.dateFormat = "MM-dd-yyyy" - dob = formatter.string(from: self.birthday) - } + let formatter = DateFormatter() + formatter.dateFormat = "MM-dd-yyyy" + dob = formatter.string(from: self.birthday) + } } - // MARK: - Labels extension UpdateUserProfileDetailView { var name: String { @@ -265,19 +241,19 @@ extension UpdateUserProfileDetailView { } return "\(givenName) \(familyName)" } - + var infoHeader: String { ModuleAppYmlReader().profileData?.profileInfoHeader ?? Constants.CustomiseStrings.basicInformation } - + var firstNameTitle: String { ModuleAppYmlReader().profileData?.firstName ?? Constants.CustomiseStrings.firstName } - + var lastNameTitle: String { ModuleAppYmlReader().profileData?.lastName ?? Constants.CustomiseStrings.lastName } - + var otherInfoHeader: String { ModuleAppYmlReader().profileData?.otherInfo ?? Constants.CustomiseStrings.otherInformation } @@ -288,10 +264,10 @@ extension GenderType { switch self { case .male: return .male - + case .female: return .female - + case .other: return .other("") } @@ -303,10 +279,10 @@ extension OCKBiologicalSex { switch self { case .male: return .male - + case .female: return .female - + default: return .other } @@ -315,17 +291,17 @@ extension OCKBiologicalSex { struct IconView: View { @Binding var image: UIImage? - @State var hashFileKey : String + @State var hashFileKey: String @State var fileName: String @State var imageViews = Data() @State private var shouldPresentImagePicker = false @State private var shouldPresentActionScheet = false @State private var sourceType = UIImagePickerController.SourceType.photoLibrary @StateObject var viewModel: UpdateUserViewModel - @State var imageUI : UIImage? = nil - + @State var imageUI: UIImage? + var imageView: Image { - + if let image = image { return Image(uiImage: image) } else if let imageUI = imageUI { @@ -333,9 +309,9 @@ struct IconView: View { } else { return Image.avatar } - + } - + var body: some View { imageView .iconStyle() @@ -346,26 +322,26 @@ struct IconView: View { } .onLoad { DispatchQueue.main.async { - if let retriveImageData = imageViews.retriveFile(fileName: fileName) { + if let retriveImageData = imageViews.retriveFile(fileName: fileName) { imageUI = viewModel.dataToImageWithoutDecryption(data: retriveImageData, key: hashFileKey) } } } .actionSheet(isPresented: $shouldPresentActionScheet) { () -> ActionSheet in ActionSheet(title: Text(Constants.CustomiseStrings.chooseMode) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), message: Text(Constants.CustomiseStrings.chooseProfileImage) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)), buttons: [ActionSheet.Button.default(Text(Constants.CustomiseStrings.camera), action: { - self.shouldPresentImagePicker = true - self.sourceType = .camera - }), ActionSheet.Button.default(Text(Constants.CustomiseStrings.photoLibrary), action: { - self.shouldPresentImagePicker = true - self.sourceType = .photoLibrary - }), ActionSheet.Button.destructive(Text(Constants.CustomiseStrings.deleteProfile), action: { - NotificationCenter.default.post(name: .deleteProfile, object: nil) - }), ActionSheet.Button.cancel()]) + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont), buttons: [ActionSheet.Button.default(Text(Constants.CustomiseStrings.camera), action: { + self.shouldPresentImagePicker = true + self.sourceType = .camera + }), ActionSheet.Button.default(Text(Constants.CustomiseStrings.photoLibrary), action: { + self.shouldPresentImagePicker = true + self.sourceType = .photoLibrary + }), ActionSheet.Button.destructive(Text(Constants.CustomiseStrings.deleteProfile), action: { + NotificationCenter.default.post(name: .deleteProfile, object: nil) + }), ActionSheet.Button.cancel()]) } .accessibilityLabel("Profile image") .accessibilityAddTraits(.isButton) @@ -374,24 +350,22 @@ struct IconView: View { } } - struct SUImagePickerView: UIViewControllerRepresentable { - var sourceType: UIImagePickerController.SourceType = .photoLibrary @Binding var image: UIImage? @Binding var isPresented: Bool - + func makeCoordinator() -> ImagePickerViewCoordinator { return ImagePickerViewCoordinator(image: $image, isPresented: $isPresented) } - + func makeUIViewController(context: Context) -> UIImagePickerController { let pickerController = UIImagePickerController() pickerController.sourceType = sourceType pickerController.delegate = context.coordinator return pickerController } - + func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) { // Nothing to update here } @@ -399,22 +373,21 @@ struct SUImagePickerView: UIViewControllerRepresentable { class ImagePickerViewCoordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { - @Binding var image: UIImage? @Binding var isPresented: Bool - + init(image: Binding, isPresented: Binding) { self._image = image self._isPresented = isPresented } - - func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { + + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { self.image = image } self.isPresented = false } - + func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { self.isPresented = false } @@ -424,12 +397,10 @@ extension Array where Element == UInt8 { func bytesToHex(spacing: String) -> String { var hexString: String = "" var count = self.count - for byte in self - { - hexString.append(String(format:"%02X", byte)) - count = count - 1 - if count > 0 - { + for byte in self { + hexString.append(String(format: "%02X", byte)) + count -= 1 + if !isEmpty { hexString.append(spacing) } } diff --git a/OTFMagicBox/Profile/Views/UpdateUserProfileView.swift b/OTFMagicBox/Profile/Views/UpdateUserProfileView.swift index b6a36d99..aaf1341a 100644 --- a/OTFMagicBox/Profile/Views/UpdateUserProfileView.swift +++ b/OTFMagicBox/Profile/Views/UpdateUserProfileView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI @@ -38,115 +38,96 @@ import OTFUtilities struct UpdateUserProfileView: View { @StateObject private var networkManager = OTFNetworkObserver() - -// var user: String + + // var user: String var imageName: String? - + var image: UIImage { guard let imageName, let image = UIImage(named: imageName) else { return UIImage(named: "user_profile")! } return image } - - var textColor: Color { - guard let uiColor = YmlReader().appTheme?.textColor.color else { - return Color(UIColor.label) - } - return Color(uiColor) - } - + @State var showUserProfile = false let user: OCKPatient - let backgroudColor: UIColor - let tColor: UIColor - let cellBackgroundColor: UIColor @State var fetchFile = Data() - let headerColor: UIColor - let buttonColor: UIColor - let borderColor: UIColor - let sepratorColor: UIColor - - @StateObject private var viewModel = UpdateUserViewModel() - + var body: some View { HStack { - ZStack(alignment: .bottomTrailing) { - if let retriveImageData = fetchFile.retriveFile(fileName: user.attachments?.Profile?.attachmentID ?? "") { - let image = viewModel.showProfileImage(user: user, imageData: retriveImageData) - ProfileIcon(image: image) - - } else { - if !fetchFile.isEmpty { - - let image = viewModel.showProfileImage(user: user, imageData: fetchFile) - ProfileIcon(image: image) - } else { - ProfileIcon(image: UIImage(named: ModuleAppYmlReader().profileData?.profileImage ?? "user_profile")!) - } - } - NetworkIndicator(status: networkManager.status) - }.padding(.trailing) - VStack(alignment: .leading) { - Text(user.remoteID ?? "") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .foregroundColor(textColor) - - Text("Edit your profile") - .font(.footnote) - .foregroundColor(textColor) - } - Spacer() - Image(systemName: "chevron.right") - .foregroundColor(Color(UIColor.tertiaryLabel)) - .font(.footnote.weight(.semibold)) - } - - .gesture(TapGesture().onEnded({ - self.showUserProfile.toggle() - })).sheet(isPresented: $showUserProfile, onDismiss: { - - }, content: { - UpdateUserProfileDetailView(user: user, backgroudColor: backgroudColor, textColor: tColor, cellBackgroundColor: cellBackgroundColor, headerColor: headerColor, buttonColor: buttonColor, borderColor: borderColor, sepratorColor: sepratorColor) - }) - .background(Color(backgroudColor)) - .onReceive(NotificationCenter.default.publisher(for: .imageUploaded)) { notification in - if let value = notification.object as? [String: Data] { - if let data = value.first?.value{ - fetchFile = data + ZStack(alignment: .bottomTrailing) { + if let retriveImageData = fetchFile.retriveFile(fileName: user.attachments?.profile?.attachmentID ?? "") { + let image = viewModel.showProfileImage(user: user, imageData: retriveImageData) + ProfileIcon(image: image) + + } else { + if !fetchFile.isEmpty { + + let image = viewModel.showProfileImage(user: user, imageData: fetchFile) + ProfileIcon(image: image) + } else { + ProfileIcon(image: UIImage(named: ModuleAppYmlReader().profileData?.profileImage ?? "user_profile")!) } } + NetworkIndicator(status: networkManager.status) + }.padding(.trailing) + VStack(alignment: .leading) { + Text(user.remoteID ?? "") + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) + .foregroundColor(.otfTextColor) + + Text("Edit your profile") + .font(.footnote) + .foregroundColor(.otfTextColor) } - .onReceive(NotificationCenter.default.publisher(for: .imageDownloaded)) { notification in - if let value = notification.object as? [String: Data] { - if let data = value.first?.value{ - fetchFile = data - } + Spacer() + Image(systemName: "chevron.right") + .foregroundColor(Color(UIColor.tertiaryLabel)) + .font(.footnote.weight(.semibold)) + } + + .gesture(TapGesture().onEnded({ + self.showUserProfile.toggle() + })).sheet(isPresented: $showUserProfile, onDismiss: { + + }, content: { + UpdateUserProfileDetailView(user: user) + }) + .background(Color.otfCellBackground) + .onReceive(NotificationCenter.default.publisher(for: .imageUploaded)) { notification in + if let value = notification.object as? [String: Data] { + if let data = value.first?.value { + fetchFile = data } } - .onReceive(NotificationCenter.default.publisher(for: .deleteProfile)) { notification in - fetchFile = Data() - } - .onReceive(viewModel.profileImageData) { data in - fetchFile = data + } + .onReceive(NotificationCenter.default.publisher(for: .imageDownloaded)) { notification in + if let value = notification.object as? [String: Data] { + if let data = value.first?.value { + fetchFile = data + } } - .onAppear() { - if let attachmentID = user.attachments?.Profile?.attachmentID { - if fetchFile.retriveFile(fileName: attachmentID) != nil {} else { - viewModel.downloadFile(attachmentID: attachmentID) - } + } + .onReceive(NotificationCenter.default.publisher(for: .deleteProfile)) { _ in + fetchFile = Data() + } + .onReceive(viewModel.profileImageData) { data in + fetchFile = data + } + .onAppear { + if let attachmentID = user.attachments?.profile?.attachmentID { + if fetchFile.retriveFile(fileName: attachmentID) != nil {} else { + viewModel.downloadFile(attachmentID: attachmentID) } } + } } } - - struct NetworkIndicator: View { var status: OTFNetworkStatus - + var body: some View { ZStack { Image(systemName: "cloud.fill") @@ -154,7 +135,7 @@ struct NetworkIndicator: View { .scaledToFit() .foregroundColor(backgroundColor.opacity(0.85)) .frame(width: Metrics.NETWORK_INDICATOR_WIDTH) - + Image(systemName: accessory) .resizable() .scaledToFit() @@ -163,7 +144,7 @@ struct NetworkIndicator: View { .padding(.top, 3) } } - + var backgroundColor: Color { switch status { case .offline: @@ -174,7 +155,7 @@ struct NetworkIndicator: View { return .gray } } - + var accessory: String { switch status { case .offline: diff --git a/OTFMagicBox/Profile/Views/WithdrawView.swift b/OTFMagicBox/Profile/Views/WithdrawView.swift index 04292747..974f4b80 100644 --- a/OTFMagicBox/Profile/Views/WithdrawView.swift +++ b/OTFMagicBox/Profile/Views/WithdrawView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI @@ -37,29 +37,27 @@ import SwiftUI struct WithdrawView: View { @State var showWithdraw = false let title: String - let textColor: Color - - init(title: String, textColor: Color) { + + init(title: String) { self.title = title - self.textColor = textColor } - + var body: some View { HStack { Text(title) - .foregroundColor(textColor) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .foregroundColor(.otfTextColor) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) Spacer() Image(systemName: "chevron.right") - .foregroundColor(Color(UIColor.tertiaryLabel)) - .font(.footnote.weight(.semibold)) + .foregroundColor(Color(UIColor.tertiaryLabel)) + .font(.footnote.weight(.semibold)) }.frame(maxWidth: .infinity, minHeight: Metrics.TITLE_VIEW_HEIGHT) .contentShape(Rectangle()) .gesture(TapGesture().onEnded({ self.showWithdraw.toggle() })).sheet(isPresented: $showWithdraw, onDismiss: { - + }, content: { WithdrawalViewController() }) @@ -70,6 +68,6 @@ struct WithdrawView: View { struct WithdrawView_Previews: PreviewProvider { static var previews: some View { - WithdrawView(title: "Withdraw from Study", textColor: Color(YmlReader().appTheme?.textColor.color ?? UIColor.black)) + WithdrawView(title: "Withdraw from Study") } } diff --git a/OTFMagicBox/Profile/Views/WithdrawalViewController.swift b/OTFMagicBox/Profile/Views/WithdrawalViewController.swift index c3f592f2..1da2b01e 100644 --- a/OTFMagicBox/Profile/Views/WithdrawalViewController.swift +++ b/OTFMagicBox/Profile/Views/WithdrawalViewController.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import UIKit @@ -37,31 +37,31 @@ import SwiftUI import OTFResearchKit struct WithdrawalViewController: UIViewControllerRepresentable { - + func makeCoordinator() -> Coordinator { Coordinator() } typealias UIViewControllerType = ORKTaskViewController - + func updateUIViewController(_ taskViewController: ORKTaskViewController, context: Context) {} func makeUIViewController(context: Context) -> ORKTaskViewController { - + let instructionStep = ORKInstructionStep(identifier: "WithdrawlInstruction") instructionStep.title = ModuleAppYmlReader().withdrawl?.withdrawalInstructionTitle instructionStep.text = ModuleAppYmlReader().withdrawl?.withdrawalInstructionText - + let completionStep = ORKCompletionStep(identifier: "Withdraw") completionStep.title = ModuleAppYmlReader().withdrawl?.withdrawTitle completionStep.text = ModuleAppYmlReader().withdrawl?.withdrawText - + let withdrawTask = ORKOrderedTask(identifier: "Withdraw", steps: [instructionStep, completionStep]) - + // wrap that task on a view controller let taskViewController = ORKTaskViewController(task: withdrawTask, taskRun: nil) - + taskViewController.delegate = context.coordinator // enables `ORKTaskViewControllerDelegate` below - + // & present the VC! return taskViewController @@ -70,26 +70,23 @@ struct WithdrawalViewController: UIViewControllerRepresentable { class Coordinator: NSObject, ORKTaskViewControllerDelegate { public func taskViewController(_ taskViewController: ORKTaskViewController, didFinishWith reason: ORKTaskViewControllerFinishReason, error: Error?) { switch reason { - case .completed: - if (ORKPasscodeViewController.isPasscodeStoredInKeychain()) { - ORKPasscodeViewController.removePasscodeFromKeychain() - } - UserDefaultsManager.setOnboardingCompleted(false) - UserDefaults.standard.set(nil, forKey: Constants.prefCareKitDataInitDate) - UserDefaults.standard.set(nil, forKey: Constants.prefHealthRecordsLastUploaded) - - NotificationCenter.default.post(name: .onboardingDidComplete, object: false) - - try? CareKitManager.shared.wipe() - - fallthrough - default: - // otherwise dismiss onboarding without proceeding. - taskViewController.dismiss(animated: true, completion: nil) - + case .completed: + if ORKPasscodeViewController.isPasscodeStoredInKeychain() { + ORKPasscodeViewController.removePasscodeFromKeychain() + } + UserDefaultsManager.setOnboardingCompleted(false) + UserDefaults.standard.set(nil, forKey: Constants.prefCareKitDataInitDate) + UserDefaults.standard.set(nil, forKey: Constants.prefHealthRecordsLastUploaded) + + NotificationCenter.default.post(name: .onboardingDidComplete, object: false) + + try? CareKitStoreManager.shared.wipe() + + fallthrough + default: + // otherwise dismiss onboarding without proceeding. + taskViewController.dismiss(animated: true, completion: nil) } } } - } - diff --git a/OTFMagicBox/SceneDelegate.swift b/OTFMagicBox/SceneDelegate.swift index 782b16f2..f558b1f0 100644 --- a/OTFMagicBox/SceneDelegate.swift +++ b/OTFMagicBox/SceneDelegate.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import UIKit @@ -38,7 +38,7 @@ import SwiftUI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - + private var isLaunched = true func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { @@ -49,6 +49,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Create the SwiftUI view that provides the window contents. OTFTheraforgeNetwork.shared.configureNetwork() let contentView = LaunchView() + .appStyle(.init(from: OTFYamlStyle(style: YmlReader().appStyle))) // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { @@ -69,16 +70,16 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - + // We sync the DB when the user is already logged in and we show the `MainView`. // This is to avoid multiple sync operations at launch time. guard !isLaunched else { isLaunched = false return } - + CloudantSyncManager.shared.syncCloudantStore(notifyWhenDone: true) { _ in - // + } } @@ -97,7 +98,4 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } - - } - diff --git a/OTFMagicBox/Schedule/ScheduleViewController.swift b/OTFMagicBox/Schedule/ScheduleViewController.swift index a9e26304..6873d4a1 100644 --- a/OTFMagicBox/Schedule/ScheduleViewController.swift +++ b/OTFMagicBox/Schedule/ScheduleViewController.swift @@ -1,105 +1,112 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFCareKit +import OTFCareKitUI import OTFCareKitStore import UIKit import OTFUtilities import SwiftUI class ScheduleViewController: OCKDailyPageViewController { - + override func viewDidLoad() { super.viewDidLoad() title = Constants.CustomiseStrings.schedule - + NotificationCenter.default.addObserver(self, selector: #selector(didReceiveStoreChangeNotification(_:)), name: .databaseSuccessfllySynchronized, object: nil) - + NotificationCenter.default.addObserver(self, selector: #selector(deleteProfileEventNotification(_:)), name: .deleteUserAccount, object: nil) } - + override func viewDidDisappear(_ animated: Bool) { NotificationCenter.default.removeObserver(self, name: .deleteUserAccount, object: nil) } - + @objc private func didReceiveStoreChangeNotification(_ notification: Notification) { reload() } - + @objc private func deleteProfileEventNotification(_ notification: Notification) { - - self.alertWithAction(title: Constants.CustomiseStrings.accountDeleted, message: Constants.deleteAccount) { action in + + self.alertWithAction(title: Constants.CustomiseStrings.accountDeleted, message: Constants.deleteAccount) { _ in OTFTheraforgeNetwork.shared.moveToOnboardingView() } - + } - - override func dailyPageViewController(_ dailyPageViewController: OCKDailyPageViewController, - prepare listViewController: OCKListViewController, for date: Date) { - + + override func dailyPageViewController( + _ dailyPageViewController: OCKDailyPageViewController, + prepare listViewController: OCKListViewController, + for date: Date) { + var query = OCKTaskQuery(for: date) query.excludesTasksWithNoEvents = true + + if let ockView = listViewController.view as? OCKView { + ockView.customStyle = OTFStyle(from: OTFYamlStyle(style: YmlReader().appStyle)) + } DispatchQueue.global(qos: .default).async { [unowned self] in storeManager.store.fetchAnyTasks(query: query, callbackQueue: .main) { result in switch result { case .failure(let error): OTFError("error in fetching fetchAnyTasks %{public}@", error.localizedDescription) - + case .success(let tasks): // Add a non-CareKit view into the list /* - let tipTitle = "Customize your app!" - let tipText = "" + let tipTitle = "Customize your app!" + let tipText = "" - // Only show the tip view on the current date - if Calendar.current.isDate(date, inSameDayAs: Date()) { - let tipView = TipView() - tipView.headerView.titleLabel.text = tipTitle - tipView.headerView.detailLabel.text = tipText - tipView.imageView.image = UIImage(named: "GraphicOperatingSystem") - listViewController.appendView(tipView, animated: false) - } + // Only show the tip view on the current date + if Calendar.current.isDate(date, inSameDayAs: Date()) { + let tipView = TipView() + tipView.headerView.titleLabel.text = tipTitle + tipView.headerView.detailLabel.text = tipText + tipView.imageView.image = UIImage(named: "GraphicOperatingSystem") + listViewController.appendView(tipView, animated: false) + } */ // Filter the tasks that exist on the given date let todayTasks = tasks.filter({ $0.schedule.exists(onDay: date) }) - + // If there's no task on the given date then show no tasks card guard !todayTasks.isEmpty else { let tipTitle = Constants.CustomiseStrings.noTasks @@ -110,7 +117,7 @@ class ScheduleViewController: OCKDailyPageViewController { listViewController.appendView(tipView, animated: false) return } - + todayTasks.forEach { task in guard task.schedule.exists(onDay: date) else { return } if task.viewType == .instruction { diff --git a/OTFMagicBox/Schedule/ScheduleViewControllerRepresentable.swift b/OTFMagicBox/Schedule/ScheduleViewControllerRepresentable.swift index 19dc9c54..67b141fc 100644 --- a/OTFMagicBox/Schedule/ScheduleViewControllerRepresentable.swift +++ b/OTFMagicBox/Schedule/ScheduleViewControllerRepresentable.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFCareKitStore @@ -38,16 +38,17 @@ import Foundation import UIKit import SwiftUI import OTFResearchKit +import OTFCareKitUI struct ScheduleViewControllerRepresentable: UIViewControllerRepresentable { - + typealias UIViewControllerType = UIViewController - + func updateUIViewController(_ taskViewController: UIViewController, context: Context) {} + func makeUIViewController(context: Context) -> UIViewController { - let manager = CareKitManager.shared + let manager = CareKitStoreManager.shared let vc = ScheduleViewController(storeManager: manager.synchronizedStoreManager) return UINavigationController(rootViewController: vc) } - } diff --git a/OTFMagicBox/Schedule/SurveyItemViewController.swift b/OTFMagicBox/Schedule/SurveyItemViewController.swift index bb4c1f61..80e18c40 100644 --- a/OTFMagicBox/Schedule/SurveyItemViewController.swift +++ b/OTFMagicBox/Schedule/SurveyItemViewController.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -51,7 +51,14 @@ class SurveyItemViewController: OCKInstructionsTaskViewController, ORKTaskViewCo } // 2b. If the user attempted to mark the task complete, display a ResearchKit survey. - let answerFormat = ORKAnswerFormat.scale(withMaximumValue: 5, minimumValue: 1, defaultValue: 5, step: 1, vertical: false, maximumValueDescription: "A LOT!", minimumValueDescription: "a little") + let answerFormat = ORKAnswerFormat.scale( + withMaximumValue: 5, + minimumValue: 1, + defaultValue: 5, + step: 1, + vertical: false, + maximumValueDescription: "A LOT!", + minimumValueDescription: "a little") let feedbackStep = ORKQuestionStep(identifier: "feedback", title: "Feedback", question: "How are you liking SampleApp?", answer: answerFormat) let surveyTask = ORKOrderedTask(identifier: "feedback", steps: [feedbackStep]) let surveyViewController = ORKTaskViewController(task: surveyTask, taskRun: nil) @@ -70,14 +77,19 @@ class SurveyItemViewController: OCKInstructionsTaskViewController, ORKTaskViewCo } // 4a. Retrieve the result from the ResearchKit survey - let survey = taskViewController.result.results!.first(where: { $0.identifier == "feedback" }) as! ORKStepResult - let feedbackResult = survey.results!.first as! ORKScaleQuestionResult + guard let survey = taskViewController.result.results!.first(where: { $0.identifier == "feedback" }) as? ORKStepResult else { + fatalError("ORKStepResult failed while casting") + } + guard let feedbackResult = survey.results!.first as? ORKScaleQuestionResult else { + fatalError("ORKScaleQuestionResult failed while casting") + } +// let feedbackResult = survey.results!.first as! ORKScaleQuestionResult let answer = Int(truncating: feedbackResult.scaleAnswer!) // 4b. Save the result into CareKit's store controller.appendOutcomeValue(value: answer, at: IndexPath(item: 0, section: 0), completion: nil) - - } + + } } class SurveyItemViewSynchronizer: OCKInstructionsTaskViewSynchronizer { @@ -88,14 +100,14 @@ class SurveyItemViewSynchronizer: OCKInstructionsTaskViewSynchronizer { instructionsView.completionButton.label.text = "Start" return instructionsView } - + override func updateView(_ view: OCKInstructionsTaskView, context: OCKSynchronizationContext) { super.updateView(view, context: context) // Check if an answer exists or not and set the detail label accordingly let element: [OCKAnyEvent]? = context.viewModel.first let firstEvent = element?.first - + if let answer = firstEvent?.outcome?.values.first?.integerValue { view.headerView.detailLabel.text = "Theraforge Rating: \(answer)" } else { diff --git a/OTFMagicBox/Schedule/TipView.swift b/OTFMagicBox/Schedule/TipView.swift index ba4e94ab..a837f18f 100644 --- a/OTFMagicBox/Schedule/TipView.swift +++ b/OTFMagicBox/Schedule/TipView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import UIKit diff --git a/OTFMagicBox/StaticViews/CardBackground.swift b/OTFMagicBox/StaticViews/CardBackground.swift index 8fbf1062..34e1c7c3 100644 --- a/OTFMagicBox/StaticViews/CardBackground.swift +++ b/OTFMagicBox/StaticViews/CardBackground.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -46,9 +46,8 @@ struct CardBackground: View { var body: some View { ScrollView { VStack { content } - .padding() + .padding() } .background(Color(UIColor.systemGroupedBackground)) } } - diff --git a/OTFMagicBox/StaticViews/CareKit/CareKitTaskViews.swift b/OTFMagicBox/StaticViews/CareKit/CareKitTaskViews.swift index fed6eadf..79b5efb7 100644 --- a/OTFMagicBox/StaticViews/CareKit/CareKitTaskViews.swift +++ b/OTFMagicBox/StaticViews/CareKit/CareKitTaskViews.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -39,16 +39,16 @@ import OTFCareKitStore // MARK: - Instruction Task View struct InstructionTaskView: UIViewControllerRepresentable { typealias UIViewControllerType = OCKInstructionsTaskViewController - + let task: OCKAnyTask let date: Date let storeManager: OCKSynchronizedStoreManager - + func makeUIViewController(context: Context) -> OCKInstructionsTaskViewController { let instructionCard = OCKInstructionsTaskViewController(task: task, eventQuery: .init(for: date), storeManager: storeManager) return instructionCard } - + func updateUIViewController(_ uiViewController: OCKInstructionsTaskViewController, context: Context) {} } @@ -66,14 +66,14 @@ struct GridTaskView: UIViewRepresentable { let task: OCKAnyTask let date: Date let storeManager: OCKSynchronizedStoreManager - + func makeUIView(context: Context) -> some UIView { let gridCard = OCKGridTaskViewController(task: task, eventQuery: .init(for: date), storeManager: storeManager) return gridCard.view } - + func updateUIView(_ uiView: UIViewType, context: Context) { - + } } @@ -90,14 +90,14 @@ struct SimpleTaskView: UIViewRepresentable { let task: OCKAnyTask let date: Date let storeManager: OCKSynchronizedStoreManager - + func makeUIView(context: Context) -> some UIView { let simpleCard = OCKSimpleTaskViewController(task: task, eventQuery: .init(for: date), storeManager: storeManager) return simpleCard.view } - + func updateUIView(_ uiView: UIViewType, context: Context) { - + } } @@ -115,14 +115,14 @@ struct ChecklistTaskView: UIViewRepresentable { let task: OCKAnyTask let date: Date let storeManager: OCKSynchronizedStoreManager - + func makeUIView(context: Context) -> some UIView { let checklistCard = OCKChecklistTaskViewController(task: task, eventQuery: .init(for: date), storeManager: storeManager) return checklistCard.view } - + func updateUIView(_ uiView: UIViewType, context: Context) { - + } } @@ -140,14 +140,14 @@ struct ButtonLogTaskView: UIViewRepresentable { let task: OCKAnyTask let date: Date let storeManager: OCKSynchronizedStoreManager - + func makeUIView(context: Context) -> some UIView { let buttonLogCard = OCKButtonLogTaskViewController(task: task, eventQuery: .init(for: date), storeManager: storeManager) return buttonLogCard.view } - + func updateUIView(_ uiView: UIViewType, context: Context) { - + } } @@ -179,7 +179,7 @@ var dummyTask: OCKAnyTask { let task = OCKTask(id: OCKStore.Tasks.doxylamine.rawValue, title: OCKStore.Tasks.doxylamine.rawValue, carePlanUUID: nil, schedule: schedule) - + return task } diff --git a/OTFMagicBox/StaticViews/CareKit/ContactsSection.swift b/OTFMagicBox/StaticViews/CareKit/ContactsSection.swift index 02ea94c3..001e901b 100644 --- a/OTFMagicBox/StaticViews/CareKit/ContactsSection.swift +++ b/OTFMagicBox/StaticViews/CareKit/ContactsSection.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -35,42 +35,39 @@ import SwiftUI struct ContactsSection: View { - let cellbackgroundColor: UIColor - let headerColor: UIColor - let textColor: UIColor var body: some View { Section(header: Text(ModuleAppYmlReader().careKitModel?.contactHeader ?? "Contact") - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(Color(headerColor))) { + .font(Font.otfheaderTitleFont) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(Color.otfHeaderColor)) { ForEach(ContactStyle.allCases, id: \.rawValue) { row in - + NavigationLink(destination: ContactDestination(style: row)) { Text(String(row.rawValue.capitalized)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .fontWeight(Font.otfFontWeight) } - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(Font.otfAppFont) .foregroundColor(.otfTextColor) .listRowBackground(Color.otfCellBackground) } - .listRowBackground(Color(cellbackgroundColor)) - .foregroundColor(Color(textColor)) + .listRowBackground(Color.otfCellBackground) + .foregroundColor(.otfTextColor) } } } struct ContactsView_Previews: PreviewProvider { static var previews: some View { - ContactsSection(cellbackgroundColor: UIColor(), headerColor: UIColor(), textColor: UIColor()) + ContactsSection() } } private struct ContactDestination: View { - + @Environment(\.storeManager) private var storeManager - + let style: ContactStyle - + var body: some View { ZStack { Color(UIColor.systemGroupedBackground) @@ -82,34 +79,33 @@ private struct ContactDestination: View { } private enum ContactStyle: String, CaseIterable { - case simple , detailed - + case simple, detailed + var rawValue: String { - get { - switch self { - case .simple: - return ModuleAppYmlReader().careKitModel?.simple ?? "" - case .detailed: - return ModuleAppYmlReader().careKitModel?.detailed ?? "" - } - } - } + switch self { + case .simple: + return ModuleAppYmlReader().careKitModel?.simple ?? "" + case .detailed: + return ModuleAppYmlReader().careKitModel?.detailed ?? "" + } + } } import OTFCareKit +import OTFCareKitUI import OTFCareKitStore private struct AdaptedContactView: UIViewControllerRepresentable { - + let style: ContactStyle let storeManager: OCKSynchronizedStoreManager - + func makeUIViewController(context: Context) -> UIViewController { let listViewController = OCKListViewController() - + let spacer = UIView(frame: .init(origin: .zero, size: .init(width: 0, height: 32))) listViewController.appendView(spacer, animated: false) - + let viewController: UIViewController? switch style { case .simple: @@ -117,10 +113,13 @@ private struct AdaptedContactView: UIViewControllerRepresentable { case .detailed: viewController = OCKDetailedContactViewController(contactID: OCKStore.Contacts.matthew.rawValue, storeManager: storeManager) } - + viewController.map { listViewController.appendViewController($0, animated: false) } + if let ockView = listViewController.view as? OCKView { + ockView.customStyle = OTFStyle(from: OTFYamlStyle(style: YmlReader().appStyle)) + } return listViewController } - + func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } diff --git a/OTFMagicBox/StaticViews/CareKit/TasksSection.swift b/OTFMagicBox/StaticViews/CareKit/TasksSection.swift index a147e53f..6f9b8e75 100644 --- a/OTFMagicBox/StaticViews/CareKit/TasksSection.swift +++ b/OTFMagicBox/StaticViews/CareKit/TasksSection.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -38,42 +38,39 @@ import OTFCareKitUI import OTFCareKitStore struct TaskSection: View { - let cellbackgroundColor: UIColor - let headerColor: UIColor - let textColor: UIColor var body: some View { - Section(header: Text(ModuleAppYmlReader().careKitModel?.taskHeader ?? "Task").font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(Color(headerColor))) { + Section(header: Text(ModuleAppYmlReader().careKitModel?.taskHeader ?? "Task").font(.otfheaderTitleFont) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(.otfHeaderColor)) { ForEach(TaskStyle.allCases, id: \.rawValue) { style in if style.supportsSwiftUI || style.supportsUIKit { - + NavigationLink(destination: TaskDestination(style: style)) { Text(style.rawValue.capitalized) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .fontWeight(Font.otfFontWeight) } .foregroundColor(.otfTextColor) .listRowBackground(Color.otfCellBackground) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(Font.otfAppFont) } } - .listRowBackground(Color(cellbackgroundColor)) - .foregroundColor(Color(textColor)) + .listRowBackground(Color.otfCellBackground) + .foregroundColor(.otfTextColor) } } } struct TaskDestination: View { - + @Environment(\.storeManager) private var storeManager - + let style: TaskStyle - + var body: some View { ZStack { Color(UIColor.systemGroupedBackground) .edgesIgnoringSafeArea(.all) - + if style.supportsSwiftUI && style.supportsUIKit { PlatformPicker { AdaptedTaskView(style: style, storeManager: storeManager) @@ -90,8 +87,8 @@ struct TaskDestination: View { } } } - .navigationBarTitle(Text(style.rawValue.capitalized).font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), displayMode: .inline) + .navigationBarTitle(Text(style.rawValue.capitalized).font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), displayMode: .inline) } } @@ -100,42 +97,38 @@ enum TaskCategory: String, Codable { } enum TaskStyle: String, CaseIterable, Codable { - + case simple, instruction, buttonLog case grid, checklist case labeledValue = "labeled value", numericProgress = "Numeric Progress" - - var rawValue: String { - get { - switch self { - case .simple: - return ModuleAppYmlReader().careKitModel?.simple ?? "" - case .instruction: - return ModuleAppYmlReader().careKitModel?.instruction ?? "" - case .buttonLog: - return ModuleAppYmlReader().careKitModel?.buttonLog ?? "" - case .grid: - return ModuleAppYmlReader().careKitModel?.grid ?? "" - case .checklist: - return ModuleAppYmlReader().careKitModel?.checklist ?? "" - case .labeledValue: - return ModuleAppYmlReader().careKitModel?.labeledValue ?? "" - case .numericProgress: - return ModuleAppYmlReader().careKitModel?.numericProgress ?? "" - } - } - } - + switch self { + case .simple: + return ModuleAppYmlReader().careKitModel?.simple ?? "" + case .instruction: + return ModuleAppYmlReader().careKitModel?.instruction ?? "" + case .buttonLog: + return ModuleAppYmlReader().careKitModel?.buttonLog ?? "" + case .grid: + return ModuleAppYmlReader().careKitModel?.grid ?? "" + case .checklist: + return ModuleAppYmlReader().careKitModel?.checklist ?? "" + case .labeledValue: + return ModuleAppYmlReader().careKitModel?.labeledValue ?? "" + case .numericProgress: + return ModuleAppYmlReader().careKitModel?.numericProgress ?? "" + } + } + var supportsSwiftUI: Bool { guard #available(iOS 14, *) else { return false } - + switch self { case .simple, .instruction, .labeledValue, .numericProgress: return true case .grid, .checklist, .buttonLog: return false } } - + var supportsUIKit: Bool { switch self { case .simple, .instruction, .grid, .checklist, .buttonLog: return true @@ -146,11 +139,11 @@ enum TaskStyle: String, CaseIterable, Codable { @available(iOS 14.0, *) struct TaskView: View { - + @Environment(\.storeManager) private var storeManager - + let style: TaskStyle - + var body: some View { CardBackground { switch style { @@ -172,24 +165,25 @@ struct TaskView: View { instructions: controller.viewModel?.instructions.map(Text.init), isComplete: controller.viewModel?.isComplete ?? false) } - + // Static view - OTFCareKitUI.NumericProgressTaskView(title: Text("Steps (Static)").font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + OTFCareKitUI.NumericProgressTaskView(title: Text("Steps (Static)").font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), progress: Text("0"), goal: Text("100"), isComplete: false) - + // Static view - OTFCareKitUI.NumericProgressTaskView(title: Text("Steps (Static)").font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + OTFCareKitUI.NumericProgressTaskView(title: Text("Steps (Static)") + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), progress: Text("0"), goal: Text("100"), isComplete: true) } case .labeledValue: VStack(spacing: 16) { - + // HealthKit linked view OTFCareKit.LabeledValueTaskView(taskID: OCKHealthKitPassthroughStore.Tasks.steps.rawValue, eventQuery: .init(for: Date()), storeManager: storeManager) { controller in @@ -197,21 +191,22 @@ struct TaskView: View { detail: controller.viewModel?.detail.map(Text.init), state: .fromViewModel(state: controller.viewModel?.state)) } - + // Static view - LabeledValueTaskView(title: Text("Heart Rate (Static)").font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)), - detail: Text("Anytime").font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + LabeledValueTaskView(title: Text("Heart Rate (Static)").font(Font.otfAppFont), + detail: Text("Anytime").font(Font.otfAppFont) + .fontWeight(YmlReader().appStyle.textWeight.fontWeight), state: .complete(Text("62"), Text("BPM"))) - + // Static view - LabeledValueTaskView(title: Text("Heart Rate (Static)").font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), - detail: Text("Anytime").font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + LabeledValueTaskView(title: Text("Heart Rate (Static)") + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), + detail: Text("Anytime").font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), state: .incomplete(Text("NO DATA") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)))) + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont))) } default: EmptyView() @@ -221,16 +216,16 @@ struct TaskView: View { } struct AdaptedTaskView: UIViewControllerRepresentable { - + let style: TaskStyle let storeManager: OCKSynchronizedStoreManager - + func makeUIViewController(context: Context) -> UIViewController { let listViewController = OCKListViewController() - + let spacer = UIView(frame: .init(origin: .zero, size: .init(width: 0, height: 32))) listViewController.appendView(spacer, animated: false) - + let taskViewController: UIViewController? switch style { case .simple: @@ -251,21 +246,24 @@ struct AdaptedTaskView: UIViewControllerRepresentable { case .labeledValue, .numericProgress: taskViewController = nil } - + taskViewController.map { listViewController.appendViewController($0, animated: false) } + if let ockView = listViewController.view as? OCKView { + ockView.customStyle = OTFStyle(from: OTFYamlStyle(style: YmlReader().appStyle)) + } return listViewController } - + func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } private extension LabeledValueTaskViewState { - + static func fromViewModel(state: LabeledValueTaskViewModel.State?) -> Self { guard let state = state else { return .incomplete(Text("")) } - + switch state { case let .complete(value, label): return .complete(Text(value), label.map(Text.init)) @@ -274,52 +272,50 @@ private extension LabeledValueTaskViewState { } } } - - struct TasksSection: View { @StateObject var viewModel: TasksViewModel - + var body: some View { List { Section(header: Text("Simple Task") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) { + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont)) { if let simpleTask = self.viewModel.simpleTask { SimpleTaskView(task: simpleTask, date: Date(), storeManager: viewModel.syncStoreManager) } } - + Section(header: Text("Instruction Task") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) { + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont)) { if let instructionTask = self.viewModel.simpleTask { InstructionTaskView(task: instructionTask, date: Date(), storeManager: viewModel.syncStoreManager) } } - + Section(header: Text("Button Log Task") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) { + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont)) { if let buttonLogTask = self.viewModel.buttonLogTask { ButtonLogTaskView(task: buttonLogTask, date: Date(), storeManager: viewModel.syncStoreManager) } } - + Section(header: Text("Grid Task") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) { + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont)) { if let gridTask = self.viewModel.checklistTask { GridTaskView(task: gridTask, date: Date(), storeManager: viewModel.syncStoreManager) } } - + Section(header: Text("Checklist Task") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) { + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont)) { if let checklistTask = self.viewModel.checklistTask { ChecklistTaskView(task: checklistTask, date: Date(), storeManager: viewModel.syncStoreManager) @@ -327,15 +323,10 @@ struct TasksSection: View { } } .listStyle(GroupedListStyle()) -// .onLoad { -// UITableView.appearance().backgroundColor = YmlReader().appTheme?.backgroundColor.color -// UITableViewCell.appearance().backgroundColor = YmlReader().appTheme?.backgroundColor.color -// UITableView.appearance().separatorColor = YmlReader().appTheme?.separatorColor.color -// } } } -struct TasksSection_Preview: PreviewProvider { +struct TasksSectionPreview: PreviewProvider { static var previews: some View { let viewModel = TasksViewModel(OCKStoreManager.shared.synchronizedStoreManager) let tasksSection = TasksSection(viewModel: viewModel) diff --git a/OTFMagicBox/StaticViews/CareKit/TasksViewModel.swift b/OTFMagicBox/StaticViews/CareKit/TasksViewModel.swift index c5b5ac7c..77809f36 100644 --- a/OTFMagicBox/StaticViews/CareKit/TasksViewModel.swift +++ b/OTFMagicBox/StaticViews/CareKit/TasksViewModel.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -39,17 +39,17 @@ import OTFUtilities class TasksViewModel: ObservableObject { let syncStoreManager: OCKSynchronizedStoreManager - - @Published var simpleTask: OCKAnyTask? = nil - @Published var instructionTask: OCKAnyTask? = nil - @Published var buttonLogTask: OCKAnyTask? = nil - @Published var gridTask: OCKAnyTask? = nil - @Published var checklistTask: OCKAnyTask? = nil - + + @Published var simpleTask: OCKAnyTask? + @Published var instructionTask: OCKAnyTask? + @Published var buttonLogTask: OCKAnyTask? + @Published var gridTask: OCKAnyTask? + @Published var checklistTask: OCKAnyTask? + init(_ storeManager: OCKSynchronizedStoreManager) { syncStoreManager = storeManager } - + func fetchTasks() { let identifiers = ["doxylamine", "nausea", "kegels", "steps", "heartRate"] var query = OCKTaskQuery(for: Date()) @@ -58,17 +58,17 @@ class TasksViewModel: ObservableObject { switch result { case .failure(let error): OTFError("error while fetching tasks %{public}@", error.localizedDescription) - + case .success(let tasks): if let kegelsTask = tasks.first(where: { $0.id == "kegels" }) { self.simpleTask = kegelsTask } - + // Create a card for the doxylamine task if there are events for it on this day. if let doxylamineTask = tasks.first(where: { $0.id == "doxylamine" }) { self.checklistTask = doxylamineTask } - + if let nauseaTask = tasks.first(where: { $0.id == "nausea" }) { self.buttonLogTask = nauseaTask } diff --git a/OTFMagicBox/StaticViews/PlatformPicker.swift b/OTFMagicBox/StaticViews/PlatformPicker.swift index 96568171..a41cc780 100644 --- a/OTFMagicBox/StaticViews/PlatformPicker.swift +++ b/OTFMagicBox/StaticViews/PlatformPicker.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -52,10 +52,9 @@ struct PlatformPicker: View { VStack(spacing: 0) { VStack { - Picker(selection: $selectedPlatform, label: Text("Platform") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) { + .fontWeight(Font.otfFontWeight) + .font(Font.otfAppFont)) { ForEach(0..: View { } } } - diff --git a/OTFMagicBox/StaticViews/RK UI/RKTasks.swift b/OTFMagicBox/StaticViews/RK UI/RKTasks.swift index 5860a5b1..f5cb9d47 100644 --- a/OTFMagicBox/StaticViews/RK UI/RKTasks.swift +++ b/OTFMagicBox/StaticViews/RK UI/RKTasks.swift @@ -10,12 +10,12 @@ import SwiftUI struct RKTasks: UIViewControllerRepresentable { typealias UIViewControllerType = TaskListViewController - + func makeUIViewController(context: Context) -> TaskListViewController { return TaskListViewController() } - + func updateUIViewController(_ uiViewController: TaskListViewController, context: Context) { - + } } diff --git a/OTFMagicBox/StaticViews/RK UI/SurveysList.swift b/OTFMagicBox/StaticViews/RK UI/SurveysList.swift index 03260135..3ddf912c 100644 --- a/OTFMagicBox/StaticViews/RK UI/SurveysList.swift +++ b/OTFMagicBox/StaticViews/RK UI/SurveysList.swift @@ -8,119 +8,104 @@ import SwiftUI struct SurveysList: View { - let cellbackgroundColor: UIColor - let headerColor: UIColor - let textColor: UIColor var body: some View { Section(header: Text(ModuleAppYmlReader().researchKitModel?.surveysHeaderTitle ?? Constants.dataBucketSurveys) - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(Color(headerColor))) { + .font(.otfheaderTitleFont) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(.otfHeaderColor)) { ForEach(TaskListRow.sections[0].rows, id: \.rawValue) { row in NavigationLink(destination: TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea()) { Text(String(describing: row)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .fontWeight(Font.otfFontWeight) } - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(Font.otfAppFont) } - .listRowBackground(Color(cellbackgroundColor)) - .foregroundColor(Color(textColor)) + .listRowBackground(Color.otfCellBackground) + .foregroundColor(.otfTextColor) } } } struct RKList_Previews: PreviewProvider { static var previews: some View { - SurveysList(cellbackgroundColor: UIColor(), headerColor: UIColor(), textColor: UIColor()) + SurveysList() } } struct SurveyQuestionsList: View { - let cellbackgroundColor: UIColor - let headerColor: UIColor - let textColor: UIColor var body: some View { Section(header: Text(ModuleAppYmlReader().researchKitModel?.surveyQuestionHeaderTitle ?? "Survey Questions") - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 13.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(Color(headerColor))) { - ForEach(TaskListRow.sections[1].rows, id: \.rawValue) { row in - - NavigationLink(destination: (TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea())) { - Text(String(describing: row)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - } - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(.otfheaderTitleFont) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(.otfHeaderColor)) { + ForEach(TaskListRow.sections[1].rows, id: \.rawValue) { row in + + NavigationLink(destination: (TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea())) { + Text(String(describing: row)) + .fontWeight(Font.otfFontWeight) } - .listRowBackground(Color(cellbackgroundColor)) - .foregroundColor(Color(textColor)) + .font(Font.otfAppFont) } + .listRowBackground(Color.otfCellBackground) + .foregroundColor(.otfTextColor) + } } } struct OnboardingList: View { - let cellbackgroundColor: UIColor - let headerColor: UIColor - let textColor: UIColor var body: some View { Section(header: Text(ModuleAppYmlReader().researchKitModel?.onBoardingHeaderTitle ?? "Onboarding") - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(Color(headerColor))) { - ForEach(TaskListRow.sections[2].rows, id: \.rawValue) { row in - NavigationLink(destination: TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea()) { - Text(String(describing: row)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - } - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(.otfheaderTitleFont) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(.otfHeaderColor)) { + ForEach(TaskListRow.sections[2].rows, id: \.rawValue) { row in + NavigationLink(destination: TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea()) { + Text(String(describing: row)) + .fontWeight(Font.otfFontWeight) } - .listRowBackground(Color(cellbackgroundColor)) - .foregroundColor(Color(textColor)) + .font(Font.otfAppFont) } + .listRowBackground(Color.otfCellBackground) + .foregroundColor(.otfTextColor) + } } } struct ActiveTasksList: View { - let cellbackgroundColor: UIColor - let headerColor: UIColor - let textColor: UIColor var body: some View { Section(header: Text(ModuleAppYmlReader().researchKitModel?.activeTasksHeaderTitle ?? "Active Tasks") - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(Color(headerColor))) { - ForEach(TaskListRow.sections[3].rows, id: \.rawValue) { row in - NavigationLink(destination: TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea()) { - Text(String(describing: row)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - } + .font(.otfheaderTitleFont) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(.otfHeaderColor)) { + ForEach(TaskListRow.sections[3].rows, id: \.rawValue) { row in + NavigationLink(destination: TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea()) { + Text(String(describing: row)) + .fontWeight(Font.otfFontWeight) } - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - - .listRowBackground(Color(cellbackgroundColor)) - .foregroundColor(Color(textColor)) } + .font(Font.otfAppFont) + + .listRowBackground(Color.otfCellBackground) + .foregroundColor(.otfTextColor) + } } } struct MiscellaneousList: View { - let cellbackgroundColor: UIColor - let headerColor: UIColor - let textColor: UIColor var body: some View { Section(header: Text(ModuleAppYmlReader().researchKitModel?.miscellaneousHeaderTitle ?? "Miscellaneous") - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) - .foregroundColor(Color(headerColor))) { - ForEach(TaskListRow.sections[4].rows, id: \.rawValue) { row in - NavigationLink(destination: TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea()) { - Text(String(describing: row)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - } - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(.otfheaderTitleFont) + .fontWeight(Font.otfheaderTitleWeight) + .foregroundColor(.otfHeaderColor)) { + ForEach(TaskListRow.sections[4].rows, id: \.rawValue) { row in + NavigationLink(destination: TaskViewControllerRepresentable(task: row.representedTask).navigationBarHidden(true).ignoresSafeArea()) { + Text(String(describing: row)) + .fontWeight(Font.otfFontWeight) } - .listRowBackground(Color(cellbackgroundColor)) - .foregroundColor(Color(textColor)) + .font(Font.otfAppFont) } + .listRowBackground(Color.otfCellBackground) + .foregroundColor(.otfTextColor) + } } } diff --git a/OTFMagicBox/StaticViews/RK UI/TaskListRow+Extras.swift b/OTFMagicBox/StaticViews/RK UI/TaskListRow+Extras.swift new file mode 100644 index 00000000..2aafec9d --- /dev/null +++ b/OTFMagicBox/StaticViews/RK UI/TaskListRow+Extras.swift @@ -0,0 +1,369 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFResearchKit + +extension TaskListRow { + class TaskListRowSection { + var title: String + var rows: [TaskListRow] + init(title: String, rows: [TaskListRow]) { + self.title = title + self.rows = rows + } + } + + /// Returns an array of all the task list row enum cases. + static var sections: [ TaskListRowSection ] { + return [ + TaskListRowSection(title: "Surveys", rows: [.form, .groupedForm, .survey]), + TaskListRowSection(title: "Survey Questions", + rows: [ .booleanQuestion, .customBooleanQuestion, + .dateQuestion, .dateTimeQuestion, + // .heightQuestion, + // .weightQuestion, + .imageChoiceQuestion, .locationQuestion, + .numericQuestion, .scaleQuestion, + .textQuestion, .textChoiceQuestion, + .timeIntervalQuestion, .timeOfDayQuestion, + .valuePickerChoiceQuestion, .validatedTextQuestion, + .imageCapture, .videoCapture, .frontFacingCamera, + .wait, .PDFViewer + // .requestPermissions + ]), + TaskListRowSection( + title: "Onboarding", + rows: [.eligibilityTask, .consent, .accountCreation, .login, .passcode] + ), + TaskListRowSection(title: "Active Tasks", rows: + [ .audio, .amslerGrid, .fitness, .holePegTest, .psat, + .reactionTime, .shortWalk, .spatialSpanMemory, + .speechRecognition, .speechInNoise, .stroop, .swiftStroop, + .timedWalkWithTurnAround, .toneAudiometry, .dBHLToneAudiometry, + .splMeter, .towerOfHanoi, .tremorTest, .twoFingerTappingInterval, + .walkBackAndForth, .kneeRangeOfMotion, .shoulderRangeOfMotion, + .trailMaking, .visualAcuityLandoltC, .contrastSensitivityPeakLandoltC + ]), + TaskListRowSection(title: "Miscellaneous", rows: + [ .videoInstruction, .webView ]) + ] + } +} + +extension TaskListRow { + // MARK: Types + /** + Every step and task in the ResearchKit framework has to have an identifier. + Within a task, the step identifiers should be unique. + + Here we use an enum to ensure that the identifiers are kept unique. Since + the enum has a raw underlying type of a `String`, the compiler can determine + the uniqueness of the case values at compile time. + + In a real application, the identifiers for your tasks and steps might + come from a database, or in a smaller application, might have some + human-readable meaning. + */ + enum Identifier { + // Task with a form, where multiple items appear on one page. + case formTask + case groupedFormTask + case formStep + case groupedFormStep + case formItem01 + case formItem02 + case formItem03 + case formItem04 + // Survey task specific identifiers. + case surveyTask + case introStep + case questionStep + case birthdayQuestion + case summaryStep + // Task with a Boolean question. + case booleanQuestionTask + case booleanQuestionStep + // Task with an example of date entry. + case dateQuestionTask + case dateQuestionStep + // Task with an example of date and time entry. + case dateTimeQuestionTask + case dateTimeQuestionStep + // Task with an example of height entry. + // case heightQuestionTask + case heightQuestionStep1 + case heightQuestionStep2 + case heightQuestionStep3 + case heightQuestionStep4 + // Task with an example of weight entry. + // case weightQuestionTask + case weightQuestionStep1 + case weightQuestionStep2 + case weightQuestionStep3 + case weightQuestionStep4 + case weightQuestionStep5 + case weightQuestionStep6 + case weightQuestionStep7 + // Task with an image choice question. + case imageChoiceQuestionTask + case imageChoiceQuestionStep1 + case imageChoiceQuestionStep2 + // Task with a location entry. + case locationQuestionTask + case locationQuestionStep + // Task with examples of numeric questions. + case numericQuestionTask + case numericQuestionStep + case numericNoUnitQuestionStep + // Task with examples of questions with sliding scales. + case scaleQuestionTask + case discreteScaleQuestionStep + case continuousScaleQuestionStep + case discreteVerticalScaleQuestionStep + case continuousVerticalScaleQuestionStep + case textScaleQuestionStep + case textVerticalScaleQuestionStep + // Task with an example of free text entry. + case textQuestionTask + case textQuestionStep + // Task with an example of a multiple choice question. + case textChoiceQuestionTask + case textChoiceQuestionStep + // Task with an example of time of day entry. + case timeOfDayQuestionTask + case timeOfDayQuestionStep + // Task with an example of time interval entry. + case timeIntervalQuestionTask + case timeIntervalQuestionStep + // Task with a value picker. + case valuePickerChoiceQuestionTask + case valuePickerChoiceQuestionStep + // Task with an example of validated text entry. + case validatedTextQuestionTask + case validatedTextQuestionStepEmail + case validatedTextQuestionStepDomain + // Image capture task specific identifiers. + case imageCaptureTask + case imageCaptureStep + // Video capture task specific identifiers. + case videoCaptureTask + case videoCaptureStep + case frontFacingCameraStep + // Task with an example of waiting. + case waitTask + case waitStepDeterminate + case waitStepIndeterminate + case pdfViewerStep + case pdfViewerTask + // case requestPermissionsStep + // Eligibility task specific indentifiers. + case eligibilityTask + case eligibilityIntroStep + case eligibilityFormStep + case eligibilityFormItem01 + case eligibilityFormItem02 + case eligibilityFormItem03 + case eligibilityIneligibleStep + case eligibilityEligibleStep + // Consent task specific identifiers. + case consentTask + case visualConsentStep + case consentSharingStep + case consentReviewStep + case consentDocumentParticipantSignature + case consentDocumentInvestigatorSignature + // Account creation task specific identifiers. + case accountCreationTask + case registrationStep + case waitStep + case verificationStep + // Login task specific identifiers. + case loginTask + case loginStep + case loginWaitStep + // Passcode task specific identifiers. + case passcodeTask + case passcodeStep + // Active tasks. + case audioTask + case amslerGridTask + case fitnessTask + case holePegTestTask + case psatTask + case reactionTime + case shortWalkTask + case spatialSpanMemoryTask + case speechRecognitionTask + case speechInNoiseTask + case stroopTask + case swiftStroopTask + case timedWalkWithTurnAroundTask + case toneAudiometryTask + case dBHLToneAudiometryTask + case splMeterTask + case splMeterStep + case towerOfHanoi + case tremorTestTask + case twoFingerTappingIntervalTask + case walkBackAndForthTask + case kneeRangeOfMotion + case shoulderRangeOfMotion + case trailMaking + case visualAcuityLandoltC + case contrastSensitivityPeakLandoltC + // Video instruction tasks. + case videoInstructionTask + case videoInstructionStep + // Web view tasks. + case webViewTask + case webViewStep + } +} + +extension TaskListRow { + // MARK: CustomStringConvertible + var description: String { + switch self { + case .form: return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.formSurveyExample ?? "Form Survey Example", comment: "") + case .groupedForm: return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.groupedFormSurveyExample ?? "Grouped Form Survey Example", comment: "") + case .survey: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.simpleSurveyExample ?? "Simple Survey Example", comment: "") + case .booleanQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.booleanQuestion ?? "Boolean Question", comment: "") + case .customBooleanQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.customBooleanQuestion ?? "Custom Boolean Question", comment: "") + case .dateQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.dateQuestion ?? "Date Question", comment: "") + case .dateTimeQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.dateAndTimeQuestion ?? "Date and Time Question", comment: "") + case .imageChoiceQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.imageChoiceQuestion ?? "Image Choice Question", comment: "") + case .locationQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.locationQuestion ?? "Location Question", comment: "") + case .numericQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.numericQuestion ?? "Numeric Question", comment: "") + case .scaleQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.scaleQuestion ?? "Scale Question", comment: "") + case .textQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.textQuestion ?? "Text Question", comment: "") + case .textChoiceQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.textChoiceQuestion ?? "Text Choice Question", comment: "") + case .timeIntervalQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.timeIntervalQuestion ?? "Time Interval Question", comment: "") + case .timeOfDayQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.timeOfDayQuestion ?? "Time of Day Question", comment: "") + case .valuePickerChoiceQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.valuePickerChoiceQuestion ?? "Value Picker Choice Question", comment: "") + case .validatedTextQuestion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.validatedTextQuestion ?? "Validated Text Question", comment: "") + case .imageCapture: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.imageCaptureStep ?? "Image Capture Step", comment: "") + case .videoCapture: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.videoCaptureStep ?? "Video Capture Step", comment: "") + case .frontFacingCamera: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.frontFacingCameraStep ?? "Front Facing Camera Step", comment: "") + case .wait: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.waitStep ?? "Wait Step", comment: "") + case .PDFViewer: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.pdfViewerStep ?? "PDF Viewer Step", comment: "") + case .eligibilityTask: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.eligibilityTaskExample ?? "Eligibility Task Example", comment: "") + case .consent: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.consentObtainingExample ?? "Consent-Obtaining Example", comment: "") + case .accountCreation: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.accountCreation ?? "Account Creation", comment: "") + case .login: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.login ?? "Login", comment: "") + case .passcode: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.passcodeCreation ?? "Passcode Creation", comment: "") + case .audio: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.audio ?? "Audio", comment: "") + + case .amslerGrid: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.amslerGrid ?? "Amsler Grid", comment: "") + case .fitness: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.fitnessCheck ?? "Fitness Check", comment: "") + + case .holePegTest: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.holePegTest ?? "Hole Peg Test", comment: "") + case .psat: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.psat ?? "PSAT", comment: "") + case .reactionTime: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.reactionTime ?? "Reaction Time", comment: "") + case .shortWalk: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.shortWalk ?? "Short Walk", comment: "") + case .spatialSpanMemory: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.spatialSpanMemory ?? "Spatial Span Memory", comment: "") + case .speechRecognition: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.speechRecognition ?? "Speech Recognition", comment: "") + + case .speechInNoise: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.speechInNoise ?? "Speech in Noise", comment: "") + case .stroop: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.stroop ?? "Stroop", comment: "") + case .swiftStroop: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.swiftStroop ?? "Swift Stroop", comment: "") + case .timedWalkWithTurnAround: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.timedWalkWithTurnAround ?? "Timed Walk with Turn Around", comment: "") + case .toneAudiometry: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.toneAudiometry ?? "Tone Audiometry", comment: "") + case .dBHLToneAudiometry: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.dBHLToneAudiometry ?? "dBHL Tone Audiometry", comment: "") + case .splMeter: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.environmentSPLMeter ?? "Environment SPL Meter", comment: "") + case .towerOfHanoi: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.towerOfHanoi ?? "Tower of Hanoi", comment: "") + case .twoFingerTappingInterval: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.twoFingerTappingInterval ?? "Two Finger Tapping Interval", comment: "") + case .walkBackAndForth: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.walkBackAndForth ?? "Walk Back and Forth", comment: "") + case .tremorTest: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.tremorTest ?? "Tremor Test", comment: "") + case .videoInstruction: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.videoInstructionTask ?? "Video Instruction Task", comment: "") + case .kneeRangeOfMotion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.kneeRangeOfMotion ?? "Knee Range of Motion", comment: "") + case .shoulderRangeOfMotion: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.shoulderRangeOfMotion ?? "Shoulder Range of Motion", comment: "") + case .trailMaking: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.trailMakingTest ?? "Trail Making Test", comment: "") + case .visualAcuityLandoltC: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.visualAcuityLandoltC ?? "Visual Acuity Landolt C", comment: "") + case .contrastSensitivityPeakLandoltC: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.contrastSensitivityPeak ?? "Contrast Sensitivity Peak", comment: "") + case .webView: + return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.webView ?? "Web View", comment: "") + } + } +} diff --git a/OTFMagicBox/StaticViews/RK UI/TaskListRow.swift b/OTFMagicBox/StaticViews/RK UI/TaskListRow.swift index feac513b..7e82f3b7 100755 --- a/OTFMagicBox/StaticViews/RK UI/TaskListRow.swift +++ b/OTFMagicBox/StaticViews/RK UI/TaskListRow.swift @@ -5,19 +5,19 @@ 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 @@ -28,7 +28,7 @@ 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 OTFResearchKit import AudioToolbox @@ -36,31 +36,31 @@ import HealthKit import UIKit /** - Wraps a SystemSoundID. + Wraps a SystemSoundID. - A class is used in order to provide appropriate cleanup when the sound is - no longer needed. -*/ + A class is used in order to provide appropriate cleanup when the sound is + no longer needed. + */ class SystemSound { var soundID: SystemSoundID = 0 - + init?(soundURL: URL) { if AudioServicesCreateSystemSoundID(soundURL as CFURL, &soundID) != noErr { - return nil + return nil } } - + deinit { AudioServicesDisposeSystemSoundID(soundID) } } /** - An enum that corresponds to a row displayed in a `TaskListViewController`. + An enum that corresponds to a row displayed in a `TaskListViewController`. - Each of the tasks is composed of one or more steps giving examples of the - types of functionality supported by the ResearchKit framework. -*/ + Each of the tasks is composed of one or more steps giving examples of the + types of functionality supported by the ResearchKit framework. + */ enum TaskListRow: Int, CustomStringConvertible { case form = 0 case groupedForm @@ -84,7 +84,7 @@ enum TaskListRow: Int, CustomStringConvertible { case frontFacingCamera case wait case PDFViewer - //case requestPermissions + // case requestPermissions case eligibilityTask case consent case accountCreation @@ -110,8 +110,6 @@ enum TaskListRow: Int, CustomStringConvertible { case tremorTest case twoFingerTappingInterval case walkBackAndForth - //case heightQuestion - //case weightQuestion case kneeRangeOfMotion case shoulderRangeOfMotion case trailMaking @@ -120,1022 +118,116 @@ enum TaskListRow: Int, CustomStringConvertible { case videoInstruction case webView - class TaskListRowSection { - var title: String - var rows: [TaskListRow] - - init(title: String, rows: [TaskListRow]) { - self.title = title - self.rows = rows - } - } - - /// Returns an array of all the task list row enum cases. - static var sections: [ TaskListRowSection ] { - - return [ - TaskListRowSection(title: "Surveys", rows: - [ - .form, - .groupedForm, - .survey - ]), - TaskListRowSection(title: "Survey Questions", rows: - [ - .booleanQuestion, - .customBooleanQuestion, - .dateQuestion, - .dateTimeQuestion, - //.heightQuestion, - //.weightQuestion, - .imageChoiceQuestion, - .locationQuestion, - .numericQuestion, - .scaleQuestion, - .textQuestion, - .textChoiceQuestion, - .timeIntervalQuestion, - .timeOfDayQuestion, - .valuePickerChoiceQuestion, - .validatedTextQuestion, - .imageCapture, - .videoCapture, - .frontFacingCamera, - .wait, - .PDFViewer, - //.requestPermissions - ]), - TaskListRowSection(title: "Onboarding", rows: - [ - .eligibilityTask, - .consent, - .accountCreation, - .login, - .passcode - ]), - TaskListRowSection(title: "Active Tasks", rows: - [ - .audio, - .amslerGrid, - .fitness, - .holePegTest, - .psat, - .reactionTime, - .shortWalk, - .spatialSpanMemory, - .speechRecognition, - .speechInNoise, - .stroop, - .swiftStroop, - .timedWalkWithTurnAround, - .toneAudiometry, - .dBHLToneAudiometry, - .splMeter, - .towerOfHanoi, - .tremorTest, - .twoFingerTappingInterval, - .walkBackAndForth, - .kneeRangeOfMotion, - .shoulderRangeOfMotion, - .trailMaking, - .visualAcuityLandoltC, - .contrastSensitivityPeakLandoltC - ]), - TaskListRowSection(title: "Miscellaneous", rows: - [ - .videoInstruction, - .webView - ]) - ]} - - // MARK: CustomStringConvertible - - var description: String { - switch self { - case .form: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.formSurveyExample ?? "Form Survey Example", comment: "") - - case .groupedForm: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.groupedFormSurveyExample ?? "Grouped Form Survey Example", comment: "") - - case .survey: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.simpleSurveyExample ?? "Simple Survey Example", comment: "") - - case .booleanQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.booleanQuestion ?? "Boolean Question", comment: "") - - case .customBooleanQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.customBooleanQuestion ?? "Custom Boolean Question", comment: "") - - case .dateQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.dateQuestion ?? "Date Question", comment: "") - - case .dateTimeQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.dateAndTimeQuestion ?? "Date and Time Question", comment: "") - -// case .heightQuestion: -// return NSLocalizedString("Height Question", comment: "") - -// case .weightQuestion: -// return NSLocalizedString("Weight Question", comment: "") - - case .imageChoiceQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.imageChoiceQuestion ?? "Image Choice Question", comment: "") - - case .locationQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.locationQuestion ?? "Location Question", comment: "") - - case .numericQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.numericQuestion ?? "Numeric Question", comment: "") - - case .scaleQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.scaleQuestion ?? "Scale Question", comment: "") - - case .textQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.textQuestion ?? "Text Question", comment: "") - - case .textChoiceQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.textChoiceQuestion ?? "Text Choice Question", comment: "") - - case .timeIntervalQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.timeIntervalQuestion ?? "Time Interval Question", comment: "") - - case .timeOfDayQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.timeOfDayQuestion ?? "Time of Day Question", comment: "") - - case .valuePickerChoiceQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.valuePickerChoiceQuestion ?? "Value Picker Choice Question", comment: "") - - case .validatedTextQuestion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.validatedTextQuestion ?? "Validated Text Question", comment: "") - - case .imageCapture: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.imageCaptureStep ?? "Image Capture Step", comment: "") - - case .videoCapture: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.videoCaptureStep ?? "Video Capture Step", comment: "") - - case .frontFacingCamera: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.frontFacingCameraStep ?? "Front Facing Camera Step", comment: "") - - case .wait: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.waitStep ?? "Wait Step", comment: "") - - case .PDFViewer: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.pdfViewerStep ?? "PDF Viewer Step", comment: "") - -// case .requestPermissions: -// return NSLocalizedString("Request Permissions Step", comment: "") - - case .eligibilityTask: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.eligibilityTaskExample ?? "Eligibility Task Example", comment: "") - - case .consent: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.consentObtainingExample ?? "Consent-Obtaining Example", comment: "") - - case .accountCreation: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.accountCreation ?? "Account Creation", comment: "") - - case .login: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.login ?? "Login", comment: "") - - case .passcode: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.passcodeCreation ?? "Passcode Creation", comment: "") - - case .audio: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.audio ?? "Audio", comment: "") - - case .amslerGrid: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.amslerGrid ?? "Amsler Grid", comment: "") - - case .fitness: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.fitnessCheck ?? "Fitness Check", comment: "") - - case .holePegTest: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.holePegTest ?? "Hole Peg Test", comment: "") - - case .psat: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.psat ?? "PSAT", comment: "") - - case .reactionTime: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.reactionTime ?? "Reaction Time", comment: "") - - case .shortWalk: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.shortWalk ?? "Short Walk", comment: "") - - case .spatialSpanMemory: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.spatialSpanMemory ?? "Spatial Span Memory", comment: "") - - case .speechRecognition: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.speechRecognition ?? "Speech Recognition", comment: "") - - case .speechInNoise: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.speechInNoise ?? "Speech in Noise", comment: "") - - case .stroop: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.stroop ?? "Stroop", comment: "") - - case .swiftStroop: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.swiftStroop ?? "Swift Stroop", comment: "") - - case .timedWalkWithTurnAround: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.timedWalkWithTurnAround ?? "Timed Walk with Turn Around", comment: "") - - case .toneAudiometry: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.toneAudiometry ?? "Tone Audiometry", comment: "") - - case .dBHLToneAudiometry: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.dBHLToneAudiometry ?? "dBHL Tone Audiometry", comment: "") - - case .splMeter: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.environmentSPLMeter ?? "Environment SPL Meter", comment: "") - - case .towerOfHanoi: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.towerOfHanoi ?? "Tower of Hanoi", comment: "") - - case .twoFingerTappingInterval: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.twoFingerTappingInterval ?? "Two Finger Tapping Interval", comment: "") - - case .walkBackAndForth: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.walkBackAndForth ?? "Walk Back and Forth", comment: "") - - case .tremorTest: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.tremorTest ?? "Tremor Test", comment: "") - - case .videoInstruction: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.videoInstructionTask ?? "Video Instruction Task", comment: "") - - case .kneeRangeOfMotion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.kneeRangeOfMotion ?? "Knee Range of Motion", comment: "") - - case .shoulderRangeOfMotion: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.shoulderRangeOfMotion ?? "Shoulder Range of Motion", comment: "") - - case .trailMaking: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.trailMakingTest ?? "Trail Making Test", comment: "") - - case .visualAcuityLandoltC: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.visualAcuityLandoltC ?? "Visual Acuity Landolt C", comment: "") - - case .contrastSensitivityPeakLandoltC: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.contrastSensitivityPeak ?? "Contrast Sensitivity Peak", comment: "") - - case .webView: - return NSLocalizedString(ModuleAppYmlReader().researchKitModel?.webView ?? "Web View", comment: "") - } - } - - // MARK: Types - - /** - Every step and task in the ResearchKit framework has to have an identifier. - Within a task, the step identifiers should be unique. - - Here we use an enum to ensure that the identifiers are kept unique. Since - the enum has a raw underlying type of a `String`, the compiler can determine - the uniqueness of the case values at compile time. - - In a real application, the identifiers for your tasks and steps might - come from a database, or in a smaller application, might have some - human-readable meaning. - */ - enum Identifier { - // Task with a form, where multiple items appear on one page. - case formTask - case groupedFormTask - case formStep - case groupedFormStep - case formItem01 - case formItem02 - case formItem03 - case formItem04 - - // Survey task specific identifiers. - case surveyTask - case introStep - case questionStep - case birthdayQuestion - case summaryStep - - // Task with a Boolean question. - case booleanQuestionTask - case booleanQuestionStep - - // Task with an example of date entry. - case dateQuestionTask - case dateQuestionStep - - // Task with an example of date and time entry. - case dateTimeQuestionTask - case dateTimeQuestionStep - - // Task with an example of height entry. - //case heightQuestionTask - case heightQuestionStep1 - case heightQuestionStep2 - case heightQuestionStep3 - case heightQuestionStep4 - - // Task with an example of weight entry. - //case weightQuestionTask - case weightQuestionStep1 - case weightQuestionStep2 - case weightQuestionStep3 - case weightQuestionStep4 - case weightQuestionStep5 - case weightQuestionStep6 - case weightQuestionStep7 - - // Task with an image choice question. - case imageChoiceQuestionTask - case imageChoiceQuestionStep1 - case imageChoiceQuestionStep2 - - // Task with a location entry. - case locationQuestionTask - case locationQuestionStep - - // Task with examples of numeric questions. - case numericQuestionTask - case numericQuestionStep - case numericNoUnitQuestionStep - - // Task with examples of questions with sliding scales. - case scaleQuestionTask - case discreteScaleQuestionStep - case continuousScaleQuestionStep - case discreteVerticalScaleQuestionStep - case continuousVerticalScaleQuestionStep - case textScaleQuestionStep - case textVerticalScaleQuestionStep - - // Task with an example of free text entry. - case textQuestionTask - case textQuestionStep - - // Task with an example of a multiple choice question. - case textChoiceQuestionTask - case textChoiceQuestionStep - - // Task with an example of time of day entry. - case timeOfDayQuestionTask - case timeOfDayQuestionStep - - // Task with an example of time interval entry. - case timeIntervalQuestionTask - case timeIntervalQuestionStep - - // Task with a value picker. - case valuePickerChoiceQuestionTask - case valuePickerChoiceQuestionStep - - // Task with an example of validated text entry. - case validatedTextQuestionTask - case validatedTextQuestionStepEmail - case validatedTextQuestionStepDomain - - // Image capture task specific identifiers. - case imageCaptureTask - case imageCaptureStep - - // Video capture task specific identifiers. - case videoCaptureTask - case videoCaptureStep - - case frontFacingCameraStep - - // Task with an example of waiting. - case waitTask - case waitStepDeterminate - case waitStepIndeterminate - - case pdfViewerStep - case pdfViewerTask - - //case requestPermissionsStep - - // Eligibility task specific indentifiers. - case eligibilityTask - case eligibilityIntroStep - case eligibilityFormStep - case eligibilityFormItem01 - case eligibilityFormItem02 - case eligibilityFormItem03 - case eligibilityIneligibleStep - case eligibilityEligibleStep - - // Consent task specific identifiers. - case consentTask - case visualConsentStep - case consentSharingStep - case consentReviewStep - case consentDocumentParticipantSignature - case consentDocumentInvestigatorSignature - - // Account creation task specific identifiers. - case accountCreationTask - case registrationStep - case waitStep - case verificationStep - - // Login task specific identifiers. - case loginTask - case loginStep - case loginWaitStep - - // Passcode task specific identifiers. - case passcodeTask - case passcodeStep - - // Active tasks. - case audioTask - case amslerGridTask - case fitnessTask - case holePegTestTask - case psatTask - case reactionTime - case shortWalkTask - case spatialSpanMemoryTask - case speechRecognitionTask - case speechInNoiseTask - case stroopTask - case swiftStroopTask - case timedWalkWithTurnAroundTask - case toneAudiometryTask - case dBHLToneAudiometryTask - case splMeterTask - case splMeterStep - case towerOfHanoi - case tremorTestTask - case twoFingerTappingIntervalTask - case walkBackAndForthTask - case kneeRangeOfMotion - case shoulderRangeOfMotion - case trailMaking - case visualAcuityLandoltC - case contrastSensitivityPeakLandoltC - - // Video instruction tasks. - case videoInstructionTask - case videoInstructionStep - - // Web view tasks. - case webViewTask - case webViewStep - } - // MARK: Properties - - /// Returns a new `ORKTask` that the `TaskListRow` enumeration represents. - var representedTask: ORKTask { - switch self { - case .form: - return formTask - - case .groupedForm: - return groupedFormTask - - case .survey: - return surveyTask - - case .booleanQuestion: - return booleanQuestionTask - - case .customBooleanQuestion: - return customBooleanQuestionTask - - case .dateQuestion: - return dateQuestionTask - - case .dateTimeQuestion: - return dateTimeQuestionTask - -// case .heightQuestion: -// return heightQuestionTask - -// case .weightQuestion: -// return weightQuestionTask - - case .imageChoiceQuestion: - return imageChoiceQuestionTask - - case .locationQuestion: - return locationQuestionTask - - case .numericQuestion: - return numericQuestionTask - - case .scaleQuestion: - return scaleQuestionTask - - case .textQuestion: - return textQuestionTask - - case .textChoiceQuestion: - return textChoiceQuestionTask - - case .timeIntervalQuestion: - return timeIntervalQuestionTask - - case .timeOfDayQuestion: - return timeOfDayQuestionTask - - case .valuePickerChoiceQuestion: - return valuePickerChoiceQuestionTask - - case .validatedTextQuestion: - return validatedTextQuestionTask - - case .imageCapture: - return imageCaptureTask - - case .videoCapture: - return videoCaptureTask - - case .frontFacingCamera: - return frontFacingCameraStep - - case .wait: - return waitTask - - case .PDFViewer: - return PDFViewerTask - -// case .requestPermissions: -// return requestPermissionsTask - - case .eligibilityTask: - return eligibilityTask - - case .consent: - return consentTask - - case .accountCreation: - return accountCreationTask - - case .login: - return loginTask - - case .passcode: - return passcodeTask - - case .audio: - return audioTask - - case .amslerGrid: - return amslerGridTask - - case .fitness: - return fitnessTask - - case .holePegTest: - return holePegTestTask - - case .psat: - return PSATTask - - case .reactionTime: - return reactionTimeTask - - case .shortWalk: - return shortWalkTask - - case .spatialSpanMemory: - return spatialSpanMemoryTask - - case .speechRecognition: - return speechRecognitionTask - - case .speechInNoise: - return speechInNoiseTask - - case .stroop: - return stroopTask - - case .swiftStroop: - return swiftStroopTask - - case .timedWalkWithTurnAround: - return timedWalkWithTurnAroundTask - - case .toneAudiometry: - return toneAudiometryTask - - case .dBHLToneAudiometry: - return dBHLToneAudiometryTask - - case .splMeter: - return splMeterTask - - case .towerOfHanoi: - return towerOfHanoiTask - - case .twoFingerTappingInterval: - return twoFingerTappingIntervalTask - - case .walkBackAndForth: - return walkBackAndForthTask - - case .tremorTest: - return tremorTestTask - - case .kneeRangeOfMotion: - return kneeRangeOfMotion - - case .shoulderRangeOfMotion: - return shoulderRangeOfMotion - - case .trailMaking: - return trailMaking - - case .visualAcuityLandoltC: - return visualAcuityLandoltC - - case .contrastSensitivityPeakLandoltC: - return contrastSensitivityPeakLandoltC - - case .videoInstruction: - return videoInstruction - - case .webView: - return webView - } - } - - // MARK: Task Creation Convenience - - /** - This task demonstrates a form step, in which multiple items are presented - in a single scrollable form. This might be used for entering multi-value - data, like taking a blood pressure reading with separate systolic and - diastolic values. - */ - private var formTask: ORKTask { - let step = ORKFormStep(identifier: String(describing: Identifier.formStep), title: NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.title ?? "Form Step", comment: ""), text: ModuleAppYmlReader().surverysTaskModel?.additionalText ?? "Additional text can go here.") - - // A first field, for entering an integer. - let formItem01Text = NSLocalizedString("Field01", comment: "") - let formItem01 = ORKFormItem(identifier: String(describing: Identifier.formItem01), text: formItem01Text, answerFormat: ORKAnswerFormat.integerAnswerFormat(withUnit: nil)) - formItem01.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") - - // A second field, for entering a time interval. - let formItem02Text = NSLocalizedString("Field02", comment: "") - let formItem02 = ORKFormItem(identifier: String(describing: Identifier.formItem02), text: formItem02Text, answerFormat: ORKTimeIntervalAnswerFormat()) - formItem02.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") - - let formItem03Text = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, comment: "") - let scaleAnswerFormat = ORKScaleAnswerFormat(maximumValue: 10, minimumValue: 0, defaultValue: 0, step: 1)//ORKScaleAnswerFormat(maximumValue: 10, minimumValue: 0, defaultValue: 0, step: 1) - scaleAnswerFormat.shouldHideRanges = true - let formItem03 = ORKFormItem(identifier: String(describing: Identifier.formItem03), text: formItem03Text, answerFormat: scaleAnswerFormat) - - let textChoices: [ORKTextChoice] = [ - ORKTextChoice(text: "choice 1", detailText: "detail 1", value: 1 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), - ORKTextChoice(text: "choice 2", detailText: "detail 2", value: 2 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), - ORKTextChoice(text: "choice 3", detailText: "detail 3", value: 3 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), - ORKTextChoice(text: "choice 4", detailText: "detail 4", value: 4 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), - ORKTextChoice(text: "choice 5", detailText: "detail 5", value: 5 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), - ORKTextChoice(text: "choice 6", detailText: "detail 6", value: 6 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false) - ] - - let textScaleAnswerFormat = ORKTextScaleAnswerFormat(textChoices: textChoices, defaultIndex: 10) - textScaleAnswerFormat.shouldHideLabels = true - textScaleAnswerFormat.shouldShowDontKnowButton = true - let formItem04 = ORKFormItem(identifier: String(describing: Identifier.formItem04), text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answerFormat: textScaleAnswerFormat) - - let appleChoices: [ORKTextChoice] = [ORKTextChoice(text:ModuleAppYmlReader().surverysTaskModel?.grannySmith ?? "Granny Smith", value: 1 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text:ModuleAppYmlReader().surverysTaskModel?.honeycrisp ?? "Honeycrisp", value: 2 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text:ModuleAppYmlReader().surverysTaskModel?.fuji ?? "Fuji", value: 3 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text:ModuleAppYmlReader().surverysTaskModel?.mcIntosh ?? "McIntosh", value: 10 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text:ModuleAppYmlReader().surverysTaskModel?.kanzi ?? "Kanzi", value: 5 as NSCoding & NSCopying & NSObjectProtocol)] - - let appleAnswerFormat = ORKTextChoiceAnswerFormat(style: .singleChoice, textChoices: appleChoices) - - let appleFormItem = ORKFormItem(identifier: "appleFormItemIdentifier", text:ModuleAppYmlReader().surverysTaskModel?.itemQuestion ?? Constants.YamlDefaults.favorite, answerFormat: appleAnswerFormat) - - - step.formItems = [ - appleFormItem, - formItem03, - formItem04, - formItem01, - formItem02 - ] - let completionStep = ORKCompletionStep(identifier: "CompletionStep") - completionStep.title = NSLocalizedString("All Done!", comment: "") - completionStep.detailText = NSLocalizedString("You have completed the questionnaire.", comment: "") - return ORKOrderedTask(identifier: String(describing: Identifier.formTask), steps: [step, completionStep]) - } - - private var groupedFormTask: ORKTask { - let step = ORKFormStep(identifier: String(describing: Identifier.groupedFormStep), title: NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.groupServeyTitle ?? "Form Step", comment: ""), text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.YourQuestion) - - //Start of first section - let learnMoreInstructionStep01 = ORKLearnMoreInstructionStep(identifier: "LearnMoreInstructionStep01") - learnMoreInstructionStep01.title = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.learnMoreTitle ?? Constants.YamlDefaults.learnMoreTitle, comment: "") - learnMoreInstructionStep01.text = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.learnMoreText ?? Constants.YamlDefaults.learnMoreText, comment: "") - let learnMoreItem01 = ORKLearnMoreItem(text: nil, learnMoreInstructionStep: learnMoreInstructionStep01) - let section01 = ORKFormItem(sectionTitle: NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.sectionTitle ?? "Section title", comment: ""), detailText: NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.sectionDetailText ?? "Section detail text", comment: ""), learnMoreItem: learnMoreItem01, showsProgress: true) - - // A first field, for entering an integer. - let formItem01Text = NSLocalizedString("Field01", comment: "") - let formItem01 = ORKFormItem(identifier: String(describing: Identifier.formItem01), text: formItem01Text, answerFormat: ORKAnswerFormat.integerAnswerFormat(withUnit: nil)) - formItem01.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") - - // A second field, for entering a time interval. - let formItem02Text = NSLocalizedString("Field02", comment: "") - let formItem02 = ORKFormItem(identifier: String(describing: Identifier.formItem02), text: formItem02Text, answerFormat: ORKTimeIntervalAnswerFormat()) - formItem02.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") - - - let sesAnswerFormat = ORKSESAnswerFormat(topRungText: "Best Off", bottomRungText: "Worst Off") - let sesFormItem = ORKFormItem(identifier: "sesIdentifier", text:ModuleAppYmlReader().surverysTaskModel?.socioeconomicLadder ?? "Select where you are on the socioeconomic ladder.", answerFormat: sesAnswerFormat) - - - //Start of section for scale question - let formItem03Text = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, comment: "") - let scaleAnswerFormat = ORKContinuousScaleAnswerFormat(maximumValue: 10, minimumValue: 0, defaultValue: 0.0, maximumFractionDigits: 1)//ORKScaleAnswerFormat(maximumValue: 10, minimumValue: 0, defaultValue: 0, step: 1) - let formItem03 = ORKFormItem(identifier: String(describing: Identifier.formItem03), text: formItem03Text, detailText: nil, learnMoreItem: nil, showsProgress: true, answerFormat: scaleAnswerFormat, tagText: nil, optional: true) - - step.formItems = [ - section01, - formItem01, - formItem02, - formItem03, - sesFormItem - ] - - // Add a question step. - let question1StepAnswerFormat = ORKBooleanAnswerFormat() - - let question1 = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.newsletter ?? Constants.YamlDefaults.newsletter, comment: "") - - let learnMoreInstructionStep = ORKLearnMoreInstructionStep(identifier: "LearnMoreInstructionStep01") - learnMoreInstructionStep.title = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.learnMoreTitle ?? Constants.YamlDefaults.learnMoreTitle, comment: "") - learnMoreInstructionStep.text = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.learnMoreText ?? Constants.YamlDefaults.learnMoreText, comment: "") - let learnMoreItem = ORKLearnMoreItem(text: nil, learnMoreInstructionStep: learnMoreInstructionStep) - - let question1Step = ORKQuestionStep(identifier: String(describing: Identifier.questionStep), title: ModuleAppYmlReader().surverysTaskModel?.questionnaire ?? Constants.YamlDefaults.Questionnaire, question: question1, answer: question1StepAnswerFormat, learnMoreItem: learnMoreItem) - question1Step.text = exampleDetailText - - //Add a question step with different layout format. - let question2StepAnswerFormat = ORKAnswerFormat.dateAnswerFormat(withDefaultDate: nil, minimumDate: nil, maximumDate: Date(), calendar: nil) - - let question2 = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.birthdayText ?? Constants.YamlDefaults.birthdayText, comment: "") - let question2Step = ORKQuestionStep(identifier: String(describing: Identifier.birthdayQuestion), title: ModuleAppYmlReader().surverysTaskModel?.questionnaire ?? Constants.YamlDefaults.Questionnaire, question: question2, answer: question2StepAnswerFormat) - question2Step.text = exampleDetailText - - - let appleChoices: [ORKTextChoice] = [ORKTextChoice(text: "Granny Smith", value: 1 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "Honeycrisp", value: 2 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "Fuji", value: 3 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "McIntosh", value: 10 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "Kanzi", value: 5 as NSCoding & NSCopying & NSObjectProtocol)] - - let appleAnswerFormat = ORKTextChoiceAnswerFormat(style: .singleChoice, textChoices: appleChoices) - - let appleFormItem = ORKFormItem(identifier: "appleFormItemIdentifier", text: ModuleAppYmlReader().surverysTaskModel?.itemQuestion ?? Constants.YamlDefaults.favorite, answerFormat: appleAnswerFormat) - - let appleFormStep = ORKFormStep(identifier: "appleFormStepIdentifier", title: "Fruit!", text: "Select the fruit you like.") - - appleFormStep.formItems = [appleFormItem] - - return ORKOrderedTask(identifier: String(describing: Identifier.groupedFormTask), steps: [step, question1Step, question2Step, appleFormStep]) - } - /** - A task demonstrating how the ResearchKit framework can be used to present a simple - survey with an introduction, a question, and a conclusion. - */ + A task demonstrating how the ResearchKit framework can be used to present a simple + survey with an introduction, a question, and a conclusion. + */ private var surveyTask: ORKTask { // Create the intro step. let instructionStep = ORKInstructionStep(identifier: String(describing: Identifier.introStep)) instructionStep.title = NSLocalizedString("Simple Survey", comment: "") instructionStep.text = exampleDescription - instructionStep.detailText = NSLocalizedString("Please use this space to provide instructions for participants. Please make sure to provide enough information so that users can progress through the survey and complete with ease.", comment: "") - + instructionStep.detailText = NSLocalizedString( + "Please use this space to provide instructions for participants. Please make sure to provide enough information so that users can progress through the survey and complete with ease.", + comment: "") // Add a question step. let question1StepAnswerFormat = ORKBooleanAnswerFormat() - let question1 = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.newsletter ?? Constants.YamlDefaults.newsletter, comment: "") - let learnMoreInstructionStep = ORKLearnMoreInstructionStep(identifier: "LearnMoreInstructionStep01") learnMoreInstructionStep.title = NSLocalizedString("Learn more title", comment: "") learnMoreInstructionStep.text = NSLocalizedString("Learn more text", comment: "") let learnMoreItem = ORKLearnMoreItem(text: nil, learnMoreInstructionStep: learnMoreInstructionStep) - - let question1Step = ORKQuestionStep(identifier: String(describing: Identifier.questionStep), title: ModuleAppYmlReader().surverysTaskModel?.questionnaire ?? Constants.YamlDefaults.Questionnaire, question: question1, answer: question1StepAnswerFormat, learnMoreItem: learnMoreItem) + let question1Step = ORKQuestionStep( + identifier: String(describing: Identifier.questionStep), + title: ModuleAppYmlReader().surverysTaskModel?.questionnaire ?? Constants.YamlDefaults.Questionnaire, + question: question1, + answer: question1StepAnswerFormat, + learnMoreItem: learnMoreItem) question1Step.text = exampleDetailText - - //Add a question step with different layout format. + // Add a question step with different layout format. let question2StepAnswerFormat = ORKAnswerFormat.dateAnswerFormat(withDefaultDate: nil, minimumDate: nil, maximumDate: Date(), calendar: nil) - let question2 = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.birthdayText ?? Constants.YamlDefaults.birthdayText, comment: "") - let question2Step = ORKQuestionStep(identifier: String(describing: Identifier.birthdayQuestion), title: ModuleAppYmlReader().surverysTaskModel?.questionnaire ?? Constants.YamlDefaults.Questionnaire, question: question2, answer: question2StepAnswerFormat) + let question2Step = ORKQuestionStep( + identifier: String(describing: Identifier.birthdayQuestion), + title: ModuleAppYmlReader().surverysTaskModel?.questionnaire ?? Constants.YamlDefaults.Questionnaire, + question: question2, answer: question2StepAnswerFormat) question2Step.text = exampleDetailText - // Add a summary step. let summaryStep = ORKInstructionStep(identifier: String(describing: Identifier.summaryStep)) summaryStep.title = NSLocalizedString("Thanks", comment: "") summaryStep.text = NSLocalizedString("Thank you for participating in this sample survey.", comment: "") - - return ORKOrderedTask(identifier: String(describing: Identifier.surveyTask), steps: [ - instructionStep, - question1Step, - question2Step, - summaryStep - ]) + return ORKOrderedTask(identifier: String(describing: Identifier.surveyTask), + steps: [ instructionStep, question1Step, question2Step, summaryStep ]) } - + /// This task presents just a single "Yes" / "No" question. private var booleanQuestionTask: ORKTask { let answerFormat = ORKBooleanAnswerFormat() - // We attach an answer format to a question step to specify what controls the user sees. - let questionStep = ORKQuestionStep(identifier: String(describing: Identifier.booleanQuestionStep), title: NSLocalizedString("Boolean", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - + let questionStep = ORKQuestionStep( + identifier: String(describing: Identifier.booleanQuestionStep), + title: NSLocalizedString("Boolean", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) // The detail text is shown in a small font below the title. questionStep.text = exampleDetailText - return ORKOrderedTask(identifier: String(describing: Identifier.booleanQuestionTask), steps: [questionStep]) } /// This task presents a customized "Yes" / "No" question. private var customBooleanQuestionTask: ORKTask { let answerFormat = ORKBooleanAnswerFormat(yesString: "Agree", noString: "Disagree") - // We attach an answer format to a question step to specify what controls the user sees. - let questionStep = ORKQuestionStep(identifier: String(describing: Identifier.booleanQuestionStep), title: NSLocalizedString("Custom Boolean", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - + let questionStep = ORKQuestionStep( + identifier: String(describing: Identifier.booleanQuestionStep), + title: NSLocalizedString("Custom Boolean", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) // The detail text is shown in a small font below the title. questionStep.text = exampleDetailText - return ORKOrderedTask(identifier: String(describing: Identifier.booleanQuestionTask), steps: [questionStep]) } - /// This task demonstrates a question which asks for a date. - private var dateQuestionTask: ORKTask { - /* - The date answer format can also support minimum and maximum limits, - a specific default value, and overriding the calendar to use. - */ - let answerFormat = ORKAnswerFormat.dateAnswerFormat() - - let step = ORKQuestionStep(identifier: String(describing: Identifier.dateQuestionStep), title: NSLocalizedString("Date", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - - step.text = exampleDetailText - - return ORKOrderedTask(identifier: String(describing: Identifier.dateQuestionTask), steps: [step]) - } - - /// This task demonstrates a question asking for a date and time of an event. - private var dateTimeQuestionTask: ORKTask { - /* - This uses the default calendar. Use a more detailed constructor to - set minimum / maximum limits. - */ - let answerFormat = ORKAnswerFormat.dateTime() - - let step = ORKQuestionStep(identifier: String(describing: Identifier.dateTimeQuestionStep), title: NSLocalizedString("Date and Time", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - - step.text = exampleDetailText - - return ORKOrderedTask(identifier: String(describing: Identifier.dateTimeQuestionTask), steps: [step]) - } - - /// This task demonstrates a question asking for the user height. - /*private var heightQuestionTask: ORKTask { - let answerFormat1 = ORKAnswerFormat.heightAnswerFormat() - - let step1 = ORKQuestionStep(identifier: String(describing: Identifier.heightQuestionStep1), title: NSLocalizedString("Height", comment: ""), question: exampleQuestionText, answer: answerFormat1) - - step1.text = "Local system" - - let answerFormat2 = ORKAnswerFormat.heightAnswerFormat(with: ORKMeasurementSystem.metric) - - let step2 = ORKQuestionStep(identifier: String(describing: Identifier.heightQuestionStep2), title: NSLocalizedString("Height", comment: ""), question: exampleQuestionText, answer: answerFormat2) - - step2.text = "Metric system" - - let answerFormat3 = ORKAnswerFormat.heightAnswerFormat(with: ORKMeasurementSystem.USC) - - let step3 = ORKQuestionStep(identifier: String(describing: Identifier.heightQuestionStep3), title: NSLocalizedString("Height", comment: ""), question: exampleQuestionText, answer: answerFormat3) - - step3.text = "USC system" - - let answerFormat4 = ORKHealthKitQuantityTypeAnswerFormat(quantityType: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.height)!, unit: HKUnit.meterUnit(with: .centi), style: .decimal) - - let step4 = ORKQuestionStep(identifier: String(describing: Identifier.heightQuestionStep4), title: NSLocalizedString("Height", comment: ""), question: exampleQuestionText, answer: answerFormat4) - - step4.text = "HealthKit, height" - - return ORKOrderedTask(identifier: String(describing: Identifier.heightQuestionTask), steps: [step1, step2, step3, step4]) - }*/ - - /// This task demonstrates a question asking for the user weight. - /*private var weightQuestionTask: ORKTask { - let answerFormat1 = ORKAnswerFormat.weightAnswerFormat() - - let step1 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep1), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat1) - - step1.text = "Local system, default precision" - - let answerFormat2 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric) - - let step2 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep2), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat2) - - step2.text = "Metric system, default precision" - - let answerFormat3 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric, numericPrecision: ORKNumericPrecision.low, minimumValue: ORKDoubleDefaultValue, maximumValue: ORKDoubleDefaultValue, defaultValue: ORKDoubleDefaultValue) - - let step3 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep3), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat3) - - step3.text = "Metric system, low precision" - - let answerFormat4 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric, numericPrecision: ORKNumericPrecision.high, minimumValue: 20.0, maximumValue: 100.0, defaultValue: 45.50) - - let step4 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep4), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat4) - - step4.text = "Metric system, high precision" - - let answerFormat5 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.USC) - - let step5 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep5), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat5) - - step5.text = "USC system, default precision" - - let answerFormat6 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.USC, numericPrecision: ORKNumericPrecision.high, minimumValue: 50.0, maximumValue: 150.0, defaultValue: 100.0) - - let step6 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep6), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat6) - - step6.text = "USC system, high precision" - - let answerFormat7 = ORKHealthKitQuantityTypeAnswerFormat(quantityType: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bodyMass)!, unit: HKUnit.gramUnit(with: .kilo), style: .decimal) - - let step7 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep7), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat7) - - step7.text = "HealthKit, body mass" - - return ORKOrderedTask(identifier: String(describing: Identifier.weightQuestionTask), steps: [step1, step2, step3, step4, step5, step6, step7]) - }*/ - - /** - This task demonstrates a survey question involving picking from a series of - image choices. A more realistic applciation of this type of question might be to - use a range of icons for faces ranging from happy to sad. - */ - private var imageChoiceQuestionTask: ORKTask { - let roundShapeImage = UIImage(named: "round_shape")! - let roundShapeText = NSLocalizedString("Round Shape", comment: "") - - let squareShapeImage = UIImage(named: "square_shape")! - let squareShapeText = NSLocalizedString("Square Shape", comment: "") - - let imageChoces = [ - ORKImageChoice(normalImage: roundShapeImage, selectedImage: nil, text: roundShapeText, value: roundShapeText as NSCoding & NSCopying & NSObjectProtocol), - ORKImageChoice(normalImage: squareShapeImage, selectedImage: nil, text: squareShapeText, value: squareShapeText as NSCoding & NSCopying & NSObjectProtocol) - ] - - let answerFormat1 = ORKAnswerFormat.choiceAnswerFormat(with: imageChoces) - - let questionStep1 = ORKQuestionStep(identifier: String(describing: Identifier.imageChoiceQuestionStep1), title: NSLocalizedString("Image Choice", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat1) - - questionStep1.text = exampleDetailText - - let answerFormat2 = ORKAnswerFormat.choiceAnswerFormat(with: imageChoces, style: .singleChoice, vertical: true) - - let questionStep2 = ORKQuestionStep(identifier: String(describing: Identifier.imageChoiceQuestionStep2), title: NSLocalizedString("Image Choice", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat2) - - questionStep2.text = exampleDetailText - - return ORKOrderedTask(identifier: String(describing: Identifier.imageChoiceQuestionTask), steps: [questionStep1, questionStep2]) - } - /// This task presents just a single location question. private var locationQuestionTask: ORKTask { let answerFormat = ORKLocationAnswerFormat() - // We attach an answer format to a question step to specify what controls the user sees. - let questionStep = ORKQuestionStep(identifier: String(describing: Identifier.locationQuestionStep), title: NSLocalizedString("Location", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) + let questionStep = ORKQuestionStep( + identifier: String(describing: Identifier.locationQuestionStep), + title: NSLocalizedString("Location", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) // The detail text is shown in a small font below the title. questionStep.text = exampleDetailText questionStep.placeholder = NSLocalizedString("Address", comment: "") - return ORKOrderedTask(identifier: String(describing: Identifier.locationQuestionTask), steps: [questionStep]) } /** - This task demonstrates use of numeric questions with and without units. - Note that the unit is just a string, prompting the user to enter the value - in the expected unit. The unit string propagates into the result object. - */ + This task demonstrates use of numeric questions with and without units. + Note that the unit is just a string, prompting the user to enter the value + in the expected unit. The unit string propagates into the result object. + */ private var numericQuestionTask: ORKTask { // This answer format will display a unit in-line with the numeric entry field. let localizedQuestionStep1AnswerFormatUnit = NSLocalizedString("Your unit", comment: "") let questionStep1AnswerFormat = ORKAnswerFormat.decimalAnswerFormat(withUnit: localizedQuestionStep1AnswerFormatUnit) - - let questionStep1 = ORKQuestionStep(identifier: String(describing: Identifier.numericQuestionStep), title: NSLocalizedString("Numeric", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: questionStep1AnswerFormat) - + let questionStep1 = ORKQuestionStep( + identifier: String(describing: Identifier.numericQuestionStep), + title: NSLocalizedString("Numeric", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: questionStep1AnswerFormat) questionStep1.text = exampleDetailText questionStep1.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") - // This answer format is similar to the previous one, but this time without displaying a unit. - let questionStep2 = ORKQuestionStep(identifier: String(describing: Identifier.numericNoUnitQuestionStep), title: NSLocalizedString("Numeric", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: ORKAnswerFormat.decimalAnswerFormat(withUnit: nil)) - + let questionStep2 = ORKQuestionStep( + identifier: String(describing: Identifier.numericNoUnitQuestionStep), + title: NSLocalizedString("Numeric", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: ORKAnswerFormat.decimalAnswerFormat(withUnit: nil)) questionStep2.text = exampleDetailText questionStep2.placeholder = NSLocalizedString("Placeholder without unit.", comment: "") - return ORKOrderedTask(identifier: String(describing: Identifier.numericQuestionTask), steps: [ questionStep1, questionStep2 @@ -1146,51 +238,82 @@ enum TaskListRow: Int, CustomStringConvertible { private var scaleQuestionTask: ORKTask { // The first step is a scale control with 10 discrete ticks. let stepTitle = NSLocalizedString("Scale", comment: "") - - let step1AnswerFormat = ORKAnswerFormat.scale(withMaximumValue: 10, minimumValue: 1, defaultValue: NSIntegerMax, step: 1, vertical: false, maximumValueDescription: exampleHighValueText, minimumValueDescription: exampleLowValueText) - - let questionStep1 = ORKQuestionStep(identifier: String(describing: Identifier.discreteScaleQuestionStep), title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: step1AnswerFormat) - + let step1AnswerFormat = ORKAnswerFormat.scale( + withMaximumValue: 10, + minimumValue: 1, + defaultValue: NSIntegerMax, + step: 1, + vertical: false, + maximumValueDescription: exampleHighValueText, + minimumValueDescription: exampleLowValueText) + let questionStep1 = ORKQuestionStep( + identifier: String(describing: Identifier.discreteScaleQuestionStep), + title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: step1AnswerFormat) questionStep1.text = NSLocalizedString("Discrete Scale", comment: "") - // The second step is a scale control that allows continuous movement with a percent formatter. - let step2AnswerFormat = ORKAnswerFormat.continuousScale(withMaximumValue: 1.0, minimumValue: 0.0, defaultValue: 99.0, maximumFractionDigits: 0, vertical: false, maximumValueDescription: nil, minimumValueDescription: nil) + let step2AnswerFormat = ORKAnswerFormat.continuousScale( + withMaximumValue: 1.0, + minimumValue: 0.0, + defaultValue: 99.0, + maximumFractionDigits: 0, + vertical: false, + maximumValueDescription: nil, + minimumValueDescription: nil) step2AnswerFormat.numberStyle = .percent - - let questionStep2 = ORKQuestionStep(identifier: String(describing: Identifier.continuousScaleQuestionStep), title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: step2AnswerFormat) - + let questionStep2 = ORKQuestionStep( + identifier: String(describing: Identifier.continuousScaleQuestionStep), + title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: step2AnswerFormat) questionStep2.text = NSLocalizedString("Continuous Scale", comment: "") - // The third step is a vertical scale control with 10 discrete ticks. - let step3AnswerFormat = ORKAnswerFormat.scale(withMaximumValue: 10, minimumValue: 1, defaultValue: NSIntegerMax, step: 1, vertical: true, maximumValueDescription: nil, minimumValueDescription: nil) - - let questionStep3 = ORKQuestionStep(identifier: String(describing: Identifier.discreteVerticalScaleQuestionStep), title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: step3AnswerFormat) - + let step3AnswerFormat = ORKAnswerFormat.scale( + withMaximumValue: 10, + minimumValue: 1, + defaultValue: NSIntegerMax, + step: 1, + vertical: true, + maximumValueDescription: nil, + minimumValueDescription: nil) + let questionStep3 = ORKQuestionStep( + identifier: String(describing: Identifier.discreteVerticalScaleQuestionStep), + title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: step3AnswerFormat) questionStep3.text = NSLocalizedString("Discrete Vertical Scale", comment: "") - // The fourth step is a vertical scale control that allows continuous movement. - let step4AnswerFormat = ORKAnswerFormat.continuousScale(withMaximumValue: 5.0, minimumValue: 1.0, defaultValue: 99.0, maximumFractionDigits: 2, vertical: true, maximumValueDescription: exampleHighValueText, minimumValueDescription: exampleLowValueText) - - let questionStep4 = ORKQuestionStep(identifier: String(describing: Identifier.continuousVerticalScaleQuestionStep), title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: step4AnswerFormat) - + let step4AnswerFormat = ORKAnswerFormat.continuousScale( + withMaximumValue: 5.0, + minimumValue: 1.0, + defaultValue: 99.0, + maximumFractionDigits: 2, + vertical: true, + maximumValueDescription: exampleHighValueText, + minimumValueDescription: exampleLowValueText) + let questionStep4 = ORKQuestionStep( + identifier: String(describing: Identifier.continuousVerticalScaleQuestionStep), + title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: step4AnswerFormat) questionStep4.text = "Continuous Vertical Scale" - // The fifth step is a scale control that allows text choices. - let textChoices: [ORKTextChoice] = [ORKTextChoice(text: "Poor", value: 1 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "Fair", value: 2 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "Good", value: 3 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "Above Average", value: 10 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "Excellent", value: 5 as NSCoding & NSCopying & NSObjectProtocol)] - + let textChoices: [ORKTextChoice] = [ + ORKTextChoice(text: "Poor", value: 1 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "Fair", value: 2 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "Good", value: 3 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "Above Average", value: 10 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "Excellent", value: 5 as NSCoding & NSCopying & NSObjectProtocol)] let step5AnswerFormat = ORKAnswerFormat.textScale(with: textChoices, defaultIndex: NSIntegerMax, vertical: false) - - let questionStep5 = ORKQuestionStep(identifier: String(describing: Identifier.textScaleQuestionStep), title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: step5AnswerFormat) - + let questionStep5 = ORKQuestionStep( + identifier: String(describing: Identifier.textScaleQuestionStep), + title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: step5AnswerFormat) questionStep5.text = "Text Scale" - // The sixth step is a vertical scale control that allows text choices. let step6AnswerFormat = ORKAnswerFormat.textScale(with: textChoices, defaultIndex: NSIntegerMax, vertical: true) - - let questionStep6 = ORKQuestionStep(identifier: String(describing: Identifier.textVerticalScaleQuestionStep), title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: step6AnswerFormat) - + let questionStep6 = ORKQuestionStep( + identifier: String(describing: Identifier.textVerticalScaleQuestionStep), + title: stepTitle, question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: step6AnswerFormat) questionStep6.text = "Text Vertical Scale" - return ORKOrderedTask(identifier: String(describing: Identifier.scaleQuestionTask), steps: [ questionStep1, questionStep2, @@ -1198,497 +321,106 @@ enum TaskListRow: Int, CustomStringConvertible { questionStep4, questionStep5, questionStep6 - ]) - } - - /** - This task demonstrates asking for text entry. Both single and multi-line - text entry are supported, with appropriate parameters to the text answer - format. - */ - private var textQuestionTask: ORKTask { - let answerFormat = ORKAnswerFormat.textAnswerFormat() - answerFormat.multipleLines = true - answerFormat.maximumLength = 280 - - let step = ORKQuestionStep(identifier: String(describing: Identifier.textQuestionStep), title: NSLocalizedString("Text", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - - step.text = exampleDetailText - - return ORKOrderedTask(identifier: String(describing: Identifier.textQuestionTask), steps: [step]) + ]) } /** - This task demonstrates a survey question for picking from a list of text - choices. In this case, the text choices are presented in a table view - (compare with the `valuePickerQuestionTask`). - */ - private var textChoiceQuestionTask: ORKTask { - let textChoiceOneText = NSLocalizedString("Choice 1", comment: "") - let textChoiceTwoText = NSLocalizedString("Choice 2", comment: "") - let textChoiceThreeText = NSLocalizedString("Choice 3", comment: "") - let textChoiceFourText = NSLocalizedString("Other", comment: "") - - // The text to display can be separate from the value coded for each choice: - let textChoices = [ - ORKTextChoice(text: textChoiceOneText, value: "choice_1" as NSCoding & NSCopying & NSObjectProtocol), - ORKTextChoice(text: textChoiceTwoText, value: "choice_2" as NSCoding & NSCopying & NSObjectProtocol), - ORKTextChoice(text: textChoiceThreeText, value: "choice_3" as NSCoding & NSCopying & NSObjectProtocol), - ORKTextChoiceOther.choice(withText: textChoiceFourText, detailText: nil, value: "choice_4" as NSCoding & NSCopying & NSObjectProtocol, exclusive: true, textViewPlaceholderText: "enter additional information") - ] - - let answerFormat = ORKAnswerFormat.choiceAnswerFormat(with: .singleChoice, textChoices: textChoices) - - let questionStep = ORKQuestionStep(identifier: String(describing: Identifier.textChoiceQuestionStep), title: NSLocalizedString("Text Choice", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - - questionStep.text = exampleDetailText - - return ORKOrderedTask(identifier: String(describing: Identifier.textChoiceQuestionTask), steps: [questionStep]) - } - - /** - This task demonstrates requesting a time interval. For example, this might - be a suitable answer format for a question like "How long is your morning - commute?" - */ - private var timeIntervalQuestionTask: ORKTask { - /* - The time interval answer format is constrained to entering a time - less than 24 hours and in steps of minutes. For times that don't fit - these restrictions, use another mode of data entry. - */ - let answerFormat = ORKAnswerFormat.timeIntervalAnswerFormat() - - let step = ORKQuestionStep(identifier: String(describing: Identifier.timeIntervalQuestionStep), title: NSLocalizedString("Time Interval", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - - step.text = exampleDetailText - - return ORKOrderedTask(identifier: String(describing: Identifier.timeIntervalQuestionTask), steps: [step]) - } - - /// This task demonstrates a question asking for a time of day. - private var timeOfDayQuestionTask: ORKTask { - /* - Because we don't specify a default, the picker will default to the - time the step is presented. For questions like "What time do you have - breakfast?", it would make sense to set the default on the answer - format. - */ - let answerFormat = ORKAnswerFormat.timeOfDayAnswerFormat() - - let questionStep = ORKQuestionStep(identifier: String(describing: Identifier.timeOfDayQuestionStep), title: NSLocalizedString("Time", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - - questionStep.text = exampleDetailText - - return ORKOrderedTask(identifier: String(describing: Identifier.timeOfDayQuestionTask), steps: [questionStep]) - } - - /** - This task demonstrates a survey question using a value picker wheel. - Compare with the `textChoiceQuestionTask` and `imageChoiceQuestionTask` - which can serve a similar purpose. - */ + This task demonstrates a survey question using a value picker wheel. + Compare with the `textChoiceQuestionTask` and `imageChoiceQuestionTask` + which can serve a similar purpose. + */ private var valuePickerChoiceQuestionTask: ORKTask { let textChoiceOneText = NSLocalizedString("Choice 1", comment: "") let textChoiceTwoText = NSLocalizedString("Choice 2", comment: "") let textChoiceThreeText = NSLocalizedString("Choice 3", comment: "") - // The text to display can be separate from the value coded for each choice: let textChoices = [ ORKTextChoice(text: textChoiceOneText, value: "choice_1" as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: textChoiceTwoText, value: "choice_2" as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: textChoiceThreeText, value: "choice_3" as NSCoding & NSCopying & NSObjectProtocol) ] - let answerFormat = ORKAnswerFormat.valuePickerAnswerFormat(with: textChoices) - - let questionStep = ORKQuestionStep(identifier: String(describing: Identifier.valuePickerChoiceQuestionStep), title: NSLocalizedString("Value Picker", comment: ""), question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answer: answerFormat) - + let questionStep = ORKQuestionStep( + identifier: String(describing: Identifier.valuePickerChoiceQuestionStep), + title: NSLocalizedString("Value Picker", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) questionStep.text = NSLocalizedString("Text Value picker", comment: "") - return ORKOrderedTask(identifier: String(describing: Identifier.valuePickerChoiceQuestionTask), steps: [questionStep]) } - - /** - This task demonstrates asking for text entry. Both single and multi-line - text entry are supported, with appropriate parameters to the text answer - format. - */ - private var validatedTextQuestionTask: ORKTask { - let answerFormatEmail = ORKAnswerFormat.emailAnswerFormat() - let stepEmail = ORKQuestionStep(identifier: String(describing: Identifier.validatedTextQuestionStepEmail), title: NSLocalizedString("Validated Text", comment: ""), question: NSLocalizedString("Email", comment: ""), answer: answerFormatEmail) - stepEmail.text = exampleDetailText - - let domainRegularExpressionPattern = "^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?$" - let domainRegularExpression = try? NSRegularExpression(pattern: domainRegularExpressionPattern) - let answerFormatDomain = ORKAnswerFormat.textAnswerFormat(withValidationRegularExpression: domainRegularExpression!, invalidMessage: "Invalid URL: %@") - answerFormatDomain.multipleLines = false - answerFormatDomain.keyboardType = .URL - answerFormatDomain.autocapitalizationType = UITextAutocapitalizationType.none - answerFormatDomain.autocorrectionType = UITextAutocorrectionType.no - answerFormatDomain.spellCheckingType = UITextSpellCheckingType.no - answerFormatDomain.textContentType = UITextContentType.URL - let stepDomain = ORKQuestionStep(identifier: String(describing: Identifier.validatedTextQuestionStepDomain), title: NSLocalizedString("Validated Text", comment: ""), question: NSLocalizedString("URL", comment: ""), answer: answerFormatDomain) - stepDomain.text = exampleDetailText - - return ORKOrderedTask(identifier: String(describing: Identifier.validatedTextQuestionTask), steps: [stepEmail, stepDomain]) - } - - /// This task presents the image capture step in an ordered task. - private var imageCaptureTask: ORKTask { - // Create the intro step. - let instructionStep = ORKInstructionStep(identifier: String(describing: Identifier.introStep)) - - instructionStep.title = NSLocalizedString("Image Capture Survey", comment: "") - - instructionStep.text = exampleDescription - - let handSolidImage = UIImage(named: "hand_solid")! - instructionStep.image = handSolidImage.withRenderingMode(.alwaysTemplate) - - let imageCaptureStep = ORKImageCaptureStep(identifier: String(describing: Identifier.imageCaptureStep)) - imageCaptureStep.title = NSLocalizedString("Image Capture", comment: "") - imageCaptureStep.isOptional = false - imageCaptureStep.accessibilityInstructions = NSLocalizedString("Your instructions for capturing the image", comment: "") - imageCaptureStep.accessibilityHint = NSLocalizedString("Captures the image visible in the preview", comment: "") - - imageCaptureStep.templateImage = UIImage(named: "hand_outline_big")! - - imageCaptureStep.templateImageInsets = UIEdgeInsets(top: 0.05, left: 0.05, bottom: 0.05, right: 0.05) - - return ORKOrderedTask(identifier: String(describing: Identifier.imageCaptureTask), steps: [ - instructionStep, - imageCaptureStep - ]) - } - - /// This task presents the video capture step in an ordered task. - private var videoCaptureTask: ORKTask { - // Create the intro step. - let instructionStep = ORKInstructionStep(identifier: String(describing: Identifier.introStep)) - - instructionStep.title = NSLocalizedString("Video Capture Survey", comment: "") - - instructionStep.text = exampleDescription - - let handSolidImage = UIImage(named: "hand_solid")! - instructionStep.image = handSolidImage.withRenderingMode(.alwaysTemplate) - - let videoCaptureStep = ORKVideoCaptureStep(identifier: String(describing: Identifier.videoCaptureStep)) - videoCaptureStep.title = NSLocalizedString("Video Capture", comment: "") - videoCaptureStep.accessibilityInstructions = NSLocalizedString("Your instructions for capturing the video", comment: "") - videoCaptureStep.accessibilityHint = NSLocalizedString("Captures the video visible in the preview", comment: "") - videoCaptureStep.templateImage = UIImage(named: "hand_outline_big")! - videoCaptureStep.templateImageInsets = UIEdgeInsets(top: 0.05, left: 0.05, bottom: 0.05, right: 0.05) - videoCaptureStep.duration = 30.0; // 30 seconds - - return ORKOrderedTask(identifier: String(describing: Identifier.videoCaptureTask), steps: [ - instructionStep, - videoCaptureStep - ]) - } - - /// This task presents a wait task. - private var waitTask: ORKTask { - let waitStepIndeterminate = ORKWaitStep(identifier: String(describing: Identifier.waitStepIndeterminate)) - waitStepIndeterminate.title = NSLocalizedString("Wait Step", comment: "") - waitStepIndeterminate.text = exampleDescription - waitStepIndeterminate.indicatorType = ORKProgressIndicatorType.indeterminate - - let waitStepDeterminate = ORKWaitStep(identifier: String(describing: Identifier.waitStepDeterminate)) - waitStepDeterminate.title = NSLocalizedString("Wait Step", comment: "") - waitStepDeterminate.text = exampleDescription - waitStepDeterminate.indicatorType = ORKProgressIndicatorType.progressBar - - return ORKOrderedTask(identifier: String(describing: Identifier.waitTask), steps: [waitStepIndeterminate, waitStepDeterminate]) + + /// This task presents a wait task. + private var waitTask: ORKTask { + let waitStepIndeterminate = ORKWaitStep(identifier: String(describing: Identifier.waitStepIndeterminate)) + waitStepIndeterminate.title = NSLocalizedString("Wait Step", comment: "") + waitStepIndeterminate.text = exampleDescription + waitStepIndeterminate.indicatorType = ORKProgressIndicatorType.indeterminate + let waitStepDeterminate = ORKWaitStep(identifier: String(describing: Identifier.waitStepDeterminate)) + waitStepDeterminate.title = NSLocalizedString("Wait Step", comment: "") + waitStepDeterminate.text = exampleDescription + waitStepDeterminate.indicatorType = ORKProgressIndicatorType.progressBar + return ORKOrderedTask(identifier: String(describing: Identifier.waitTask), steps: [waitStepIndeterminate, waitStepDeterminate]) } /// This task presents the PDF Viewer Step private var PDFViewerTask: ORKTask { - let PDFViewerStep = ORKPDFViewerStep(identifier: String(describing: Identifier.pdfViewerStep), pdfURL: Bundle.main.bundleURL.appendingPathComponent("ResearchKit.pdf")) PDFViewerStep.title = NSLocalizedString("PDF Step", comment: "") - return ORKOrderedTask(identifier: String(describing: Identifier.pdfViewerTask), steps: [PDFViewerStep]) } - /*private var requestPermissionsTask: ORKTask { - let healthKitTypesToWrite: Set = [ - HKObjectType.quantityType(forIdentifier: .bodyMassIndex)!, - HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!, - HKObjectType.workoutType()] - - let healthKitTypesToRead: Set = [ - HKObjectType.characteristicType(forIdentifier: .dateOfBirth)!, - HKObjectType.characteristicType(forIdentifier: .bloodType)!, - HKObjectType.workoutType()] - - - let healthKitPermissionType = ORKHealthKitPermissionType(sampleTypesToWrite: healthKitTypesToWrite, - objectTypesToRead: healthKitTypesToRead) - - let notificationsPermissionType = ORKNotificationPermissionType( - authorizationOptions: [.alert, .badge, .sound]) - - let motionActivityPermissionType = ORKMotionActivityPermissionType() - - let requestPermissionsStep = ORKRequestPermissionsStep( - identifier: String(describing: Identifier.requestPermissionsStep), - permissionTypes: [ - healthKitPermissionType, - notificationsPermissionType, - motionActivityPermissionType - ]) - - requestPermissionsStep.title = "Authorization Requests" - requestPermissionsStep.text = "Please review the authorizations below and enable to contribute to the study." - - return ORKOrderedTask(identifier: String(describing: Identifier.requestPermissionsStep), steps: [requestPermissionsStep]) - }*/ - - /** - A task demonstrating how the ResearchKit framework can be used to determine - eligibility using a navigable ordered task. - */ - private var eligibilityTask: ORKTask { - // Intro step - let introStep = ORKInstructionStep(identifier: String(describing: Identifier.eligibilityIntroStep)) - introStep.title = NSLocalizedString("Eligibility Task", comment: "") - introStep.text = exampleDescription - introStep.detailText = NSLocalizedString("Please use this space to provide instructions for participants. Please make sure to provide enough information so that users can progress through the survey and complete with ease.", comment: "") - - // Form step - let formStep = ORKFormStep(identifier: String(describing: Identifier.eligibilityFormStep)) - formStep.title = NSLocalizedString("Eligibility", comment: "") - formStep.isOptional = false - - // Form items - let textChoices: [ORKTextChoice] = [ORKTextChoice(text: "Yes", value: "Yes" as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "No", value: "No" as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "N/A", value: "N/A" as NSCoding & NSCopying & NSObjectProtocol)] - let answerFormat = ORKTextChoiceAnswerFormat(style: ORKChoiceAnswerStyle.singleChoice, textChoices: textChoices) - - let formItem01 = ORKFormItem(identifier: String(describing: Identifier.eligibilityFormItem01), text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answerFormat: answerFormat) - formItem01.isOptional = false - let formItem02 = ORKFormItem(identifier: String(describing: Identifier.eligibilityFormItem02), text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answerFormat: answerFormat) - formItem02.isOptional = false - let formItem03 = ORKFormItem(identifier: String(describing: Identifier.eligibilityFormItem03), text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, answerFormat: answerFormat) - formItem03.isOptional = false - - formStep.formItems = [ - formItem01, - formItem02, - formItem03 - ] - - // Ineligible step - let ineligibleStep = ORKInstructionStep(identifier: String(describing: Identifier.eligibilityIneligibleStep)) - ineligibleStep.title = NSLocalizedString("Eligibility Result", comment: "") - ineligibleStep.detailText = NSLocalizedString("You are ineligible to join the study", comment: "") - - // Eligible step - let eligibleStep = ORKCompletionStep(identifier: String(describing: Identifier.eligibilityEligibleStep)) - eligibleStep.title = NSLocalizedString("Eligibility Result", comment: "") - eligibleStep.detailText = NSLocalizedString("You are eligible to join the study", comment: "") - - // Create the task - let eligibilityTask = ORKNavigableOrderedTask(identifier: String(describing: Identifier.eligibilityTask), steps: [ - introStep, - formStep, - ineligibleStep, - eligibleStep - ]) - - // Build navigation rules. - var resultSelector = ORKResultSelector(stepIdentifier: String(describing: Identifier.eligibilityFormStep), resultIdentifier: String(describing: Identifier.eligibilityFormItem01)) - let predicateFormItem01 = ORKResultPredicate.predicateForChoiceQuestionResult(with: resultSelector, expectedAnswerValue: "Yes" as NSCoding & NSCopying & NSObjectProtocol) - - resultSelector = ORKResultSelector(stepIdentifier: String(describing: Identifier.eligibilityFormStep), resultIdentifier: String(describing: Identifier.eligibilityFormItem02)) - let predicateFormItem02 = ORKResultPredicate.predicateForChoiceQuestionResult(with: resultSelector, expectedAnswerValue: "Yes" as NSCoding & NSCopying & NSObjectProtocol) - - resultSelector = ORKResultSelector(stepIdentifier: String(describing: Identifier.eligibilityFormStep), resultIdentifier: String(describing: Identifier.eligibilityFormItem03)) - let predicateFormItem03 = ORKResultPredicate.predicateForChoiceQuestionResult(with: resultSelector, expectedAnswerValue: "No" as NSCoding & NSCopying & NSObjectProtocol) - - let predicateEligible = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateFormItem01, predicateFormItem02, predicateFormItem03]) - let predicateRule = ORKPredicateStepNavigationRule(resultPredicatesAndDestinationStepIdentifiers: [ (predicateEligible, String(describing: Identifier.eligibilityEligibleStep)) ]) - - eligibilityTask.setNavigationRule(predicateRule, forTriggerStepIdentifier: String(describing: Identifier.eligibilityFormStep)) - - // Add end direct rules to skip unneeded steps - let directRule = ORKDirectStepNavigationRule(destinationStepIdentifier: ORKNullStepIdentifier) - eligibilityTask.setNavigationRule(directRule, forTriggerStepIdentifier: String(describing: Identifier.eligibilityIneligibleStep)) - - return eligibilityTask - } - - /// A task demonstrating how the ResearchKit framework can be used to obtain informed consent. - private var consentTask: ORKTask { - /* - Informed consent starts by presenting an animated sequence conveying - the main points of your consent document. - */ - let visualConsentStep = ORKVisualConsentStep(identifier: String(describing: Identifier.visualConsentStep), document: consentDocument) - - let investigatorShortDescription = NSLocalizedString("Institution", comment: "") - let investigatorLongDescription = NSLocalizedString("Institution and its partners", comment: "") - let localizedLearnMoreHTMLContent = NSLocalizedString("Your sharing learn more content here.", comment: "") - - /* - If you want to share the data you collect with other researchers for - use in other studies beyond this one, it is best practice to get - explicit permission from the participant. Use the consent sharing step - for this. - */ - let sharingConsentStep = ORKConsentSharingStep(identifier: String(describing: Identifier.consentSharingStep), investigatorShortDescription: investigatorShortDescription, investigatorLongDescription: investigatorLongDescription, localizedLearnMoreHTMLContent: localizedLearnMoreHTMLContent) - - /* - After the visual presentation, the consent review step displays - your consent document and can obtain a signature from the participant. - - The first signature in the document is the participant's signature. - This effectively tells the consent review step which signatory is - reviewing the document. - */ - let signature = consentDocument.signatures!.first - - let reviewConsentStep = ORKConsentReviewStep(identifier: String(describing: Identifier.consentReviewStep), signature: signature, in: consentDocument) - reviewConsentStep.requiresScrollToBottom = true - - // In a real application, you would supply your own localized text. - reviewConsentStep.title = NSLocalizedString("Consent Document", comment: "") - reviewConsentStep.text = loremIpsumText - reviewConsentStep.reasonForConsent = loremIpsumText - - return ORKOrderedTask(identifier: String(describing: Identifier.consentTask), steps: [ - visualConsentStep, - sharingConsentStep, - reviewConsentStep - ]) - } - - /// This task presents the Account Creation process. - private var accountCreationTask: ORKTask { - /* - A registration step provides a form step that is populated with email and password fields. - If you wish to include any of the additional fields, then you can specify it through the `options` parameter. - */ - let registrationTitle = NSLocalizedString("Registration", comment: "") - let passcodeValidationRegexPattern = "^(?=.*\\d).{4,8}$" - let passcodeValidationRegularExpression = try? NSRegularExpression(pattern: passcodeValidationRegexPattern) - let passcodeInvalidMessage = NSLocalizedString("A valid password must be 4 to 8 characters long and include at least one numeric character.", comment: "") - let registrationOptions: ORKRegistrationStepOption = [.includeGivenName, .includeFamilyName, .includeGender, .includeDOB, .includePhoneNumber] - let registrationStep = ORKRegistrationStep(identifier: String(describing: Identifier.registrationStep), title: registrationTitle, text: exampleDetailText, passcodeValidationRegularExpression: passcodeValidationRegularExpression, passcodeInvalidMessage: passcodeInvalidMessage, options: registrationOptions) - registrationStep.phoneNumberValidationRegularExpression = try? NSRegularExpression(pattern: "^[+]{1,1}[1]{1,1}\\s{1,1}[(]{1,1}[1-9]{3,3}[)]{1,1}\\s{1,1}[1-9]{3,3}\\s{1,1}[1-9]{4,4}$") - registrationStep.phoneNumberInvalidMessage = "Expected format +1 (555) 555 5555" - - /* - A wait step allows you to upload the data from the user registration onto your server before presenting the verification step. - */ - let waitTitle = NSLocalizedString("Creating account", comment: "") - let waitText = NSLocalizedString("Please wait while we upload your data", comment: "") - let waitStep = ORKWaitStep(identifier: String(describing: Identifier.waitStep)) - waitStep.title = waitTitle - waitStep.text = waitText - - /* - A verification step view controller subclass is required in order to use the verification step. - The subclass provides the view controller button and UI behavior by overriding the following methods. - */ - class VerificationViewController: ORKVerificationStepViewController { - override func resendEmailButtonTapped() { - let alertTitle = NSLocalizedString("Resend Verification Email", comment: "") - let alertMessage = NSLocalizedString("Button tapped", comment: "") - let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertController.Style.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil)) - self.present(alert, animated: true, completion: nil) - } - } - - let verificationStep = ORKVerificationStep(identifier: String(describing: Identifier.verificationStep), text: exampleDetailText, verificationViewControllerClass: VerificationViewController.self) - - return ORKOrderedTask(identifier: String(describing: Identifier.accountCreationTask), steps: [ - registrationStep, - waitStep, - verificationStep - ]) - } - - /// This tasks presents the login step. - private var loginTask: ORKTask { - /* - A login step view controller subclass is required in order to use the login step. - The subclass provides the behavior for the login step forgot password button. - */ - class LoginViewController: ORKLoginStepViewController { - override func forgotPasswordButtonTapped() { - let alertTitle = NSLocalizedString("Forgot password?", comment: "") - let alertMessage = NSLocalizedString("Button tapped", comment: "") - let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertController.Style.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil)) - self.present(alert, animated: true, completion: nil) - } - } - - /* - A login step provides a form step that is populated with email and password fields, - and a button for `Forgot password?`. - */ - let loginTitle = NSLocalizedString("Login", comment: "") - let loginStep = ORKLoginStep(identifier: String(describing: Identifier.loginStep), title: loginTitle, text: exampleDetailText, loginViewControllerClass: LoginViewController.self) - - /* - A wait step allows you to validate the data from the user login against your server before proceeding. - */ - let waitTitle = NSLocalizedString("Logging in", comment: "") - let waitText = NSLocalizedString("Please wait while we validate your credentials", comment: "") - let waitStep = ORKWaitStep(identifier: String(describing: Identifier.loginWaitStep)) - waitStep.title = waitTitle - waitStep.text = waitText - - return ORKOrderedTask(identifier: String(describing: Identifier.loginTask), steps: [loginStep, waitStep]) - } - - /// This task demonstrates the Passcode creation process. - private var passcodeTask: ORKTask { - /* - If you want to protect the app using a passcode. It is reccomended to - ask user to create passcode as part of the consent process and use the - authentication and editing view controllers to interact with the passcode. - - The passcode is stored in the keychain. - */ - let passcodeConsentStep = ORKPasscodeStep(identifier: String(describing: Identifier.passcodeStep)) - passcodeConsentStep.title = NSLocalizedString("Passcode", comment: "") - return ORKOrderedTask(identifier: String(describing: Identifier.passcodeTask), steps: [passcodeConsentStep]) - } - /// This task presents the Audio pre-defined active task. private var audioTask: ORKTask { - return ORKOrderedTask.audioTask(withIdentifier: String(describing: Identifier.audioTask), intendedUseDescription: exampleDescription, speechInstruction: exampleSpeechInstruction, shortSpeechInstruction: exampleSpeechInstruction, duration: 20, recordingSettings: nil, checkAudioLevel: true, options: []) + return ORKOrderedTask.audioTask( + withIdentifier: String(describing: Identifier.audioTask), + intendedUseDescription: exampleDescription, + speechInstruction: exampleSpeechInstruction, + shortSpeechInstruction: exampleSpeechInstruction, + duration: 20, + recordingSettings: nil, + checkAudioLevel: true, + options: []) } /** - Amsler Grid + Amsler Grid */ private var amslerGridTask: ORKTask { return ORKOrderedTask.amslerGridTask(withIdentifier: String(describing: Identifier.amslerGridTask), intendedUseDescription: exampleDescription, options: []) } /** - This task presents the Fitness pre-defined active task. For this example, - short walking and rest durations of 20 seconds each are used, whereas more - realistic durations might be several minutes each. - */ + This task presents the Fitness pre-defined active task. For this example, + short walking and rest durations of 20 seconds each are used, whereas more + realistic durations might be several minutes each. + */ private var fitnessTask: ORKTask { return ORKOrderedTask.fitnessCheck(withIdentifier: String(describing: Identifier.fitnessTask), intendedUseDescription: exampleDescription, walkDuration: 20, restDuration: 20, options: []) } /// This task presents the Hole Peg Test pre-defined active task. private var holePegTestTask: ORKTask { - return ORKNavigableOrderedTask.holePegTest(withIdentifier: String(describing: Identifier.holePegTestTask), intendedUseDescription: exampleDescription, dominantHand: .right, numberOfPegs: 9, threshold: 0.2, rotated: false, timeLimit: 300, options: []) + return ORKNavigableOrderedTask.holePegTest( + withIdentifier: String(describing: Identifier.holePegTestTask), + intendedUseDescription: exampleDescription, + dominantHand: .right, + numberOfPegs: 9, + threshold: 0.2, + rotated: false, + timeLimit: 300, + options: []) } /// This task presents the PSAT pre-defined active task. private var PSATTask: ORKTask { - return ORKOrderedTask.psatTask(withIdentifier: String(describing: Identifier.psatTask), intendedUseDescription: exampleDescription, presentationMode: ORKPSATPresentationMode.auditory.union(.visual), interStimulusInterval: 3.0, stimulusDuration: 1.0, seriesLength: 60, options: []) + return ORKOrderedTask.psatTask( + withIdentifier: String(describing: Identifier.psatTask), + intendedUseDescription: exampleDescription, + presentationMode: ORKPSATPresentationMode.auditory.union(.visual), + interStimulusInterval: 3.0, + stimulusDuration: 1.0, + seriesLength: 60, + options: []) } /// This task presents the Reaction Time pre-defined active task. @@ -1696,22 +428,57 @@ enum TaskListRow: Int, CustomStringConvertible { /// An example of a custom sound. let successSoundURL = Bundle.main.url(forResource: "tap", withExtension: "aif")! let successSound = SystemSound(soundURL: successSoundURL)! - return ORKOrderedTask.reactionTime(withIdentifier: String(describing: Identifier.reactionTime), intendedUseDescription: exampleDescription, maximumStimulusInterval: 10, minimumStimulusInterval: 4, thresholdAcceleration: 0.5, numberOfAttempts: 3, timeout: 3, successSound: successSound.soundID, timeoutSound: 0, failureSound: UInt32(kSystemSoundID_Vibrate), options: []) + return ORKOrderedTask.reactionTime( + withIdentifier: String(describing: Identifier.reactionTime), + intendedUseDescription: exampleDescription, + maximumStimulusInterval: 10, + minimumStimulusInterval: 4, + thresholdAcceleration: 0.5, + numberOfAttempts: 3, + timeout: 3, + successSound: successSound.soundID, + timeoutSound: 0, + failureSound: UInt32(kSystemSoundID_Vibrate), options: []) } /// This task presents the Gait and Balance pre-defined active task. private var shortWalkTask: ORKTask { - return ORKOrderedTask.shortWalk(withIdentifier: String(describing: Identifier.shortWalkTask), intendedUseDescription: exampleDescription, numberOfStepsPerLeg: 20, restDuration: 20, options: []) + return ORKOrderedTask.shortWalk( + withIdentifier: String(describing: Identifier.shortWalkTask), + intendedUseDescription: exampleDescription, + numberOfStepsPerLeg: 20, + restDuration: 20, + options: []) } /// This task presents the Spatial Span Memory pre-defined active task. private var spatialSpanMemoryTask: ORKTask { - return ORKOrderedTask.spatialSpanMemoryTask(withIdentifier: String(describing: Identifier.spatialSpanMemoryTask), intendedUseDescription: exampleDescription, initialSpan: 3, minimumSpan: 2, maximumSpan: 15, playSpeed: 1.0, maximumTests: 5, maximumConsecutiveFailures: 3, customTargetImage: nil, customTargetPluralName: nil, requireReversal: false, options: []) + return ORKOrderedTask.spatialSpanMemoryTask( + withIdentifier: String(describing: Identifier.spatialSpanMemoryTask), + intendedUseDescription: exampleDescription, + initialSpan: 3, + minimumSpan: 2, + maximumSpan: 15, + playSpeed: 1.0, + maximumTests: 5, + maximumConsecutiveFailures: 3, + customTargetImage: nil, + customTargetPluralName: nil, + requireReversal: false, + options: []) } /// This task presents the Speech Recognition pre-defined active task. private var speechRecognitionTask: ORKTask { - return ORKOrderedTask.speechRecognitionTask(withIdentifier: String(describing: Identifier.speechRecognitionTask), intendedUseDescription: exampleDescription, speechRecognizerLocale: .englishUS, speechRecognitionImage: nil, speechRecognitionText: NSLocalizedString("A quick brown fox jumps over the lazy dog.", comment: ""), shouldHideTranscript: false, allowsEdittingTranscript: true, options: []) + return ORKOrderedTask.speechRecognitionTask( + withIdentifier: String(describing: Identifier.speechRecognitionTask), + intendedUseDescription: exampleDescription, + speechRecognizerLocale: .englishUS, + speechRecognitionImage: nil, + speechRecognitionText: NSLocalizedString("A quick brown fox jumps over the lazy dog.", comment: ""), + shouldHideTranscript: false, + allowsEdittingTranscript: true, + options: []) } /// This task presents the Speech in Noise pre-defined active task. @@ -1732,38 +499,48 @@ enum TaskListRow: Int, CustomStringConvertible { instructionStep.image = UIImage(named: "stroop") instructionStep.imageContentMode = .center instructionStep.detailText = "Every time a word appears, select the first letter of the name of the COLOR that is shown." - + let instructionStep2 = ORKInstructionStep(identifier: "stroopInstructionStep2") instructionStep2.title = "Stroop" instructionStep2.text = "Your description goes here." instructionStep2.detailText = "Every time a word appears, select the first letter of the name of the COLOR that is shown." instructionStep2.image = UIImage(named: "stroop") instructionStep2.imageContentMode = .center - let countdownStep = ORKCountdownStep(identifier: "stroopCountdownStep") countdownStep.title = "Stroop" - let stroopStep = ORKSwiftStroopStep(identifier: "stroopStep") stroopStep.numberOfAttempts = 10 stroopStep.title = "Stroop" stroopStep.text = "Select the first letter of the name of the COLOR that is shown." stroopStep.spokenInstruction = stroopStep.text - let completionStep = ORKCompletionStep(identifier: "stroopCompletionStep") completionStep.title = "Activity Complete" completionStep.text = "Your data will be analyzed and you will be notified when your results are ready." - + return ORKOrderedTask(identifier: "stroopTask", steps: [instructionStep, instructionStep2, countdownStep, stroopStep, completionStep]) } - + /// This task presents the Timed Walk with turn around pre-defined active task. private var timedWalkWithTurnAroundTask: ORKTask { - return ORKOrderedTask.timedWalk(withIdentifier: String(describing: Identifier.timedWalkWithTurnAroundTask), intendedUseDescription: exampleDescription, distanceInMeters: 100.0, timeLimit: 180.0, turnAroundTimeLimit: 60.0, includeAssistiveDeviceForm: true, options: []) + return ORKOrderedTask.timedWalk( + withIdentifier: String(describing: Identifier.timedWalkWithTurnAroundTask), + intendedUseDescription: exampleDescription, + distanceInMeters: 100.0, + timeLimit: 180.0, + turnAroundTimeLimit: 60.0, + includeAssistiveDeviceForm: true, + options: []) } - + /// This task presents the Tone Audiometry pre-defined active task. private var toneAudiometryTask: ORKTask { - return ORKOrderedTask.toneAudiometryTask(withIdentifier: String(describing: Identifier.toneAudiometryTask), intendedUseDescription: exampleDescription, speechInstruction: nil, shortSpeechInstruction: nil, toneDuration: 20, options: []) + return ORKOrderedTask.toneAudiometryTask( + withIdentifier: String(describing: Identifier.toneAudiometryTask), + intendedUseDescription: exampleDescription, + speechInstruction: nil, + shortSpeechInstruction: nil, + toneDuration: 20, + options: []) } /// This task presents the dBHL Tone Audiometry pre-defined active task. @@ -1780,7 +557,7 @@ enum TaskListRow: Int, CustomStringConvertible { splMeterStep.title = NSLocalizedString("SPL Meter", comment: "") return ORKOrderedTask(identifier: String(describing: Identifier.splMeterTask), steps: [splMeterStep]) } - + private var towerOfHanoiTask: ORKTask { return ORKOrderedTask.towerOfHanoiTask(withIdentifier: String(describing: Identifier.towerOfHanoi), intendedUseDescription: exampleDescription, numberOfDisks: 5, options: []) } @@ -1788,22 +565,27 @@ enum TaskListRow: Int, CustomStringConvertible { /// This task presents the Two Finger Tapping pre-defined active task. private var twoFingerTappingIntervalTask: ORKTask { return ORKOrderedTask.twoFingerTappingIntervalTask(withIdentifier: String(describing: Identifier.twoFingerTappingIntervalTask), intendedUseDescription: exampleDescription, duration: 10, - handOptions: [.both], options: []) + handOptions: [.both], options: []) } /// This task presents a walk back-and-forth task private var walkBackAndForthTask: ORKTask { - return ORKOrderedTask.walkBackAndForthTask(withIdentifier: String(describing: Identifier.walkBackAndForthTask), intendedUseDescription: exampleDescription, walkDuration: 30, restDuration: 30, options: []) + return ORKOrderedTask.walkBackAndForthTask( + withIdentifier: String(describing: Identifier.walkBackAndForthTask), + intendedUseDescription: exampleDescription, + walkDuration: 30, + restDuration: 30, + options: []) } /// This task presents the Tremor Test pre-defined active task. private var tremorTestTask: ORKTask { return ORKOrderedTask.tremorTest(withIdentifier: String(describing: Identifier.tremorTestTask), - intendedUseDescription: exampleDescription, - activeStepDuration: 10, - activeTaskOptions: [], - handOptions: [.both], - options: []) + intendedUseDescription: exampleDescription, + activeStepDuration: 10, + activeTaskOptions: [], + handOptions: [.both], + options: []) } /// This task presents a knee range of motion task @@ -1813,15 +595,24 @@ enum TaskListRow: Int, CustomStringConvertible { /// This task presents a shoulder range of motion task private var shoulderRangeOfMotion: ORKTask { - return ORKOrderedTask.shoulderRangeOfMotionTask(withIdentifier: String(describing: Identifier.shoulderRangeOfMotion), limbOption: .left, intendedUseDescription: exampleDescription, options: []) + return ORKOrderedTask.shoulderRangeOfMotionTask( + withIdentifier: String(describing: Identifier.shoulderRangeOfMotion), + limbOption: .left, + intendedUseDescription: exampleDescription, + options: []) } /// This task presents a trail making task private var trailMaking: ORKTask { let intendedUseDescription = "Tests visual attention and task switching" - return ORKOrderedTask.trailmakingTask(withIdentifier: String(describing: Identifier.trailMaking), intendedUseDescription: intendedUseDescription, trailmakingInstruction: nil, trailType: .B, options: []) + return ORKOrderedTask.trailmakingTask( + withIdentifier: String(describing: Identifier.trailMaking), + intendedUseDescription: intendedUseDescription, + trailmakingInstruction: nil, + trailType: .B, + options: []) } - + // This task presents a visual acuity landolt C task private var visualAcuityLandoltC: ORKTask { let orderedTask = ORKOrderedTask.landoltCVisualAcuityTask(withIdentifier: String(describing: Identifier.visualAcuityLandoltC), intendedUseDescription: "lorem ipsum") @@ -1843,7 +634,6 @@ enum TaskListRow: Int, CustomStringConvertible { return ORKOrderedTask(identifier: String(describing: Identifier.videoInstructionTask), steps: [videoInstructionStep]) } - /// This task presents a video instruction step private var frontFacingCameraStep: ORKTask { let frontFacingCameraStep = ORKFrontFacingCameraStep(identifier: String(describing: Identifier.frontFacingCameraStep)) @@ -1856,7 +646,6 @@ enum TaskListRow: Int, CustomStringConvertible { return ORKOrderedTask(identifier: String(describing: Identifier.videoInstructionTask), steps: [frontFacingCameraStep]) } - /// This task presents a web view step private var webView: ORKTask { let webViewStep = ORKWebViewStep(identifier: String(describing: Identifier.webViewStep), html: exampleHtml) @@ -1864,126 +653,786 @@ enum TaskListRow: Int, CustomStringConvertible { webViewStep.showSignatureAfterContent = true return ORKOrderedTask(identifier: String(describing: Identifier.webViewTask), steps: [webViewStep]) } - - // MARK: Consent Document Creation Convenience - - /** - A consent document provides the content for the visual consent and consent - review steps. This helper sets up a consent document with some dummy - content. You should populate your consent document to suit your study. - */ - private var consentDocument: ORKConsentDocument { - let consentDocument = ORKConsentDocument() - - /* - This is the title of the document, displayed both for review and in - the generated PDF. - */ - consentDocument.title = NSLocalizedString("Example Consent", comment: "") - - // This is the title of the signature page in the generated document. - consentDocument.signaturePageTitle = NSLocalizedString("Consent", comment: "") - - /* - This is the line shown on the signature page of the generated document, - just above the signatures. - */ - consentDocument.signaturePageContent = NSLocalizedString("I agree to participate in this research study.", comment: "") - - /* - Add the participant signature, which will be filled in during the - consent review process. This signature initially does not have a - signature image or a participant name; these are collected during - the consent review step. - */ - let participantSignatureTitle = NSLocalizedString("Participant", comment: "") - let participantSignature = ORKConsentSignature(forPersonWithTitle: participantSignatureTitle, dateFormatString: nil, identifier: String(describing: Identifier.consentDocumentParticipantSignature)) - - consentDocument.addSignature(participantSignature) - - /* - Add the investigator signature. This is pre-populated with the - investigator's signature image and name, and the date of their - signature. If you need to specify the date as now, you could generate - a date string with code here. - - This signature is only used for the generated PDF. - */ - let signatureImage = UIImage(named: "signature")! - let investigatorSignatureTitle = NSLocalizedString("Investigator", comment: "") - let investigatorSignatureGivenName = NSLocalizedString("Jonny", comment: "") - let investigatorSignatureFamilyName = NSLocalizedString("Appleseed", comment: "") - let investigatorSignatureDateString = "3/10/15" - - let investigatorSignature = ORKConsentSignature(forPersonWithTitle: investigatorSignatureTitle, dateFormatString: nil, identifier: String(describing: Identifier.consentDocumentInvestigatorSignature), givenName: investigatorSignatureGivenName, familyName: investigatorSignatureFamilyName, signatureImage: signatureImage, dateString: investigatorSignatureDateString) - - consentDocument.addSignature(investigatorSignature) - - /* - This is the HTML content for the "Learn More" page for each consent - section. In a real consent, this would be your content, and you would - have different content for each section. - - If your content is just text, you can use the `content` property - instead of the `htmlContent` property of `ORKConsentSection`. - */ - let htmlContentString = "

  • Lorem
  • ipsum
  • dolor

\(loremIpsumLongText)

\(loremIpsumMediumText)

" - - /* - These are all the consent section types that have pre-defined animations - and images. We use them in this specific order, so we see the available - animated transitions. - */ - let consentSectionTypes: [ORKConsentSectionType] = [ - .overview, - .dataGathering, - .privacy, - .dataUse, - .timeCommitment, - .studySurvey, - .studyTasks, - .withdrawing - ] - - /* - For each consent section type in `consentSectionTypes`, create an - `ORKConsentSection` that represents it. +} - In a real app, you would set specific content for each section. - */ - var consentSections: [ORKConsentSection] = consentSectionTypes.map { contentSectionType in - let consentSection = ORKConsentSection(type: contentSectionType) - - consentSection.summary = loremIpsumShortText - - if contentSectionType == .overview { - consentSection.htmlContent = htmlContentString - } else { - consentSection.content = loremIpsumLongText - } - - return consentSection +// MARK: - Task Creation Convenience +extension TaskListRow { + /// Returns a new `ORKTask` that the `TaskListRow` enumeration represents. + var representedTask: ORKTask { + switch self { + case .form: return formTask + case .groupedForm: return groupedFormTask + case .survey: return surveyTask + case .booleanQuestion: return booleanQuestionTask + case .customBooleanQuestion: return customBooleanQuestionTask + case .dateQuestion: return dateQuestionTask + case .dateTimeQuestion: return dateTimeQuestionTask + case .imageChoiceQuestion: return imageChoiceQuestionTask + case .locationQuestion: return locationQuestionTask + case .numericQuestion: return numericQuestionTask + case .scaleQuestion: return scaleQuestionTask + case .textQuestion: return textQuestionTask + case .textChoiceQuestion: return textChoiceQuestionTask + case .timeIntervalQuestion: return timeIntervalQuestionTask + case .timeOfDayQuestion: return timeOfDayQuestionTask + case .valuePickerChoiceQuestion: return valuePickerChoiceQuestionTask + case .validatedTextQuestion: return validatedTextQuestionTask + case .imageCapture: return imageCaptureTask + case .videoCapture: return videoCaptureTask + case .frontFacingCamera: return frontFacingCameraStep + case .wait: return waitTask + case .PDFViewer: return PDFViewerTask + case .eligibilityTask: return eligibilityTask + case .consent: return consentTask + case .accountCreation: return accountCreationTask + case .login: return loginTask + case .passcode: return passcodeTask + case .audio: return audioTask + case .amslerGrid: return amslerGridTask + case .fitness: return fitnessTask + case .holePegTest: return holePegTestTask + case .psat: return PSATTask + case .reactionTime: return reactionTimeTask + case .shortWalk: return shortWalkTask + case .spatialSpanMemory: return spatialSpanMemoryTask + case .speechRecognition: return speechRecognitionTask + case .speechInNoise: return speechInNoiseTask + case .stroop: return stroopTask + case .swiftStroop: return swiftStroopTask + case .timedWalkWithTurnAround: return timedWalkWithTurnAroundTask + case .toneAudiometry: return toneAudiometryTask + case .dBHLToneAudiometry: return dBHLToneAudiometryTask + case .splMeter: return splMeterTask + case .towerOfHanoi: return towerOfHanoiTask + case .twoFingerTappingInterval: return twoFingerTappingIntervalTask + case .walkBackAndForth: return walkBackAndForthTask + case .tremorTest: return tremorTestTask + case .kneeRangeOfMotion: return kneeRangeOfMotion + case .shoulderRangeOfMotion: return shoulderRangeOfMotion + case .trailMaking: return trailMaking + case .visualAcuityLandoltC: return visualAcuityLandoltC + case .contrastSensitivityPeakLandoltC: return contrastSensitivityPeakLandoltC + case .videoInstruction: return videoInstruction + case .webView: return webView } - - /* - This is an example of a section that is only in the review document - or only in the generated PDF, and is not displayed in `ORKVisualConsentStep`. - */ - let consentSection = ORKConsentSection(type: .onlyInDocument) - consentSection.summary = NSLocalizedString(".OnlyInDocument Scene Summary", comment: "") - consentSection.title = NSLocalizedString(".OnlyInDocument Scene", comment: "") - consentSection.content = loremIpsumLongText - - consentSections += [consentSection] - - // Set the sections on the document after they've been created. + } +} + +// MARK: - Form task +extension TaskListRow { + /** + This task demonstrates a form step, in which multiple items are presented + in a single scrollable form. This might be used for entering multi-value + data, like taking a blood pressure reading with separate systolic and + diastolic values. + */ + private var formTask: ORKTask { + let step = ORKFormStep(identifier: String(describing: Identifier.formStep), + title: NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.title ?? "Form Step", comment: ""), + text: ModuleAppYmlReader().surverysTaskModel?.additionalText ?? "Additional text can go here.") + // A first field, for entering an integer. + let formItem01Text = NSLocalizedString("Field01", comment: "") + let formItem01 = ORKFormItem(identifier: String(describing: Identifier.formItem01), text: formItem01Text, answerFormat: ORKAnswerFormat.integerAnswerFormat(withUnit: nil)) + formItem01.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") + // A second field, for entering a time interval. + let formItem02Text = NSLocalizedString("Field02", comment: "") + let formItem02 = ORKFormItem(identifier: String(describing: Identifier.formItem02), text: formItem02Text, answerFormat: ORKTimeIntervalAnswerFormat()) + formItem02.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") + let formItem03Text = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, comment: "") + let scaleAnswerFormat = ORKScaleAnswerFormat(maximumValue: 10, minimumValue: 0, defaultValue: 0, step: 1)// ORKScaleAnswerFormat(maximumValue: 10, minimumValue: 0, defaultValue: 0, step: 1) + scaleAnswerFormat.shouldHideRanges = true + let formItem03 = ORKFormItem(identifier: String(describing: Identifier.formItem03), text: formItem03Text, answerFormat: scaleAnswerFormat) + let textChoices: [ORKTextChoice] = [ + ORKTextChoice(text: "choice 1", detailText: "detail 1", value: 1 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), + ORKTextChoice(text: "choice 2", detailText: "detail 2", value: 2 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), + ORKTextChoice(text: "choice 3", detailText: "detail 3", value: 3 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), + ORKTextChoice(text: "choice 4", detailText: "detail 4", value: 4 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), + ORKTextChoice(text: "choice 5", detailText: "detail 5", value: 5 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false), + ORKTextChoice(text: "choice 6", detailText: "detail 6", value: 6 as NSCoding & NSCopying & NSObjectProtocol, exclusive: false) + ] + let textScaleAnswerFormat = ORKTextScaleAnswerFormat(textChoices: textChoices, defaultIndex: 10) + textScaleAnswerFormat.shouldHideLabels = true + textScaleAnswerFormat.shouldShowDontKnowButton = true + let formItem04 = ORKFormItem( + identifier: String(describing: Identifier.formItem04), + text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answerFormat: textScaleAnswerFormat) + let appleChoices: [ORKTextChoice] = [ + ORKTextChoice(text: ModuleAppYmlReader().surverysTaskModel?.grannySmith ?? "Granny Smith", value: 1 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: ModuleAppYmlReader().surverysTaskModel?.honeycrisp ?? "Honeycrisp", value: 2 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: ModuleAppYmlReader().surverysTaskModel?.fuji ?? "Fuji", value: 3 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: ModuleAppYmlReader().surverysTaskModel?.mcIntosh ?? "McIntosh", value: 10 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: ModuleAppYmlReader().surverysTaskModel?.kanzi ?? "Kanzi", value: 5 as NSCoding & NSCopying & NSObjectProtocol)] + let appleAnswerFormat = ORKTextChoiceAnswerFormat(style: .singleChoice, textChoices: appleChoices) + let appleFormItem = ORKFormItem(identifier: "appleFormItemIdentifier", + text: ModuleAppYmlReader().surverysTaskModel?.itemQuestion ?? Constants.YamlDefaults.favorite, + answerFormat: appleAnswerFormat) + step.formItems = [ appleFormItem, formItem03, formItem04, formItem01, formItem02 ] + let completionStep = ORKCompletionStep(identifier: "CompletionStep") + completionStep.title = NSLocalizedString("All Done!", comment: "") + completionStep.detailText = NSLocalizedString("You have completed the questionnaire.", comment: "") + return ORKOrderedTask(identifier: String(describing: Identifier.formTask), steps: [step, completionStep]) + } +} + +// MARK: - Account creation and passcode +extension TaskListRow { + /// This task presents the Account Creation process. + private var accountCreationTask: ORKTask { + /* + A registration step provides a form step that is populated with email and password fields. + If you wish to include any of the additional fields, then you can specify it through the `options` parameter. + */ + let registrationTitle = NSLocalizedString("Registration", comment: "") + let passcodeValidationRegexPattern = "^(?=.*\\d).{4,8}$" + let passcodeValidationRegularExpression = try? NSRegularExpression(pattern: passcodeValidationRegexPattern) + let passcodeInvalidMessage = NSLocalizedString("A valid password must be 4 to 8 characters long and include at least one numeric character.", comment: "") + let registrationOptions: ORKRegistrationStepOption = [.includeGivenName, .includeFamilyName, .includeGender, .includeDOB, .includePhoneNumber] + let registrationStep = ORKRegistrationStep( + identifier: String(describing: Identifier.registrationStep), + title: registrationTitle, + text: exampleDetailText, + passcodeValidationRegularExpression: passcodeValidationRegularExpression, + passcodeInvalidMessage: passcodeInvalidMessage, + options: registrationOptions) + registrationStep.phoneNumberValidationRegularExpression = try? NSRegularExpression(pattern: "^[+]{1,1}[1]{1,1}\\s{1,1}[(]{1,1}[1-9]{3,3}[)]{1,1}\\s{1,1}[1-9]{3,3}\\s{1,1}[1-9]{4,4}$") + registrationStep.phoneNumberInvalidMessage = "Expected format +1 (555) 555 5555" + /* + A wait step allows you to upload the data from the user registration onto your server before presenting the verification step. + */ + let waitTitle = NSLocalizedString("Creating account", comment: "") + let waitText = NSLocalizedString("Please wait while we upload your data", comment: "") + let waitStep = ORKWaitStep(identifier: String(describing: Identifier.waitStep)) + waitStep.title = waitTitle + waitStep.text = waitText + /* + A verification step view controller subclass is required in order to use the verification step. + The subclass provides the view controller button and UI behavior by overriding the following methods. + */ + class VerificationViewController: ORKVerificationStepViewController { + override func resendEmailButtonTapped() { + let alertTitle = NSLocalizedString("Resend Verification Email", comment: "") + let alertMessage = NSLocalizedString("Button tapped", comment: "") + let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertController.Style.alert) + alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil)) + self.present(alert, animated: true, completion: nil) + } + } + let verificationStep = ORKVerificationStep( + identifier: String(describing: Identifier.verificationStep), + text: exampleDetailText, + verificationViewControllerClass: VerificationViewController.self) + return ORKOrderedTask(identifier: String(describing: Identifier.accountCreationTask), steps: [ + registrationStep, + waitStep, + verificationStep + ]) + } + + /// This tasks presents the login step. + private var loginTask: ORKTask { + /* + A login step view controller subclass is required in order to use the login step. + The subclass provides the behavior for the login step forgot password button. + */ + class LoginViewController: ORKLoginStepViewController { + override func forgotPasswordButtonTapped() { + let alertTitle = NSLocalizedString("Forgot password?", comment: "") + let alertMessage = NSLocalizedString("Button tapped", comment: "") + let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertController.Style.alert) + alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil)) + self.present(alert, animated: true, completion: nil) + } + } + /* + A login step provides a form step that is populated with email and password fields, + and a button for `Forgot password?`. + */ + let loginTitle = NSLocalizedString("Login", comment: "") + let loginStep = ORKLoginStep(identifier: String(describing: Identifier.loginStep), title: loginTitle, text: exampleDetailText, loginViewControllerClass: LoginViewController.self) + /* + A wait step allows you to validate the data from the user login against your server before proceeding. + */ + let waitTitle = NSLocalizedString("Logging in", comment: "") + let waitText = NSLocalizedString("Please wait while we validate your credentials", comment: "") + let waitStep = ORKWaitStep(identifier: String(describing: Identifier.loginWaitStep)) + waitStep.title = waitTitle + waitStep.text = waitText + return ORKOrderedTask(identifier: String(describing: Identifier.loginTask), steps: [loginStep, waitStep]) + } + + /// This task demonstrates the Passcode creation process. + private var passcodeTask: ORKTask { + /* + If you want to protect the app using a passcode. It is reccomended to + ask user to create passcode as part of the consent process and use the + authentication and editing view controllers to interact with the passcode. + The passcode is stored in the keychain. + */ + let passcodeConsentStep = ORKPasscodeStep(identifier: String(describing: Identifier.passcodeStep)) + passcodeConsentStep.title = NSLocalizedString("Passcode", comment: "") + return ORKOrderedTask(identifier: String(describing: Identifier.passcodeTask), steps: [passcodeConsentStep]) + } + + /// A task demonstrating how the ResearchKit framework can be used to obtain informed consent. + private var consentTask: ORKTask { + /* + Informed consent starts by presenting an animated sequence conveying + the main points of your consent document. + */ + let visualConsentStep = ORKVisualConsentStep(identifier: String(describing: Identifier.visualConsentStep), document: consentDocument) + + let investigatorShortDescription = NSLocalizedString("Institution", comment: "") + let investigatorLongDescription = NSLocalizedString("Institution and its partners", comment: "") + let localizedLearnMoreHTMLContent = NSLocalizedString("Your sharing learn more content here.", comment: "") + /* + If you want to share the data you collect with other researchers for + use in other studies beyond this one, it is best practice to get + explicit permission from the participant. Use the consent sharing step + for this. + */ + let sharingConsentStep = ORKConsentSharingStep( + identifier: String(describing: Identifier.consentSharingStep), + investigatorShortDescription: investigatorShortDescription, + investigatorLongDescription: investigatorLongDescription, + localizedLearnMoreHTMLContent: localizedLearnMoreHTMLContent) + + /* + After the visual presentation, the consent review step displays + your consent document and can obtain a signature from the participant. + + The first signature in the document is the participant's signature. + This effectively tells the consent review step which signatory is + reviewing the document. + */ + let signature = consentDocument.signatures!.first + let reviewConsentStep = ORKConsentReviewStep(identifier: String(describing: Identifier.consentReviewStep), signature: signature, in: consentDocument) + reviewConsentStep.requiresScrollToBottom = true + // In a real application, you would supply your own localized text. + reviewConsentStep.title = NSLocalizedString("Consent Document", comment: "") + reviewConsentStep.text = loremIpsumText + reviewConsentStep.reasonForConsent = loremIpsumText + return ORKOrderedTask(identifier: String(describing: Identifier.consentTask), steps: [ + visualConsentStep, + sharingConsentStep, + reviewConsentStep + ]) + } + + private var eligibilityTask: ORKTask { + // Intro step + let introStep = ORKInstructionStep(identifier: String(describing: Identifier.eligibilityIntroStep)) + introStep.title = NSLocalizedString("Eligibility Task", comment: "") + introStep.text = exampleDescription + introStep.detailText = + NSLocalizedString( + "Please use this space to provide instructions for participants. Please make sure to provide enough information so that users can progress through the survey and complete with ease.", + comment: "") + // Form step + let formStep = ORKFormStep(identifier: String(describing: Identifier.eligibilityFormStep)) + formStep.title = NSLocalizedString("Eligibility", comment: "") + formStep.isOptional = false + // Form items + let textChoices: [ORKTextChoice] = [ + ORKTextChoice(text: "Yes", value: "Yes" as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "No", value: "No" as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "N/A", value: "N/A" as NSCoding & NSCopying & NSObjectProtocol)] + let answerFormat = ORKTextChoiceAnswerFormat(style: ORKChoiceAnswerStyle.singleChoice, textChoices: textChoices) + let formItem01 = ORKFormItem( + identifier: String(describing: Identifier.eligibilityFormItem01), + text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answerFormat: answerFormat) + formItem01.isOptional = false + let formItem02 = ORKFormItem( + identifier: String(describing: Identifier.eligibilityFormItem02), + text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answerFormat: answerFormat) + formItem02.isOptional = false + let formItem03 = ORKFormItem( + identifier: String(describing: Identifier.eligibilityFormItem03), + text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answerFormat: answerFormat) + formItem03.isOptional = false + formStep.formItems = [ formItem01, formItem02, formItem03 ] + // Ineligible step + let ineligibleStep = ORKInstructionStep(identifier: String(describing: Identifier.eligibilityIneligibleStep)) + ineligibleStep.title = NSLocalizedString("Eligibility Result", comment: "") + ineligibleStep.detailText = NSLocalizedString("You are ineligible to join the study", comment: "") + // Eligible step + let eligibleStep = ORKCompletionStep(identifier: String(describing: Identifier.eligibilityEligibleStep)) + eligibleStep.title = NSLocalizedString("Eligibility Result", comment: "") + eligibleStep.detailText = NSLocalizedString("You are eligible to join the study", comment: "") + // Create the task + let eligibilityTask = ORKNavigableOrderedTask(identifier: String(describing: Identifier.eligibilityTask), steps: [ + introStep, + formStep, + ineligibleStep, + eligibleStep + ]) + // Build navigation rules. + var resultSelector = ORKResultSelector(stepIdentifier: String(describing: Identifier.eligibilityFormStep), resultIdentifier: String(describing: Identifier.eligibilityFormItem01)) + let predicateFormItem01 = ORKResultPredicate.predicateForChoiceQuestionResult(with: resultSelector, expectedAnswerValue: "Yes" as NSCoding & NSCopying & NSObjectProtocol) + resultSelector = ORKResultSelector(stepIdentifier: String(describing: Identifier.eligibilityFormStep), resultIdentifier: String(describing: Identifier.eligibilityFormItem02)) + let predicateFormItem02 = ORKResultPredicate.predicateForChoiceQuestionResult(with: resultSelector, expectedAnswerValue: "Yes" as NSCoding & NSCopying & NSObjectProtocol) + resultSelector = ORKResultSelector(stepIdentifier: String(describing: Identifier.eligibilityFormStep), resultIdentifier: String(describing: Identifier.eligibilityFormItem03)) + let predicateFormItem03 = ORKResultPredicate.predicateForChoiceQuestionResult(with: resultSelector, expectedAnswerValue: "No" as NSCoding & NSCopying & NSObjectProtocol) + let predicateEligible = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateFormItem01, predicateFormItem02, predicateFormItem03]) + let predicateRule = ORKPredicateStepNavigationRule(resultPredicatesAndDestinationStepIdentifiers: [ (predicateEligible, String(describing: Identifier.eligibilityEligibleStep)) ]) + eligibilityTask.setNavigationRule(predicateRule, forTriggerStepIdentifier: String(describing: Identifier.eligibilityFormStep)) + + // Add end direct rules to skip unneeded steps + let directRule = ORKDirectStepNavigationRule(destinationStepIdentifier: ORKNullStepIdentifier) + eligibilityTask.setNavigationRule(directRule, forTriggerStepIdentifier: String(describing: Identifier.eligibilityIneligibleStep)) + + return eligibilityTask + } +} + +// MARK: - Text questions +extension TaskListRow { + /** + This task demonstrates asking for text entry. Both single and multi-line + text entry are supported, with appropriate parameters to the text answer + format. + */ + private var textQuestionTask: ORKTask { + let answerFormat = ORKAnswerFormat.textAnswerFormat() + answerFormat.multipleLines = true + answerFormat.maximumLength = 280 + let step = ORKQuestionStep( + identifier: String(describing: Identifier.textQuestionStep), + title: NSLocalizedString("Text", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) + step.text = exampleDetailText + return ORKOrderedTask(identifier: String(describing: Identifier.textQuestionTask), steps: [step]) + } + + /** + This task demonstrates a survey question for picking from a list of text + choices. In this case, the text choices are presented in a table view + (compare with the `valuePickerQuestionTask`). + */ + private var textChoiceQuestionTask: ORKTask { + let textChoiceOneText = NSLocalizedString("Choice 1", comment: "") + let textChoiceTwoText = NSLocalizedString("Choice 2", comment: "") + let textChoiceThreeText = NSLocalizedString("Choice 3", comment: "") + let textChoiceFourText = NSLocalizedString("Other", comment: "") + // The text to display can be separate from the value coded for each choice: + let textChoices = [ + ORKTextChoice(text: textChoiceOneText, value: "choice_1" as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: textChoiceTwoText, value: "choice_2" as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: textChoiceThreeText, value: "choice_3" as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoiceOther.choice( + withText: textChoiceFourText, + detailText: nil, + value: "choice_4" as NSCoding & NSCopying & NSObjectProtocol, + exclusive: true, + textViewPlaceholderText: "enter additional information") + ] + let answerFormat = ORKAnswerFormat.choiceAnswerFormat(with: .singleChoice, textChoices: textChoices) + let questionStep = ORKQuestionStep( + identifier: String(describing: Identifier.textChoiceQuestionStep), + title: NSLocalizedString("Text Choice", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) + questionStep.text = exampleDetailText + return ORKOrderedTask(identifier: String(describing: Identifier.textChoiceQuestionTask), steps: [questionStep]) + } + + /** + This task demonstrates asking for text entry. Both single and multi-line + text entry are supported, with appropriate parameters to the text answer + format. + */ + private var validatedTextQuestionTask: ORKTask { + let answerFormatEmail = ORKAnswerFormat.emailAnswerFormat() + let stepEmail = ORKQuestionStep( + identifier: String(describing: Identifier.validatedTextQuestionStepEmail), + title: NSLocalizedString("Validated Text", comment: ""), + question: NSLocalizedString("Email", comment: ""), + answer: answerFormatEmail) + stepEmail.text = exampleDetailText + let domainRegularExpressionPattern = "^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?$" + let domainRegularExpression = try? NSRegularExpression(pattern: domainRegularExpressionPattern) + let answerFormatDomain = ORKAnswerFormat.textAnswerFormat(withValidationRegularExpression: domainRegularExpression!, invalidMessage: "Invalid URL: %@") + answerFormatDomain.multipleLines = false + answerFormatDomain.keyboardType = .URL + answerFormatDomain.autocapitalizationType = UITextAutocapitalizationType.none + answerFormatDomain.autocorrectionType = UITextAutocorrectionType.no + answerFormatDomain.spellCheckingType = UITextSpellCheckingType.no + answerFormatDomain.textContentType = UITextContentType.URL + let stepDomain = ORKQuestionStep( + identifier: String(describing: Identifier.validatedTextQuestionStepDomain), + title: NSLocalizedString("Validated Text", comment: ""), + question: NSLocalizedString("URL", comment: ""), + answer: answerFormatDomain) + stepDomain.text = exampleDetailText + return ORKOrderedTask(identifier: String(describing: Identifier.validatedTextQuestionTask), steps: [stepEmail, stepDomain]) + } +} + +// MARK: - Date and time questions +extension TaskListRow { + /// This task demonstrates a question which asks for a date. + private var dateQuestionTask: ORKTask { + /* + The date answer format can also support minimum and maximum limits, + a specific default value, and overriding the calendar to use. + */ + let answerFormat = ORKAnswerFormat.dateAnswerFormat() + + let step = ORKQuestionStep( + identifier: String(describing: Identifier.dateQuestionStep), + title: NSLocalizedString("Date", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) + + step.text = exampleDetailText + + return ORKOrderedTask(identifier: String(describing: Identifier.dateQuestionTask), steps: [step]) + } + + /// This task demonstrates a question asking for a date and time of an event. + private var dateTimeQuestionTask: ORKTask { + /* + This uses the default calendar. Use a more detailed constructor to + set minimum / maximum limits. + */ + let answerFormat = ORKAnswerFormat.dateTime() + + let step = ORKQuestionStep( + identifier: String(describing: Identifier.dateTimeQuestionStep), + title: NSLocalizedString("Date and Time", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) + + step.text = exampleDetailText + + return ORKOrderedTask(identifier: String(describing: Identifier.dateTimeQuestionTask), steps: [step]) + } + + /** + This task demonstrates requesting a time interval. For example, this might + be a suitable answer format for a question like "How long is your morning + commute?" + */ + private var timeIntervalQuestionTask: ORKTask { + /* + The time interval answer format is constrained to entering a time + less than 24 hours and in steps of minutes. For times that don't fit + these restrictions, use another mode of data entry. + */ + let answerFormat = ORKAnswerFormat.timeIntervalAnswerFormat() + let step = ORKQuestionStep( + identifier: String(describing: Identifier.timeIntervalQuestionStep), + title: NSLocalizedString("Time Interval", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) + step.text = exampleDetailText + return ORKOrderedTask(identifier: String(describing: Identifier.timeIntervalQuestionTask), steps: [step]) + } + + /// This task demonstrates a question asking for a time of day. + private var timeOfDayQuestionTask: ORKTask { + /* + Because we don't specify a default, the picker will default to the + time the step is presented. For questions like "What time do you have + breakfast?", it would make sense to set the default on the answer + format. + */ + let answerFormat = ORKAnswerFormat.timeOfDayAnswerFormat() + let questionStep = ORKQuestionStep( + identifier: String(describing: Identifier.timeOfDayQuestionStep), + title: NSLocalizedString("Time", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat) + questionStep.text = exampleDetailText + return ORKOrderedTask( + identifier: String(describing: Identifier.timeOfDayQuestionTask), + steps: [questionStep]) + } +} + +// MARK: - Image and video questions +extension TaskListRow { + /** + This task demonstrates a survey question involving picking from a series of + image choices. A more realistic applciation of this type of question might be to + use a range of icons for faces ranging from happy to sad. + */ + private var imageChoiceQuestionTask: ORKTask { + let roundShapeImage = UIImage(named: "round_shape")! + let roundShapeText = NSLocalizedString("Round Shape", comment: "") + let squareShapeImage = UIImage(named: "square_shape")! + let squareShapeText = NSLocalizedString("Square Shape", comment: "") + let imageChoces = [ + ORKImageChoice(normalImage: roundShapeImage, selectedImage: nil, text: roundShapeText, value: roundShapeText as NSCoding & NSCopying & NSObjectProtocol), + ORKImageChoice(normalImage: squareShapeImage, selectedImage: nil, text: squareShapeText, value: squareShapeText as NSCoding & NSCopying & NSObjectProtocol) + ] + let answerFormat1 = ORKAnswerFormat.choiceAnswerFormat(with: imageChoces) + let questionStep1 = ORKQuestionStep( + identifier: String(describing: Identifier.imageChoiceQuestionStep1), + title: NSLocalizedString("Image Choice", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat1) + questionStep1.text = exampleDetailText + let answerFormat2 = ORKAnswerFormat.choiceAnswerFormat(with: imageChoces, style: .singleChoice, vertical: true) + let questionStep2 = ORKQuestionStep( + identifier: String(describing: Identifier.imageChoiceQuestionStep2), + title: NSLocalizedString("Image Choice", comment: ""), + question: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, + answer: answerFormat2) + questionStep2.text = exampleDetailText + return ORKOrderedTask( + identifier: String(describing: Identifier.imageChoiceQuestionTask), + steps: [questionStep1, questionStep2]) + } + + /// This task presents the image capture step in an ordered task. + private var imageCaptureTask: ORKTask { + // Create the intro step. + let instructionStep = ORKInstructionStep(identifier: String(describing: Identifier.introStep)) + instructionStep.title = NSLocalizedString("Image Capture Survey", comment: "") + instructionStep.text = exampleDescription + let handSolidImage = UIImage(named: "hand_solid")! + instructionStep.image = handSolidImage.withRenderingMode(.alwaysTemplate) + let imageCaptureStep = ORKImageCaptureStep(identifier: String(describing: Identifier.imageCaptureStep)) + imageCaptureStep.title = NSLocalizedString("Image Capture", comment: "") + imageCaptureStep.isOptional = false + imageCaptureStep.accessibilityInstructions = NSLocalizedString("Your instructions for capturing the image", comment: "") + imageCaptureStep.accessibilityHint = NSLocalizedString("Captures the image visible in the preview", comment: "") + imageCaptureStep.templateImage = UIImage(named: "hand_outline_big")! + imageCaptureStep.templateImageInsets = UIEdgeInsets(top: 0.05, left: 0.05, bottom: 0.05, right: 0.05) + return ORKOrderedTask(identifier: String(describing: Identifier.imageCaptureTask), steps: [ + instructionStep, + imageCaptureStep + ]) + } + + /// This task presents the video capture step in an ordered task. + private var videoCaptureTask: ORKTask { + // Create the intro step. + let instructionStep = ORKInstructionStep(identifier: String(describing: Identifier.introStep)) + instructionStep.title = NSLocalizedString("Video Capture Survey", comment: "") + instructionStep.text = exampleDescription + let handSolidImage = UIImage(named: "hand_solid")! + instructionStep.image = handSolidImage.withRenderingMode(.alwaysTemplate) + let videoCaptureStep = ORKVideoCaptureStep(identifier: String(describing: Identifier.videoCaptureStep)) + videoCaptureStep.title = NSLocalizedString("Video Capture", comment: "") + videoCaptureStep.accessibilityInstructions = NSLocalizedString("Your instructions for capturing the video", comment: "") + videoCaptureStep.accessibilityHint = NSLocalizedString("Captures the video visible in the preview", comment: "") + videoCaptureStep.templateImage = UIImage(named: "hand_outline_big")! + videoCaptureStep.templateImageInsets = UIEdgeInsets(top: 0.05, left: 0.05, bottom: 0.05, right: 0.05) + videoCaptureStep.duration = 30.0 // 30 seconds + return ORKOrderedTask(identifier: String(describing: Identifier.videoCaptureTask), steps: [ + instructionStep, + videoCaptureStep + ]) + } +} + +// MARK: - Grouped form +extension TaskListRow { + private var groupedFormTask: ORKTask { + let step = ORKFormStep( + identifier: String(describing: Identifier.groupedFormStep), + title: NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.groupServeyTitle ?? "Form Step", comment: ""), + text: ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.YourQuestion) + // Start of first section + let learnMoreInstructionStep01 = ORKLearnMoreInstructionStep(identifier: "LearnMoreInstructionStep01") + learnMoreInstructionStep01.title = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.learnMoreTitle ?? Constants.YamlDefaults.learnMoreTitle, comment: "") + learnMoreInstructionStep01.text = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.learnMoreText ?? Constants.YamlDefaults.learnMoreText, comment: "") + let learnMoreItem01 = ORKLearnMoreItem(text: nil, learnMoreInstructionStep: learnMoreInstructionStep01) + let section01 = ORKFormItem( + sectionTitle: NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.sectionTitle ?? "Section title", comment: ""), + detailText: NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.sectionDetailText ?? "Section detail text", comment: ""), + learnMoreItem: learnMoreItem01, showsProgress: true) + // A first field, for entering an integer. + let formItem01Text = NSLocalizedString("Field01", comment: "") + let formItem01 = ORKFormItem(identifier: String(describing: Identifier.formItem01), text: formItem01Text, answerFormat: ORKAnswerFormat.integerAnswerFormat(withUnit: nil)) + formItem01.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") + // A second field, for entering a time interval. + let formItem02Text = NSLocalizedString("Field02", comment: "") + let formItem02 = ORKFormItem(identifier: String(describing: Identifier.formItem02), text: formItem02Text, answerFormat: ORKTimeIntervalAnswerFormat()) + formItem02.placeholder = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.placeholder ?? Constants.YamlDefaults.placeholder, comment: "") + let sesAnswerFormat = ORKSESAnswerFormat( + topRungText: "Best Off", + bottomRungText: "Worst Off") + let sesFormItem = ORKFormItem( + identifier: "sesIdentifier", text: ModuleAppYmlReader().surverysTaskModel?.socioeconomicLadder ?? "Select where you are on the socioeconomic ladder.", + answerFormat: sesAnswerFormat) + // Start of section for scale question + let formItem03Text = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.questionText ?? Constants.YamlDefaults.questionText, comment: "") + let scaleAnswerFormat = ORKContinuousScaleAnswerFormat( + maximumValue: 10, + minimumValue: 0, + defaultValue: 0.0, + maximumFractionDigits: 1)// ORKScaleAnswerFormat(maximumValue: 10, minimumValue: 0, defaultValue: 0, step: 1) + let formItem03 = ORKFormItem( + identifier: String(describing: Identifier.formItem03), + text: formItem03Text, + detailText: nil, + learnMoreItem: nil, + showsProgress: true, + answerFormat: scaleAnswerFormat, + tagText: nil, + optional: true) + step.formItems = [ section01, formItem01, formItem02, formItem03, sesFormItem ] + // Add a question step. + let question1StepAnswerFormat = ORKBooleanAnswerFormat() + let question1 = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.newsletter ?? Constants.YamlDefaults.newsletter, comment: "") + let learnMoreInstructionStep = ORKLearnMoreInstructionStep(identifier: "LearnMoreInstructionStep01") + learnMoreInstructionStep.title = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.learnMoreTitle ?? Constants.YamlDefaults.learnMoreTitle, comment: "") + learnMoreInstructionStep.text = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.learnMoreText ?? Constants.YamlDefaults.learnMoreText, comment: "") + let learnMoreItem = ORKLearnMoreItem(text: nil, learnMoreInstructionStep: learnMoreInstructionStep) + let question1Step = ORKQuestionStep( + identifier: String(describing: Identifier.questionStep), + title: ModuleAppYmlReader().surverysTaskModel?.questionnaire ?? Constants.YamlDefaults.Questionnaire, + question: question1, + answer: question1StepAnswerFormat, + learnMoreItem: learnMoreItem) + question1Step.text = exampleDetailText + // Add a question step with different layout format. + let question2StepAnswerFormat = ORKAnswerFormat.dateAnswerFormat(withDefaultDate: nil, minimumDate: nil, maximumDate: Date(), calendar: nil) + let question2 = NSLocalizedString(ModuleAppYmlReader().surverysTaskModel?.birthdayText ?? Constants.YamlDefaults.birthdayText, comment: "") + let question2Step = ORKQuestionStep( + identifier: String(describing: Identifier.birthdayQuestion), + title: ModuleAppYmlReader().surverysTaskModel?.questionnaire ?? Constants.YamlDefaults.Questionnaire, + question: question2, + answer: question2StepAnswerFormat) + question2Step.text = exampleDetailText + let appleChoices: [ORKTextChoice] = [ + ORKTextChoice(text: "Granny Smith", value: 1 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "Honeycrisp", value: 2 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "Fuji", value: 3 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "McIntosh", value: 10 as NSCoding & NSCopying & NSObjectProtocol), + ORKTextChoice(text: "Kanzi", value: 5 as NSCoding & NSCopying & NSObjectProtocol)] + let appleAnswerFormat = ORKTextChoiceAnswerFormat(style: .singleChoice, textChoices: appleChoices) + let appleFormItem = ORKFormItem( + identifier: "appleFormItemIdentifier", + text: ModuleAppYmlReader().surverysTaskModel?.itemQuestion ?? Constants.YamlDefaults.favorite, + answerFormat: appleAnswerFormat) + let appleFormStep = ORKFormStep(identifier: "appleFormStepIdentifier", title: "Fruit!", text: "Select the fruit you like.") + appleFormStep.formItems = [appleFormItem] + return ORKOrderedTask(identifier: String(describing: Identifier.groupedFormTask), steps: [step, question1Step, question2Step, appleFormStep]) + } +} + +// MARK: - Consent task +extension TaskListRow { + // MARK: Consent Document Creation Convenience + /** + A consent document provides the content for the visual consent and consent + review steps. This helper sets up a consent document with some dummy + content. You should populate your consent document to suit your study. + */ + private var consentDocument: ORKConsentDocument { + let consentDocument = ORKConsentDocument() + + /* + This is the title of the document, displayed both for review and in + the generated PDF. + */ + consentDocument.title = NSLocalizedString("Example Consent", comment: "") + // This is the title of the signature page in the generated document. + consentDocument.signaturePageTitle = NSLocalizedString("Consent", comment: "") + /* + This is the line shown on the signature page of the generated document, + just above the signatures. + */ + consentDocument.signaturePageContent = NSLocalizedString("I agree to participate in this research study.", comment: "") + /* + Add the participant signature, which will be filled in during the + consent review process. This signature initially does not have a + signature image or a participant name; these are collected during + the consent review step. + */ + let participantSignatureTitle = NSLocalizedString("Participant", comment: "") + let participantSignature = ORKConsentSignature( + forPersonWithTitle: participantSignatureTitle, + dateFormatString: nil, + identifier: String(describing: Identifier.consentDocumentParticipantSignature)) + consentDocument.addSignature(participantSignature) + /* + Add the investigator signature. This is pre-populated with the + investigator's signature image and name, and the date of their + signature. If you need to specify the date as now, you could generate + a date string with code here. + This signature is only used for the generated PDF. + */ + let signatureImage = UIImage(named: "signature")! + let investigatorSignatureTitle = NSLocalizedString("Investigator", comment: "") + let investigatorSignatureGivenName = NSLocalizedString("Jonny", comment: "") + let investigatorSignatureFamilyName = NSLocalizedString("Appleseed", comment: "") + let investigatorSignatureDateString = "3/10/15" + let investigatorSignature = ORKConsentSignature( + forPersonWithTitle: investigatorSignatureTitle, + dateFormatString: nil, + identifier: String(describing: Identifier.consentDocumentInvestigatorSignature), + givenName: investigatorSignatureGivenName, + familyName: investigatorSignatureFamilyName, + signatureImage: signatureImage, + dateString: investigatorSignatureDateString) + consentDocument.addSignature(investigatorSignature) + /* + This is the HTML content for the "Learn More" page for each consent + section. In a real consent, this would be your content, and you would + have different content for each section. + + If your content is just text, you can use the `content` property + instead of the `htmlContent` property of `ORKConsentSection`. + */ + let htmlContentString = "
  • Lorem
  • ipsum
  • dolor

\(loremIpsumLongText)

\(loremIpsumMediumText)

" + /* + These are all the consent section types that have pre-defined animations + and images. We use them in this specific order, so we see the available + animated transitions. + */ + let consentSectionTypes: [ORKConsentSectionType] = [ + .overview, + .dataGathering, + .privacy, + .dataUse, + .timeCommitment, + .studySurvey, + .studyTasks, + .withdrawing + ] + /* + For each consent section type in `consentSectionTypes`, create an + `ORKConsentSection` that represents it. + + In a real app, you would set specific content for each section. + */ + var consentSections: [ORKConsentSection] = consentSectionTypes.map { contentSectionType in + let consentSection = ORKConsentSection(type: contentSectionType) + consentSection.summary = loremIpsumShortText + if contentSectionType == .overview { + consentSection.htmlContent = htmlContentString + } else { + consentSection.content = loremIpsumLongText + } + return consentSection + } + /* + This is an example of a section that is only in the review document + or only in the generated PDF, and is not displayed in `ORKVisualConsentStep`. + */ + let consentSection = ORKConsentSection(type: .onlyInDocument) + consentSection.summary = NSLocalizedString(".OnlyInDocument Scene Summary", comment: "") + consentSection.title = NSLocalizedString(".OnlyInDocument Scene", comment: "") + consentSection.content = loremIpsumLongText + consentSections += [consentSection] + // Set the sections on the document after they've been created. consentDocument.sections = consentSections - return consentDocument } - +} + +// MARK: - String +extension TaskListRow { // MARK: `ORKTask` Reused Text Convenience - private var exampleDescription: String { return NSLocalizedString("Your description goes here.", comment: "") } @@ -2021,17 +1470,20 @@ enum TaskListRow: Int, CustomStringConvertible { } private var loremIpsumMediumText: String { - return "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam adhuc, meo fortasse vitio, quid ego quaeram non perspicis. Plane idem, inquit, et maxima quidem, qua fieri nulla maior potest. Quonam, inquit, modo?" + return "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam adhuc, meo fortasse vitio, quid ego quaeram non perspicis." } private var loremIpsumLongText: String { - return "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam adhuc, meo fortasse vitio, quid ego quaeram non perspicis. Plane idem, inquit, et maxima quidem, qua fieri nulla maior potest. Quonam, inquit, modo? An potest, inquit ille, quicquam esse suavius quam nihil dolere? Cave putes quicquam esse verius. Quonam, inquit, modo?" + return """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam adhuc, meo fortasse vitio, quid ego quaeram non perspicis. + Plane idem, inquit, et maxima quidem, qua fieri nulla maior potest. Quonam, inquit, modo? An potest, inquit ille, + quicquam esse suavius quam nihil dolere? Cave putes quicquam esse verius. Quonam, inquit, modo? + """ } private var exampleHtml: String { return """ - diff --git a/OTFMagicBox/StaticViews/RK UI/TaskListViewController.swift b/OTFMagicBox/StaticViews/RK UI/TaskListViewController.swift index 1727c538..0e275fea 100755 --- a/OTFMagicBox/StaticViews/RK UI/TaskListViewController.swift +++ b/OTFMagicBox/StaticViews/RK UI/TaskListViewController.swift @@ -4,19 +4,19 @@ 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 @@ -27,20 +27,20 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + */ import UIKit import OTFResearchKit /** - This example displays a catalog of tasks, each consisting of one or two steps, - built using the ResearchKit framework. The `TaskListViewController` displays the - available tasks in this catalog. - - When you tap a task, it is presented like a participant in a study might - see it. After completing the task, you can see the results generated by - the task by switching to the results tab. -*/ + This example displays a catalog of tasks, each consisting of one or two steps, + built using the ResearchKit framework. The `TaskListViewController` displays the + available tasks in this catalog. + + When you tap a task, it is presented like a participant in a study might + see it. After completing the task, you can see the results generated by + the task by switching to the results tab. + */ class TaskListViewController: UITableViewController, ORKTaskViewControllerDelegate { var waitStepViewController: ORKWaitStepViewController? @@ -48,79 +48,79 @@ class TaskListViewController: UITableViewController, ORKTaskViewControllerDelega var waitStepProgress: CGFloat = 0.0 // MARK: Types - + enum TableViewCellIdentifier: String { case `default` = "Default" } - + // MARK: Properties - + /** - When a task is completed, the `TaskListViewController` calls this closure - with the created task. - */ + When a task is completed, the `TaskListViewController` calls this closure + with the created task. + */ var taskResultFinishedCompletionHandler: ((ORKResult) -> Void)? - + // MARK: View Life Cycle - + override func viewDidLoad() { super.viewDidLoad() - + if #available(iOS 13.0, *) { self.tableView.backgroundColor = UIColor.systemGroupedBackground } - + tableView.register(UITableViewCell.self, forCellReuseIdentifier: TableViewCellIdentifier.default.rawValue) } - + // MARK: UITableViewDataSource override func numberOfSections(in tableView: UITableView) -> Int { return TaskListRow.sections.count } - + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return TaskListRow.sections[section].rows.count } - + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return TaskListRow.sections[section].title } - + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifier.default.rawValue, for: indexPath) - + let taskListRow = TaskListRow.sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row] - + cell.textLabel!.text = "\(taskListRow)" - + if #available(iOS 13.0, *) { cell.textLabel?.textColor = UIColor.label } - + return cell } - + // MARK: UITableViewDelegate - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) - + // Present the task view controller that the user asked for. let taskListRow = TaskListRow.sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row] - + // Create a task from the `TaskListRow` to present in the `ORKTaskViewController`. let task = taskListRow.representedTask - + /* - Passing `nil` for the `taskRunUUID` lets the task view controller - generate an identifier for this run of the task. - */ + Passing `nil` for the `taskRunUUID` lets the task view controller + generate an identifier for this run of the task. + */ let taskViewController = ORKTaskViewController(task: task, taskRun: nil) // Make sure we receive events from `taskViewController`. taskViewController.delegate = self - + // Assign a directory to store `taskViewController` output. taskViewController.outputDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! @@ -131,23 +131,23 @@ class TaskListViewController: UITableViewController, ORKTaskViewControllerDelega */ present(taskViewController, animated: true, completion: nil) } - + // MARK: ORKTaskViewControllerDelegate - + func taskViewController(_ taskViewController: ORKTaskViewController, didFinishWith reason: ORKTaskViewControllerFinishReason, error: Error?) { /* - The `reason` passed to this method indicates why the task view - controller finished: Did the user cancel, save, or actually complete - the task; or was there an error? + The `reason` passed to this method indicates why the task view + controller finished: Did the user cancel, save, or actually complete + the task; or was there an error? - The actual result of the task is on the `result` property of the task - view controller. - */ + The actual result of the task is on the `result` property of the task + view controller. + */ taskResultFinishedCompletionHandler?(taskViewController.result) taskViewController.dismiss(animated: true, completion: nil) } - + func taskViewController(_ taskViewController: ORKTaskViewController, stepViewControllerWillAppear stepViewController: ORKStepViewController) { // Example data processing for the wait step. if stepViewController.step?.identifier == "WaitStepIndeterminate" || @@ -169,20 +169,19 @@ class TaskListViewController: UITableViewController, ORKTaskViewControllerDelega }) } } - + func taskViewController(_ taskViewController: ORKTaskViewController, learnMoreButtonPressedWith learnMoreStep: ORKLearnMoreInstructionStep, for stepViewController: ORKStepViewController) { - // FIXME: Temporary fix. This method should not be called if it is only used to present the learnMoreStepViewController, the stepViewController should present the learnMoreStepViewController. stepViewController.present(UINavigationController(rootViewController: ORKLearnMoreStepViewController(step: learnMoreStep)), animated: true) { - + } } - + func delay(_ delay: Double, closure: @escaping () -> Void ) { let delayTime = DispatchTime.now() + delay let dispatchWorkItem = DispatchWorkItem(block: closure) DispatchQueue.main.asyncAfter(deadline: delayTime, execute: dispatchWorkItem) } - + @objc func updateProgressOfWaitStepViewController() { if let waitStepViewController = waitStepViewController { diff --git a/OTFMagicBox/StaticViews/RK UI/TaskViewControllerRepresentable.swift b/OTFMagicBox/StaticViews/RK UI/TaskViewControllerRepresentable.swift index 986c60ff..dcb33399 100644 --- a/OTFMagicBox/StaticViews/RK UI/TaskViewControllerRepresentable.swift +++ b/OTFMagicBox/StaticViews/RK UI/TaskViewControllerRepresentable.swift @@ -11,57 +11,55 @@ import OTFResearchKit struct TaskViewControllerRepresentable: UIViewControllerRepresentable { let task: ORKTask - + var waitStepViewController: ORKWaitStepViewController? var waitStepUpdateTimer: Timer? var waitStepProgress: CGFloat = 0.0 - + var taskResultFinishedCompletionHandler: ((ORKResult) -> Void)? - + @Environment(\.presentationMode) var presentationMode - + typealias UIViewControllerType = ORKTaskViewController - + func makeUIViewController(context: Context) -> ORKTaskViewController { let taskViewController = ORKTaskViewController(task: task, taskRun: nil) - + taskViewController.delegate = context.coordinator taskViewController.outputDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! - + return taskViewController } - + func updateUIViewController(_ uiViewController: ORKTaskViewController, context: Context) { - + } - + func makeCoordinator() -> Coordinator { Coordinator(self) } - - class Coordinator: NSObject, ORKTaskViewControllerDelegate { var parent: TaskViewControllerRepresentable - + init(_ parent: TaskViewControllerRepresentable) { self.parent = parent } - + func taskViewController(_ taskViewController: ORKTaskViewController, didFinishWith reason: ORKTaskViewControllerFinishReason, error: Error?) { /* - The `reason` passed to this method indicates why the task view - controller finished: Did the user cancel, save, or actually complete - the task; or was there an error? + The `reason` passed to this method indicates why the task view + controller finished: Did the user cancel, save, or actually complete + the task; or was there an error? - The actual result of the task is on the `result` property of the task - view controller. - */ + The actual result of the task is on the `result` property of the task + view controller. + */ parent.taskResultFinishedCompletionHandler?(taskViewController.result) - //taskViewController.dismiss(animated: true, completion: nil) + // taskViewController.dismiss(animated: true, completion: nil) parent.presentationMode.wrappedValue.dismiss() } - + func taskViewController(_ taskViewController: ORKTaskViewController, stepViewControllerWillAppear stepViewController: ORKStepViewController) { // Example data processing for the wait step. if stepViewController.step?.identifier == "WaitStepIndeterminate" || @@ -77,27 +75,29 @@ struct TaskViewControllerRepresentable: UIViewControllerRepresentable { if let stepViewController = stepViewController as? ORKWaitStepViewController { self.parent.waitStepViewController = stepViewController self.parent.waitStepProgress = 0.0 - self.parent.waitStepUpdateTimer = Timer(timeInterval: 0.1, target: self, selector: #selector(TaskListViewController.updateProgressOfWaitStepViewController), userInfo: nil, repeats: true) + self.parent.waitStepUpdateTimer = Timer( + timeInterval: 0.1, + target: self, + selector: #selector(TaskListViewController.updateProgressOfWaitStepViewController), + userInfo: nil, + repeats: true) RunLoop.main.add(self.parent.waitStepUpdateTimer!, forMode: RunLoop.Mode.common) } }) } } - + func taskViewController(_ taskViewController: ORKTaskViewController, learnMoreButtonPressedWith learnMoreStep: ORKLearnMoreInstructionStep, for stepViewController: ORKStepViewController) { - // FIXME: Temporary fix. This method should not be called if it is only used to present the learnMoreStepViewController, the stepViewController should present the learnMoreStepViewController. stepViewController.present(UINavigationController(rootViewController: ORKLearnMoreStepViewController(step: learnMoreStep)), animated: true) { - + } } - - func delay(_ delay: Double, closure: @escaping () -> Void ) { let delayTime = DispatchTime.now() + delay let dispatchWorkItem = DispatchWorkItem(block: closure) DispatchQueue.main.asyncAfter(deadline: delayTime, execute: dispatchWorkItem) } - + @objc func updateProgressOfWaitStepViewController() { if let waitStepViewController = parent.waitStepViewController { diff --git a/OTFMagicBox/StaticViews/StaticUI.swift b/OTFMagicBox/StaticViews/StaticUI.swift index dc10e8ef..b92a17a6 100644 --- a/OTFMagicBox/StaticViews/StaticUI.swift +++ b/OTFMagicBox/StaticViews/StaticUI.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -40,15 +40,15 @@ struct CareKitViews: View { VStack { Text("ResearchKit Views") .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.screenTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) + .font(Font.otfscreenTitleFont) + .fontWeight(Font.otfheaderTitleWeight) List { - ContactsSection(cellbackgroundColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, headerColor: YmlReader().appTheme?.headerColor.color ?? .black, textColor: YmlReader().appTheme?.textColor.color ?? .black) - TaskSection(cellbackgroundColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, headerColor: YmlReader().appTheme?.headerColor.color ?? .black, textColor: YmlReader().appTheme?.textColor.color ?? .black) + ContactsSection() + TaskSection() } .listStyle(GroupedListStyle()) } - + } } @@ -57,62 +57,62 @@ struct ResearchKitViews: View { VStack { Text("ResearchKit Views") .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.screenTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.screenTitleFont.fontWeight) + .font(Font.otfscreenTitleFont) + .fontWeight(Font.otfscreenTitleFontWeight) List { - SurveysList(cellbackgroundColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, headerColor: YmlReader().appTheme?.headerColor.color ?? .black, textColor: YmlReader().appTheme?.textColor.color ?? .black) - SurveyQuestionsList(cellbackgroundColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, headerColor: YmlReader().appTheme?.headerColor.color ?? .black, textColor: YmlReader().appTheme?.textColor.color ?? .black) - OnboardingList(cellbackgroundColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, headerColor: YmlReader().appTheme?.headerColor.color ?? .black, textColor: YmlReader().appTheme?.textColor.color ?? .black) - ActiveTasksList(cellbackgroundColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, headerColor: YmlReader().appTheme?.headerColor.color ?? .black, textColor: YmlReader().appTheme?.textColor.color ?? .black) - MiscellaneousList(cellbackgroundColor: YmlReader().appTheme?.cellbackgroundColor.color ?? .black, headerColor: YmlReader().appTheme?.headerColor.color ?? .black, textColor: YmlReader().appTheme?.textColor.color ?? .black) + SurveysList() + SurveyQuestionsList() + OnboardingList() + ActiveTasksList() + MiscellaneousList() } .listStyle(GroupedListStyle()) } - + } } struct StaticUI: View { - + @State private var isPresenting = false - + init() { - UITableView.appearance().separatorColor = YmlReader().appTheme?.separatorColor.color - UITableView.appearance().backgroundColor = YmlReader().appTheme?.backgroundColor.color + UITableView.appearance().separatorColor = YmlReader().appStyle.separatorColor.color + UITableView.appearance().backgroundColor = YmlReader().appStyle.backgroundColor.color } var body: some View { NavigationView { VStack { Text("Sample Views") .foregroundColor(.otfTextColor) - .font(YmlReader().appTheme?.screenTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.headerTitleWeight.fontWeight) + .font(Font.otfscreenTitleFont) + .fontWeight(Font.otfheaderTitleWeight) List { - + NavigationLink(destination: CareKitViews()) { Text(ModuleAppYmlReader().careKitModel?.careKit ?? "CareKit") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .fontWeight(Font.otfFontWeight) } .foregroundColor(.otfTextColor) .listRowBackground(Color.otfCellBackground) - + NavigationLink(destination: ResearchKitViews()) { Text(ModuleAppYmlReader().researchKitModel?.researchKit ?? "ResearchKit") - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .fontWeight(Font.otfFontWeight) } .foregroundColor(.otfTextColor) .listRowBackground(Color.otfCellBackground) } .listStyle(GroupedListStyle()) - .onReceive(NotificationCenter.default.publisher(for: .deleteUserAccount)) { notification in + .onReceive(NotificationCenter.default.publisher(for: .deleteUserAccount)) { _ in isPresenting = true } .alert(isPresented: $isPresenting) { - + Alert( title: Text(Constants.CustomiseStrings.accountDeleted) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight), + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight), message: Text(Constants.deleteAccount), dismissButton: .default(Text(Constants.CustomiseStrings.okay), action: { OTFTheraforgeNetwork.shared.moveToOnboardingView() @@ -125,7 +125,7 @@ struct StaticUI: View { .background(Color.otfCellBackground) } } - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(Font.otfAppFont) } } diff --git a/OTFMagicBox/Styling/OTFStyle.swift b/OTFMagicBox/Styling/OTFStyle.swift new file mode 100644 index 00000000..ed30f907 --- /dev/null +++ b/OTFMagicBox/Styling/OTFStyle.swift @@ -0,0 +1,29 @@ +// +// OTFStyle.swift +// OTFMagicBox +// +// Created by Tomas Martins on 31/01/24. +// + +import Foundation +import SwiftUI +import OTFDesignSystem +import OTFCareKitUI + +class OTFStyle: OCKStyler { + let otfDesignStyle: OTFDesignStyler + let color: OCKColorStyler + + init(from otfDesignStyle: OTFDesignStyler) { + self.otfDesignStyle = otfDesignStyle + self.color = OTFThemeColorStyler(from: otfDesignStyle.color) + } +} + +public extension View { + internal func appStyle(_ style: OTFStyle) -> some View { + return self + .environment(\.otfdsStyle, style.otfDesignStyle) + .environment(\.careKitStyle, style) + } +} diff --git a/OTFMagicBox/Styling/OTFStyleColorStyler.swift b/OTFMagicBox/Styling/OTFStyleColorStyler.swift new file mode 100644 index 00000000..8abdacb0 --- /dev/null +++ b/OTFMagicBox/Styling/OTFStyleColorStyler.swift @@ -0,0 +1,107 @@ +// +// OTFStyleColorStyler.swift +// OTFMagicBox +// +// Created by Tomas Martins on 06/02/24. +// + +import Foundation +import OTFDesignSystem +import OTFCareKitUI + +class OTFThemeColorStyler: OCKColorStyler { + let otfDesignColor: OTFDesignStylerColor + + init(from otfDesignColor: OTFDesignStylerColor) { + self.otfDesignColor = otfDesignColor + } + + var label: UIColor { + return UIColor(otfDesignColor.label) + } + + var secondaryLabel: UIColor { + return UIColor(otfDesignColor.secondaryLabel) + } + + var tertiaryLabel: UIColor { + return UIColor(otfDesignColor.tertiaryLabel) + } + + var separator: UIColor { + return UIColor(otfDesignColor.separator) + } + + var customFill: UIColor { + return UIColor(otfDesignColor.customFill) + } + + var secondaryCustomFill: UIColor { + return UIColor(otfDesignColor.secondaryCustomFill) + } + + var tertiaryCustomFill: UIColor { + return UIColor(otfDesignColor.tertiaryCustomFill) + } + + var quaternaryCustomFill: UIColor { + return UIColor(otfDesignColor.quaternaryCustomFill) + } + + var customBlue: UIColor { + return UIColor(otfDesignColor.customBlue) + } + + var customGray: UIColor { + return UIColor(otfDesignColor.customGray) + } + + var customGray2: UIColor { + return UIColor(otfDesignColor.customGray2) + } + + var customGray3: UIColor { + return UIColor(otfDesignColor.customGray3) + } + + var customGray4: UIColor { + return UIColor(otfDesignColor.customGray4) + } + + var customGray5: UIColor { + return UIColor(otfDesignColor.customGray5) + } + + var white: UIColor { + return UIColor.white + } + + var black: UIColor { + return UIColor.black + } + + var clear: UIColor { + return UIColor.clear + } + + var customBackground: UIColor { + return UIColor(otfDesignColor.customBackground) + } + + var secondaryCustomBackground: UIColor { + return UIColor(otfDesignColor.secondaryCustomBackground) + } + + var customGroupedBackground: UIColor { + return UIColor(otfDesignColor.customGroupedBackground) + } + + var secondaryCustomGroupedBackground: UIColor { + return UIColor(otfDesignColor.secondaryCustomGroupedBackground) + } + + var tertiaryCustomGroupedBackground: UIColor { + return UIColor(otfDesignColor.tertiaryCustomGroupedBackground) + } +} + diff --git a/OTFMagicBox/Styling/OTFYamlStyle.swift b/OTFMagicBox/Styling/OTFYamlStyle.swift new file mode 100644 index 00000000..12411258 --- /dev/null +++ b/OTFMagicBox/Styling/OTFYamlStyle.swift @@ -0,0 +1,75 @@ +// +// OTFYamlStyle.swift +// OTFMagicBox +// +// Created by Tomas Martins on 06/02/24. +// + +import SwiftUI +import OTFDesignSystem +import OTFCareKitUI + +class OTFYamlStyle: OTFDesignStyler { + var color: OTFDesignStylerColor + + init(style: ThemeCustomization) { + self.color = StylerColor(style: style) + } +} + +extension OTFYamlStyle { + class StylerColor: OTFDesignStylerColor { + var label: Color + var secondaryLabel: Color + var separator: Color + var customFill: Color + var customGray: Color + var primaryButton: Color + var customBackground: Color + + init(style: ThemeCustomization) { + if let backgroundColor = style.backgroundColor.color { + self.customBackground = Color(backgroundColor) + } else { + self.customBackground = .systemBackground + } + + if let textColor = style.textColor.color { + self.label = Color(textColor) + } else { + self.label = Color(UIColor.label) + } + + if let separatorColor = style.separatorColor.color { + self.separator = Color(separatorColor) + } else { + self.separator = Color.separator + } + + if let cellBackgroundColor = style.cellbackgroundColor.color { + self.customFill = Color(cellBackgroundColor) + } else { + self.customFill = Color.tertiarySystemFill + } + + if let buttonTextColor = style.buttonTextColor.color { + self.primaryButton = Color(buttonTextColor) + } else { + self.primaryButton = Color.systemBlue + } + + if let borderColor = style.borderColor.color { + self.customGray = Color(borderColor) + } else { + self.customGray = Color(UIColor.systemGray) + } + + if let headerColor = style.headerColor.color { + self.secondaryLabel = Color(headerColor) + } else { + self.secondaryLabel = Color(UIColor.secondaryLabel) + } + } + + } +} diff --git a/OTFMagicBox/Tasks/TaskItem.swift b/OTFMagicBox/Tasks/TaskItem.swift index 1fff3d29..02d2e48e 100644 --- a/OTFMagicBox/Tasks/TaskItem.swift +++ b/OTFMagicBox/Tasks/TaskItem.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import Foundation @@ -37,14 +37,14 @@ import OTFResearchKit import SwiftUI /** - The list of tasks for the user. + The list of tasks for the user. */ enum TaskItem: Int, CaseIterable { // Task items. case sampleSurvey, sampleActivity - + // Task titles. var title: String { switch self { @@ -54,7 +54,7 @@ enum TaskItem: Int, CaseIterable { return "Activity" } } - + // Task sub titles. var subtitle: String { switch self { @@ -64,7 +64,7 @@ enum TaskItem: Int, CaseIterable { return "Sample sensor/data collection activities." } } - + // Icons for the tasks. var image: UIImage? { switch self { @@ -74,7 +74,7 @@ enum TaskItem: Int, CaseIterable { return getImage(named: "activityImage") } } - + // Section titles for the tasks. var sectionTitle: String { switch self { @@ -83,7 +83,7 @@ enum TaskItem: Int, CaseIterable { } } - // Action of a each task. + // Action of a each task. var action: some View { switch self { case .sampleSurvey: @@ -92,9 +92,8 @@ enum TaskItem: Int, CaseIterable { return AnyView(TaskViewController(tasks: TaskSamples.sampleWalkingTask)) } } - + fileprivate func getImage(named: String) -> UIImage? { UIImage(named: named) ?? UIImage(systemName: "questionmark.square") } } - diff --git a/OTFMagicBox/Tasks/TaskItemView.swift b/OTFMagicBox/Tasks/TaskItemView.swift index 2cf38785..3bc2d44f 100644 --- a/OTFMagicBox/Tasks/TaskItemView.swift +++ b/OTFMagicBox/Tasks/TaskItemView.swift @@ -1,51 +1,49 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI import OTFResearchKit - - struct TaskItemView: View { - + let item: TaskItem @State var showingDetail = false - + init(item: TaskItem) { self.item = item } - + var body: some View { HStack { if item.image != nil { @@ -53,11 +51,11 @@ struct TaskItemView: View { } VStack(alignment: .leading) { Text(item.title) - .font(YmlReader().appTheme?.headerTitleFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(.otfheaderTitleFont) + .fontWeight(Font.otfFontWeight) Text(item.subtitle) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } Spacer() } @@ -66,7 +64,7 @@ struct TaskItemView: View { self.showingDetail.toggle() })) .sheet(isPresented: $showingDetail, onDismiss: {}, content: { - item.action + item.action }) } } diff --git a/OTFMagicBox/Tasks/TaskSamples.swift b/OTFMagicBox/Tasks/TaskSamples.swift index 426d0f44..e323d783 100644 --- a/OTFMagicBox/Tasks/TaskSamples.swift +++ b/OTFMagicBox/Tasks/TaskSamples.swift @@ -1,100 +1,126 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFResearchKit /** The sample tasks for a user. -*/ -struct TaskSamples { + */ +enum TaskSamples { // Sample walking task. static let sampleWalkingTask: ORKOrderedTask = { let intendedUseDescription = Constants.CustomiseStrings.intendedDescription - + return ORKOrderedTask.shortWalk(withIdentifier: "ShortWalkTask", intendedUseDescription: intendedUseDescription, numberOfStepsPerLeg: 20, restDuration: 30, options: ORKPredefinedTaskOption()) }() - + /** Sample survey activity. - */ + */ static let sampleSurveyTask: ORKOrderedTask = { var steps = [ORKStep]() - + // Instruction step let instructionStep = ORKInstructionStep(identifier: "IntroStep") instructionStep.title = Constants.CustomiseStrings.instructionStepTitle instructionStep.text = Constants.CustomiseStrings.instructionStepText - + steps += [instructionStep] - - //In general, would you say your health is: - let healthScaleAnswerFormat = ORKAnswerFormat.scale(withMaximumValue: 5, minimumValue: 1, defaultValue: 3, step: 1, vertical: false, maximumValueDescription: "Excellent", minimumValueDescription: "Poor") - let healthScaleQuestionStep = ORKQuestionStep(identifier: "HealthScaleQuestionStep", title: Constants.CustomiseStrings.healthScaleTitle, question: Constants.CustomiseStrings.healthScaleQuestion, answer: healthScaleAnswerFormat) - + + // In general, would you say your health is: + let healthScaleAnswerFormat = ORKAnswerFormat.scale( + withMaximumValue: 5, + minimumValue: 1, + defaultValue: 3, + step: 1, + vertical: false, + maximumValueDescription: "Excellent", + minimumValueDescription: "Poor") + let healthScaleQuestionStep = ORKQuestionStep( + identifier: "HealthScaleQuestionStep", + title: Constants.CustomiseStrings.healthScaleTitle, + question: Constants.CustomiseStrings.healthScaleQuestion, + answer: healthScaleAnswerFormat) + steps += [healthScaleQuestionStep] - + let textChoices = [ ORKTextChoice(text: "Yes, Limited A lot", value: 0 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "Yes, Limited A Little", value: 1 as NSCoding & NSCopying & NSObjectProtocol), ORKTextChoice(text: "No, Not Limited At All", value: 2 as NSCoding & NSCopying & NSObjectProtocol) ] let textChoiceAnswerFormat = ORKAnswerFormat.choiceAnswerFormat(with: .singleChoice, textChoices: textChoices) - let textStep = ORKQuestionStep(identifier: "TextStep", title: "Daily Activities", question: "MODERATE ACTIVITIES, such as moving a table, pushing a vacuum cleaner, bowling, or playing golf:", answer: textChoiceAnswerFormat) - + let textStep = ORKQuestionStep( + identifier: "TextStep", + title: "Daily Activities", + question: "MODERATE ACTIVITIES, such as moving a table, pushing a vacuum cleaner, bowling, or playing golf:", + answer: textChoiceAnswerFormat) + steps += [textStep] - - - let formItem = ORKFormItem(identifier: "FormItem1", text: "MODERATE ACTIVITIES, such as moving a table, pushing a vacuum cleaner, bowling, or playing golf:", answerFormat: textChoiceAnswerFormat) - let formItem2 = ORKFormItem(identifier: "FormItem2", text: "Climbing SEVERAL flights of stairs:", answerFormat: textChoiceAnswerFormat) - let formStep = ORKFormStep(identifier: "FormStep", title: "Daily Activities", text: "The following two questions are about activities you might do during a typical day. Does YOUR HEALTH NOW LIMIT YOU in these activities? If so, how much?") + let formItem = ORKFormItem( + identifier: "FormItem1", + text: "MODERATE ACTIVITIES, such as moving a table, pushing a vacuum cleaner, bowling, or playing golf:", + answerFormat: textChoiceAnswerFormat) + let formItem2 = ORKFormItem( + identifier: "FormItem2", + text: "Climbing SEVERAL flights of stairs:", + answerFormat: textChoiceAnswerFormat) + let formStep = ORKFormStep( + identifier: "FormStep", + title: "Daily Activities", + text: "The following two questions are about activities you might do during a typical day. Does YOUR HEALTH NOW LIMIT YOU in these activities? If so, how much?") formStep.formItems = [formItem, formItem2] - + steps += [formStep] - + let booleanAnswer = ORKBooleanAnswerFormat(yesString: "Yes", noString: "No") - let booleanQuestionStep = ORKQuestionStep(identifier: "QuestionStep", title: nil, question: "In the past four weeks, did you feel limited in the kind of work that you can accomplish?", answer: booleanAnswer) - + let booleanQuestionStep = ORKQuestionStep( + identifier: "QuestionStep", + title: nil, + question: "In the past four weeks, did you feel limited in the kind of work that you can accomplish?", + answer: booleanAnswer) + steps += [booleanQuestionStep] - - //SUMMARY + + // SUMMARY let summaryStep = ORKCompletionStep(identifier: "SummaryStep") summaryStep.title = "Thank you." summaryStep.text = "We appreciate your time." - + steps += [summaryStep] - + return ORKOrderedTask(identifier: "SurveyTask-Assessment", steps: steps) }() } diff --git a/OTFMagicBox/Tasks/TaskViewController.swift b/OTFMagicBox/Tasks/TaskViewController.swift index b4436384..4ae8b73d 100644 --- a/OTFMagicBox/Tasks/TaskViewController.swift +++ b/OTFMagicBox/Tasks/TaskViewController.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ import UIKit @@ -37,22 +37,20 @@ import SwiftUI import OTFResearchKit struct TaskViewController: UIViewControllerRepresentable { - + let vc: ORKTaskViewController - + init(tasks: ORKOrderedTask) { self.vc = ORKTaskViewController(task: tasks, taskRun: NSUUID() as UUID) - + } typealias UIViewControllerType = ORKTaskViewController - + func updateUIViewController(_ taskViewController: ORKTaskViewController, context: Context) { } func makeUIViewController(context: Context) -> ORKTaskViewController { - - // & present the VC! return self.vc } - + } diff --git a/OTFMagicBox/Tasks/TasksUIView.swift b/OTFMagicBox/Tasks/TasksUIView.swift index 60427318..7845175c 100644 --- a/OTFMagicBox/Tasks/TasksUIView.swift +++ b/OTFMagicBox/Tasks/TasksUIView.swift @@ -1,84 +1,84 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI /** - The Tasks view, where a patient performs activities. + The Tasks view, where a patient performs activities. */ struct TasksUIView: View { - + var date: String { let formatter = DateFormatter() formatter.dateFormat = "MMM. d, YYYY" let date = formatter.string(from: Date()) return date } - + let color: Color - + let listItems = TaskItem.allCases - var listItemsPerHeader = [String:[TaskItem]]() + var listItemsPerHeader = [String: [TaskItem]]() var listItemsSections = [String]() - + init(color: Color) { self.color = color - - if listItemsPerHeader.count <= 0 { // init + + if listItemsPerHeader.isEmpty { for item in listItems { if listItemsPerHeader[item.sectionTitle] == nil { listItemsPerHeader[item.sectionTitle] = [TaskItem]() listItemsSections.append(item.sectionTitle) } - + listItemsPerHeader[item.sectionTitle]?.append(item) } } } - + var body: some View { VStack { Text(YmlReader().appTitle) - .font(YmlReader().appTheme?.screenTitleFont.appFont ?? Font.system(size: 17.0)) + .font(Font.otfscreenTitleFont) .foregroundColor(self.color) .padding(.top, 20) Text(self.date) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) + .font(Font.otfAppFont) .padding() List { ForEach(listItemsSections, id: \.self) { key in - Section(header: Text(key).font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0))) { + Section(header: Text(key).font(Font.otfAppFont)) { ForEach(listItemsPerHeader[key]!, id: \.self) { item in TaskItemView(item: item) } @@ -91,6 +91,6 @@ struct TasksUIView: View { struct TasksUIView_Previews: PreviewProvider { static var previews: some View { - TasksUIView(color: Color(YmlReader().appTheme?.textColor.color ?? UIColor.black)) + TasksUIView(color: .otfTextColor) } } diff --git a/OTFMagicBox/ViewModifiers/StyleModifiers.swift b/OTFMagicBox/ViewModifiers/StyleModifiers.swift index 5a7d94ba..4794881d 100644 --- a/OTFMagicBox/ViewModifiers/StyleModifiers.swift +++ b/OTFMagicBox/ViewModifiers/StyleModifiers.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI @@ -49,7 +49,7 @@ extension View { .padding() .overlay(Capsule().strokeBorder(color, style: StrokeStyle(lineWidth: 1.0))) .padding() - + case .secureField: self.padding() .overlay(Capsule().strokeBorder(color, style: StrokeStyle(lineWidth: 1.0))) @@ -57,8 +57,6 @@ extension View { } } } - - extension Image { func logoStyle() -> some View { self.resizable() @@ -66,7 +64,7 @@ extension Image { .padding(.leading, Metrics.PADDING_HORIZONTAL_BUTTON * 4) .padding(.trailing, Metrics.PADDING_HORIZONTAL_BUTTON * 4) } - + func iconStyle() -> some View { self.resizable() .clipped() @@ -74,4 +72,3 @@ extension Image { .overlay(Circle().stroke(Color(YmlReader().primaryColor), lineWidth: 2.0)) } } - diff --git a/OTFMagicBox/ViewModifiers/ViewDidLoadModifier.swift b/OTFMagicBox/ViewModifiers/ViewDidLoadModifier.swift index d2ee9ee4..f9b17171 100644 --- a/OTFMagicBox/ViewModifiers/ViewDidLoadModifier.swift +++ b/OTFMagicBox/ViewModifiers/ViewDidLoadModifier.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI diff --git a/OTFMagicBox/Views/LaunchView.swift b/OTFMagicBox/Views/LaunchView.swift index 0687c7d3..ed47be48 100644 --- a/OTFMagicBox/Views/LaunchView.swift +++ b/OTFMagicBox/Views/LaunchView.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI @@ -37,13 +37,13 @@ import OTFCareKitStore import OTFCloudClientAPI struct LaunchView: View { - + @State var onboardingCompleted = UserDefaultsManager.onboardingDidComplete @State private var isDefaultAPIKey = false - + var body: some View { VStack(spacing: 10) { - if onboardingCompleted, let _ = TheraForgeKeychainService.shared.loadUser() { + if onboardingCompleted, TheraForgeKeychainService.shared.loadUser() != nil { MainView() } else { OnboardingView { @@ -55,25 +55,25 @@ struct LaunchView: View { isDefaultAPIKey = true return } - + didCompleteOnBoarding() - }).onReceive(NotificationCenter.default.publisher(for: .onboardingDidComplete)) { notification in + }).onReceive(NotificationCenter.default.publisher(for: .onboardingDidComplete)) { _ in didCompleteOnBoarding() }.alert(isPresented: $isDefaultAPIKey) { return Alert(title: Text(Constants.CustomiseStrings.apiKeyMissing) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - , + .font(Font.otfAppFont) + , message: Text(Constants.CustomiseStrings.setValidApiKey) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) - , + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) + , dismissButton: .cancel({ UserDefaultsManager.setOnboardingCompleted(false) onboardingCompleted = false })) } } - + func didCompleteOnBoarding() { self.onboardingCompleted = UserDefaultsManager.onboardingDidComplete } diff --git a/OTFMagicBox/Views/LoadingView.swift b/OTFMagicBox/Views/LoadingView.swift index 5048dc02..53625e18 100644 --- a/OTFMagicBox/Views/LoadingView.swift +++ b/OTFMagicBox/Views/LoadingView.swift @@ -1,47 +1,47 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. + 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. + 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 contributor(s) 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. + 3. Neither the name of the copyright holder(s) nor the names of any contributor(s) 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. -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. + THIS SOFTWARE IS 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 SwiftUI struct LoadingView: View { - + private let username: String - + init(username: String) { self.username = username } - + var body: some View { VStack(spacing: 10) { if #available(iOS 14.0, *) { @@ -58,15 +58,18 @@ struct LoadingView: View { } struct ActivityIndicator: UIViewRepresentable { - + typealias UIView = UIActivityIndicatorView var isAnimating: Bool - fileprivate var configuration = { (indicator: UIView) in } + fileprivate var configuration = { (_: UIView) in } func makeUIView(context: UIViewRepresentableContext) -> UIView { UIView() } func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext) { - isAnimating ? uiView.startAnimating() : uiView.stopAnimating() + if isAnimating { + uiView.startAnimating() + } else { + uiView.stopAnimating() + } configuration(uiView) } } - diff --git a/OTFMagicBox/Views/MainView.swift b/OTFMagicBox/Views/MainView.swift index 783ec19b..d21ab0bb 100644 --- a/OTFMagicBox/Views/MainView.swift +++ b/OTFMagicBox/Views/MainView.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -33,14 +33,16 @@ */ import SwiftUI +import OTFCareKitUI import OTFCareKitStore struct MainView: View { - + let color: Color - + init() { - self.color = Color(YmlReader().primaryColor) + self.color = Color(YmlReader().appStyle.buttonTextColor.color ?? + YmlReader().primaryColor) OTFTheraforgeNetwork.shared.refreshToken { response in switch response { case .success(let data): @@ -51,56 +53,57 @@ struct MainView: View { } } } + } - + var body: some View { TabView { if YmlReader().useCareKit { ScheduleViewControllerRepresentable().tabItem { UIImage.loadImage(named: "tab_schedule").renderingMode(.template) Text("Tasks") - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } + .ignoresSafeArea(.all) NavigationView { - ContactsViewController(storeManager: CareKitManager.shared.synchronizedStoreManager) + ContactsViewController(storeManager: CareKitStoreManager.shared.synchronizedStoreManager) .navigationBarTitle(Text("Care Team"), displayMode: .inline) } .tabItem { UIImage.loadImage(named: "tab_care").renderingMode(.template) Text("Contacts") - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } } - + if YmlReader().showCheckupScreen { CheckUpView().tabItem { UIImage.loadImage(named: "tab_tasks").renderingMode(.template) Text("Check Up") - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } } - + if YmlReader().showStaticUIScreen { StaticUI().tabItem { Image(systemName: "uiwindow.split.2x1") Text("UI") - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } } - + ProfileUIView().tabItem { UIImage.loadImage(named: "tab_profile").renderingMode(.template) Text(Constants.CustomiseStrings.profile) - .font(YmlReader().appTheme?.textFont.appFont ?? Font.system(size: 17.0)) - .fontWeight(YmlReader().appTheme?.textWeight.fontWeight) + .font(Font.otfAppFont) + .fontWeight(Font.otfFontWeight) } } .accentColor(self.color) - } } diff --git a/OTFMagicBox/Views/RingProgressView.swift b/OTFMagicBox/Views/RingProgressView.swift index 323a0273..082d74b1 100644 --- a/OTFMagicBox/Views/RingProgressView.swift +++ b/OTFMagicBox/Views/RingProgressView.swift @@ -1,25 +1,25 @@ /* Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - + 4. Commercial redistribution in any form requires an explicit license agreement with the copyright holder(s). Please contact support@hippocratestech.com for further information regarding licensing. - + 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. @@ -39,14 +39,14 @@ struct RingProgressView: View { var color: Color var lineWidth: CGFloat var opacity: Double = 0.3 - + var body: some View { ZStack { Circle() .stroke(lineWidth: lineWidth) .opacity(opacity) .foregroundColor(color) - + Circle() .trim(from: 0.0, to: CGFloat(min(progress, 1.0))) .stroke(style: StrokeStyle(lineWidth: lineWidth, lineCap: .round, lineJoin: .round)) diff --git a/OTFMagicBoxTests/OTFMagicBoxTests.swift b/OTFMagicBoxTests/OTFMagicBoxTests.swift index 11d02d1a..a102bcd9 100644 --- a/OTFMagicBoxTests/OTFMagicBoxTests.swift +++ b/OTFMagicBoxTests/OTFMagicBoxTests.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 XCTest diff --git a/OTFMagicBoxTests/OTFMagicBoxYamlTests.swift b/OTFMagicBoxTests/OTFMagicBoxYamlTests.swift index f7e5fc67..af280a8f 100644 --- a/OTFMagicBoxTests/OTFMagicBoxYamlTests.swift +++ b/OTFMagicBoxTests/OTFMagicBoxYamlTests.swift @@ -1,35 +1,35 @@ /* -Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. - -4. Commercial redistribution in any form requires an explicit license agreement with the -copyright holder(s). Please contact support@hippocratestech.com for further information -regarding licensing. - -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. + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 XCTest @@ -38,40 +38,38 @@ import XCTest class OTFMagicBoxYamlTests: XCTestCase { /************************************************* THERAFORGE CONFIGURATIONS TESTS *******************************************************************************/ - + func testPrimaryColor() { let inputValue = YmlReader().primaryColor let expectedValue = UIColor.systemTeal XCTAssertEqual(inputValue, expectedValue) } - + func testTintColor() { let inputValue = YmlReader().tintColor let expectedValue = UIColor.blue XCTAssertEqual(inputValue, expectedValue) } - + func testRegistrationIsDOB() { let inputValue = ModuleAppYmlReader().registration?.showDateOfBirth let expectedValue = Constants.true XCTAssertEqual(inputValue, expectedValue) } - + func testRegistrationIsGender() { let inputValue = ModuleAppYmlReader().registration?.showGender let expectedValue = Constants.true XCTAssertEqual(inputValue, expectedValue) } - + /************************************************* CARDINALKIT CONFIGURATIONS TESTS *******************************************************************************/ - + func testStudyTitle() { let inputValue = YmlReader().studyTitle let expectedValue = "Health Study" XCTAssertEqual(inputValue, expectedValue) } - - func testLoginPasswordless() { let inputValue = ModuleAppYmlReader().loginPasswordless let expectedValue = true @@ -83,7 +81,7 @@ class OTFMagicBoxYamlTests: XCTestCase { let expectedValue = "Almost done!" XCTAssertEqual(inputValue, expectedValue) } - + func testLoginStepText() { let inputValue = ModuleAppYmlReader().loginStepText let expectedValue = "We need to confirm your email address and send you a copy of the consent you just signed." @@ -97,63 +95,60 @@ class OTFMagicBoxYamlTests: XCTestCase { title: "Welcome to MagicBox", color: "Black", description: "Your health care app") - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testTeamEmail() { let inputValue = YmlReader().teamEmail let expectedValue = "info@hippocratestech.com" - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testConsentTitle() { let inputValue = ModuleAppYmlReader().consentTitle let expectedValue = "TheraForge Consent" - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testPasscodeType() { let inputValue = ModuleAppYmlReader().passcodeType let expectedValue = "4" - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testFailedLoginTitle() { let inputValue = ModuleAppYmlReader().failedLoginTitle let expectedValue = "Unable to Login" - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testHealthPermissionsTitle() { let inputValue = ModuleAppYmlReader().healthPermissionsTitle let expectedValue = "Permission to read activity data 🏃🏽‍♀️" - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testUseCareKit() { let inputValue = YmlReader().useCareKit let expectedValue = true - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testHealthRecordsPermissionTitle() { let inputValue = ModuleAppYmlReader().healthRecords?.permissionsTitle let expectedValue = "Permission to read Health Records 🏥" - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testHealthKitTypes() { let inputValue = ModuleAppYmlReader().healthKitDataToRead.first let expectedValue = HealthKitTypes(type: "StepCount") - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - + func testCompletionStepTitle() { let inputValue = ModuleAppYmlReader().completionStepTitle let expectedValue = "Welcome aboard." - XCTAssertEqual(inputValue, expectedValue); + XCTAssertEqual(inputValue, expectedValue) } - - } - diff --git a/OTFMagicBox Watch Watch App/Assets.xcassets/AccentColor.colorset/Contents.json b/OTFMagicBoxWatch/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from OTFMagicBox Watch Watch App/Assets.xcassets/AccentColor.colorset/Contents.json rename to OTFMagicBoxWatch/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/OTFMagicBox Watch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json b/OTFMagicBoxWatch/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from OTFMagicBox Watch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json rename to OTFMagicBoxWatch/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/OTFMagicBox Watch Watch App/Assets.xcassets/Contents.json b/OTFMagicBoxWatch/Assets.xcassets/Contents.json similarity index 100% rename from OTFMagicBox Watch Watch App/Assets.xcassets/Contents.json rename to OTFMagicBoxWatch/Assets.xcassets/Contents.json diff --git a/OTFMagicBoxWatch/ContentView.swift b/OTFMagicBoxWatch/ContentView.swift new file mode 100644 index 00000000..afb7f4c9 --- /dev/null +++ b/OTFMagicBoxWatch/ContentView.swift @@ -0,0 +1,50 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFCareKit +import SwiftUI +import WatchKit +import OTFCareKitStore + +struct ContentView: View { + @ViewBuilder var body: some View { + if #available(watchOS 7, *) { + CareKitListView() + } + } +} + +#Preview { + ContentView() +} diff --git a/OTFMagicBoxWatch/DataStore/OTFCareKitStoreManager.swift b/OTFMagicBoxWatch/DataStore/OTFCareKitStoreManager.swift new file mode 100644 index 00000000..cc4d37e6 --- /dev/null +++ b/OTFMagicBoxWatch/DataStore/OTFCareKitStoreManager.swift @@ -0,0 +1,75 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFCloudantStore +import WatchConnectivity +import WatchKit +import OTFCareKit +import OTFCareKitStore +import Combine + +class OTFCareKitStoreManager: NSObject { + static var shared = OTFCareKitStoreManager() + let peer = OTFWatchConnectivityPeer() + var cloudantStore: OTFCloudantStore! + var session: SessionManager! + var synchronizedStoreManager: OCKSynchronizedStoreManager! + var coordinator: OCKStoreCoordinator = { + let coordinator = OCKStoreCoordinator() + return coordinator + }() + + override init() { + let store = try? WatchStoreService.shared.currentStore(peer: self.peer) + guard let cloudantStore = store else { return } + self.cloudantStore = cloudantStore + + self.coordinator.attach(store: self.cloudantStore) + synchronizedStoreManager = OCKSynchronizedStoreManager(wrapping: coordinator) + + peer.automaticallySynchronizes = true + session = SessionManager(peer: peer, store: cloudantStore) + + let subscriber = Subscribers.Sink { _ in + } receiveValue: { _ in + store?.synchronize(target: Target.mobile, completion: { _ in }) + } + + synchronizedStoreManager.notificationPublisher.receive(subscriber: subscriber) + } + + func wipe() throws { + try cloudantStore.datastoreManager.deleteDatastoreNamed("local_db") + } +} diff --git a/OTFMagicBoxWatch/DataStore/WatchStoreService.swift b/OTFMagicBoxWatch/DataStore/WatchStoreService.swift new file mode 100644 index 00000000..f0a5abc1 --- /dev/null +++ b/OTFMagicBoxWatch/DataStore/WatchStoreService.swift @@ -0,0 +1,48 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. + */ + +import Foundation +import OTFCloudantStore + +public class WatchStoreService { + public static let shared = WatchStoreService() + + /** + - Description: It will return an instance of OTFCloudantStore initialized with the default db name `local_db` + - Returns: Fully initialized OTFCloudantStore object. + */ + public func currentStore(peer: OTFWatchConnectivityPeer) throws -> OTFCloudantStore { + return try OTFCloudantStore(storeName: "local_db", remote: peer) + } +} diff --git a/OTFMagicBoxWatch/Extensions/Extension+Notification.swift b/OTFMagicBoxWatch/Extensions/Extension+Notification.swift new file mode 100644 index 00000000..57191bf6 --- /dev/null +++ b/OTFMagicBoxWatch/Extensions/Extension+Notification.swift @@ -0,0 +1,41 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. + */ + +import Foundation + +extension NSNotification.Name { + static let synced = NSNotification.Name("synced") + static let databaseSync = NSNotification.Name("databaseSync") + static let userLoggedOut = NSNotification.Name("userLoggedOut") +} diff --git a/OTFMagicBoxWatch/Extensions/Extension+OCKTask.swift b/OTFMagicBoxWatch/Extensions/Extension+OCKTask.swift new file mode 100644 index 00000000..a7c35768 --- /dev/null +++ b/OTFMagicBoxWatch/Extensions/Extension+OCKTask.swift @@ -0,0 +1,86 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFCareKitStore +import OTFCareKit + +private struct GroupIdentifierKeys: Codable { + var viewType: TaskStyle = .simple +} + +extension OCKTask { + private var groupIdentifierKeys: GroupIdentifierKeys { + guard let groupIdentifier = groupIdentifier else { return GroupIdentifierKeys() } + let data = Data(groupIdentifier.utf8) + let keys = try? JSONDecoder().decode(GroupIdentifierKeys.self, from: data) + return keys ?? GroupIdentifierKeys() + } + + var viewType: TaskStyle { + return groupIdentifierKeys.viewType + } +} + +enum TaskStyle: String, CaseIterable, Codable { + case simple, instruction, buttonLog + case grid, checklist + case labeledValue = "labeled value", numericProgress = "Numeric Progress" + var rawValue: String { + switch self { + case .simple: + return "Simple" + case .instruction: + return "instruction" + case .buttonLog: + return "buttonLog" + case .grid: + return "grid" + case .checklist: + return "checklist" + case .labeledValue: + return "labeled value" + case .numericProgress: + return "Numeric Progress" + } + } + + var supportsSwiftUI: Bool { + guard #available(iOS 14, *) else { return false } + + switch self { + case .simple, .instruction, .labeledValue, .numericProgress: return true + case .grid, .checklist, .buttonLog: return false + } + } +} diff --git a/OTFMagicBoxWatch/Managers/SessionManager.swift b/OTFMagicBoxWatch/Managers/SessionManager.swift new file mode 100644 index 00000000..b91625ab --- /dev/null +++ b/OTFMagicBoxWatch/Managers/SessionManager.swift @@ -0,0 +1,109 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 OTFCloudantStore +import WatchConnectivity +import WatchKit +import OTFCareKitStore +import OTFCareKit + +class SessionManager: NSObject, WCSessionDelegate { + + fileprivate(set) var peer: OTFWatchConnectivityPeer! + fileprivate(set) var store: OTFCloudantStore! + @Published var tasks = [OCKAnyTask]() + + init(peer: OTFWatchConnectivityPeer!, store: OTFCloudantStore!) { + super.init() + self.peer = peer + self.store = store + WCSession.default.delegate = self + WCSession.default.activate() + } + + func session(_ session: WCSession, + activationDidCompleteWith activationState: WCSessionActivationState, + error: Error?) { + + print("New session state: \(activationState)") + if let error { + print("Error is \(error.localizedDescription)") + } + + switch activationState { + case .activated: + print("WCSession activated successfully") + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + self.store.synchronize { error in + print(error?.localizedDescription ?? "Successful sync!") + DispatchQueue.main.async { + NotificationCenter.default.post(name: .databaseSync, object: nil) + } + } + } + + case .inactive: + print("Unable to activate the WCSession. Error: \(error?.localizedDescription ?? "--")") + case .notActivated: + print("Unexpected .notActivated state received after trying to activate the WCSession") + @unknown default: + print("Unexpected state received after trying to activate the WCSession") + } + } + + func session(_ session: WCSession, + didReceiveMessage message: [String: Any], + replyHandler: @escaping ([String: Any]) -> Void) { + print("Did receive message from MOBILE APP!") + if message[databaseSyncedKey] as? String != nil { + self.store.synchronize { error in + print(error?.localizedDescription ?? "Successful sync!") + DispatchQueue.main.async { + NotificationCenter.default.post(name: .databaseSync, object: nil) + } + } + } else if message["userNotLoggedIn"] as? String != nil { + // Wipe out data + self.store.deleteRecords { _ in + DispatchQueue.main.async { + NotificationCenter.default.post(name: .userLoggedOut, object: nil) + } + } + } else { + peer.reply(to: message, store: store) { reply in + replyHandler(reply) + } + } + } +} diff --git a/OTFMagicBox Watch Watch App/OTFMagicBox Watch Watch App.entitlements b/OTFMagicBoxWatch/OTFMagicBoxWatch.entitlements similarity index 87% rename from OTFMagicBox Watch Watch App/OTFMagicBox Watch Watch App.entitlements rename to OTFMagicBoxWatch/OTFMagicBoxWatch.entitlements index dab226cc..e3ba5ffc 100644 --- a/OTFMagicBox Watch Watch App/OTFMagicBox Watch Watch App.entitlements +++ b/OTFMagicBoxWatch/OTFMagicBoxWatch.entitlements @@ -5,7 +5,9 @@ com.apple.developer.healthkit com.apple.developer.healthkit.access - + + health-records + com.apple.developer.healthkit.background-delivery diff --git a/OTFMagicBoxWatch/OTFMagicBoxWatch.swift b/OTFMagicBoxWatch/OTFMagicBoxWatch.swift new file mode 100644 index 00000000..34bcdbdd --- /dev/null +++ b/OTFMagicBoxWatch/OTFMagicBoxWatch.swift @@ -0,0 +1,44 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI + +@main +struct OTFMagicBoxWatch: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/OTFMagicBox Watch Watch App/Preview Content/Preview Assets.xcassets/Contents.json b/OTFMagicBoxWatch/Preview Content/Preview Assets.xcassets/Contents.json similarity index 100% rename from OTFMagicBox Watch Watch App/Preview Content/Preview Assets.xcassets/Contents.json rename to OTFMagicBoxWatch/Preview Content/Preview Assets.xcassets/Contents.json diff --git a/OTFMagicBoxWatch/Views/ActivityIndicatorView.swift b/OTFMagicBoxWatch/Views/ActivityIndicatorView.swift new file mode 100644 index 00000000..3c17c6d7 --- /dev/null +++ b/OTFMagicBoxWatch/Views/ActivityIndicatorView.swift @@ -0,0 +1,44 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI + +struct ActivityIndicatorView: View { + var body: some View { + ProgressView { + Text("Loading...") + .font(.system(size: 10)) + } + } +} diff --git a/OTFMagicBoxWatch/Views/CareKitListView.swift b/OTFMagicBoxWatch/Views/CareKitListView.swift new file mode 100644 index 00000000..c49e5cb0 --- /dev/null +++ b/OTFMagicBoxWatch/Views/CareKitListView.swift @@ -0,0 +1,110 @@ +/* + Copyright (c) 2021, Hippocrates Technologies S.r.l.. 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 contributor(s) 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. + + 4. Commercial redistribution in any form requires an explicit license agreement with the + copyright holder(s). Please contact support@hippocratestech.com for further information + regarding licensing. + + 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 SwiftUI +import Contacts +import OTFCareKit +import OTFCareKitUI +import OTFCareKitStore +import WatchConnectivity + +struct CareKitListView: View { + let carekitstore = OTFCareKitStoreManager.shared + @State var tasks = [OCKTask]() + @State var userLoggedOut = false + @State var isLoading = true + + var body: some View { + VStack { + if isLoading { + VStack(alignment: .center) { + ActivityIndicatorView() + } + } else { + if userLoggedOut { + VStack(alignment: .center) { + Text("Please log in on your phone app to see the tasks!") + .padding(.init(top: 5, leading: 15, bottom: 5, trailing: 15)) + } + } else { + if tasks.isEmpty { + VStack(alignment: .center) { + Text("No task for today!") + .padding(.init(top: 5, leading: 15, bottom: 5, trailing: 15)) + } + } else { + List { + ForEach(tasks, id: \.id) { task in + SimpleTaskView(taskID: task.id, eventQuery: .init(for: task.effectiveDate), storeManager: carekitstore.synchronizedStoreManager) + } + } + } + } + } + }.onAppear { + getDailyTasks() + } + .onReceive(NotificationCenter.default.publisher(for: .databaseSync)) { _ in + userLoggedOut = false + isLoading = true + getDailyTasks() + } + .onReceive(NotificationCenter.default.publisher(for: .userLoggedOut)) { _ in + userLoggedOut = true + } + } + + func getDailyTasks() { + carekitstore.cloudantStore.fetchTasks { result in + switch result { + case .failure(_): + isLoading = false + case .success(let data): + tasks = [] + let todayTasks: [OCKTask] = data.filter({ $0.schedule.exists(onDay: Date()) }) + print("message from peer! \(todayTasks)") + DispatchQueue.main.async { + self.tasks = todayTasks + isLoading = false + } + } + } + } +} + +struct CareKitListView_Previews: PreviewProvider { + static var previews: some View { + CareKitListView() + } +} diff --git a/Podfile b/Podfile index 13aa5940..27bd5cd5 100644 --- a/Podfile +++ b/Podfile @@ -1,37 +1,30 @@ # Uncomment the next line to define a global platform for your project +source 'https://cdn.cocoapods.org' +source 'https://github.com/TheraForge/OTFCocoapodSpecs' -target 'OTFMagicBox' do - use_frameworks! - - source 'https://cdn.cocoapods.org' - source 'https://github.com/TheraForge/OTFCocoapodSpecs' +use_frameworks! - pod 'OTFToolBox/CareHealth', '1.0.3-beta' - pod 'GoogleSignIn', '~> 7.0.0' +target 'OTFMagicBox' do + platform :ios, '14.6' - platform :ios, '14.0' + pod 'OTFToolBox/CareHealth', '1.0.4-beta' + pod 'GoogleSignIn', '~> 7.0.0' end -target 'OTFMagicBox Watch Watch App' do - use_frameworks! - - source 'https://cdn.cocoapods.org' - source 'https://github.com/TheraForge/OTFCocoapodSpecs' - - # Only include the necessary dependency for the watchOS target - pod 'OTFCareKit/Care', '2.0.2-beta.3' - - platform :watchos, '7.0' +target 'OTFMagicBoxWatch' do + platform :watchos, '8.0' + + pod 'OTFCloudantStore/CloudantCareHealth', '1.0.4-beta' + pod 'OTFCareKit/CareHealth', '2.0.2-beta.4' end - post_install do |installer| - installer.generated_projects.each do |project| - project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' - config.build_settings['WATCHOS_DEPLOYMENT_TARGET'] = '7.0' - end - end - end + installer.generated_projects.each do |project| + project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0' + config.build_settings['WATCHOS_DEPLOYMENT_TARGET'] = '8.0' + end + end + end end diff --git a/README.md b/README.md index dfea1778..4d4340cd 100644 --- a/README.md +++ b/README.md @@ -8,17 +8,36 @@ For more details on the features of the SDK and on the TheraForge Cloud setup pr ## Change Log
+ Release 1.0.4-beta + + - **New Styling Structure** + - Thanks to the new OTFStyle structure, the app can now adopt a user-selected theme in the `AppSysParameter.yml` file, which is applied equally to custom components inside the app, CareKitUI components and OTFDesignSystem components. + - Added a new OTFStyle environment object and modifier, allowing developers to apply the selected custom style to all the components of the app, whether they are from the TheraForge design system or from CareKit; developers can even apply them to custom views they may want to create. + - Removed the appTheme property from AppSysParameter and replaced it with styles, an array of styles that developers can use to apply to the app or to add their own custom styles that they can create. + - Removed the color properties from the DesignConfig model, as the colors are now fetched from appStyle. + - **Updated OTFToolBox** + - Updated OTFToolbox version to 1.0.4-beta, which corresponds to an updated version of OTFToolBox that includes the new OTFDesignSystem framework. + - **Bug Fixes** + - Fixed a bug on the ScheduleViewController in which the background would not reach the bottom area of the screen outside the safe area. + - Fixed an issue in which, when scrolling a list on the ScheduleViewController list, the contents of the list would go over the navigation bar. This has been fixed by applying an opaque white background to the navigation bar. + - **WatchOS support** + - Improved watchOS support. + - **Watch Synchronisation** + - This release synchronizes daily tasks between iOS and watchOS and updates their outcomes in both local stores as well as in the cloud. +
+ +
Release 1.0.3-beta - - **End-to-End File Encryption (TheraForge CryptoBox)** - Added class-based end-to-end encryption (E2EE) and integrity verification technology to protect sensitive user data at rest or in transit with the XChaCha20Poly1305 algorithm, which is independent from and in addition to TLS and native storage crypto. This creates two independent layers of highly secure data cryptography. - - **Biometric Authentications** - The app supports biometric authentication (FaceID or TouchID), which provides a secure and user-friendly way to authenticate users. - - **Sign in Using Password AutoFill** - With just a few taps users can create and save new passwords or log in to an existing account - - **Manage Documents** - MagicBox allows you to upload, download, re-name and delete different documents. User profile pictures and consent forms are saved as documents. - - **Improved Theme Customization Using YAML File** + - **End-to-End File Encrption (TheraForge CryptoBox)** + Added end-to-end encrption feature which prevents third parties from accessing data while it's being transferred from one user to another + - **Biometric authentications** + The app supports biometric authentication which provides secure and user-friendly way to authenticate users + - **Password-less login, use auto-fill sign in** + With just a few taps, users can create and save new passwords or log in to an existing account + - **Manage documents** + MagicBox allows you to upload, donwload, re-name and delete different docuements. User's profile picture and consent form are saved as documents. + - **Improved theme customization using yml file** - Font - Font size - Font weight @@ -27,17 +46,17 @@ For more details on the features of the SDK and on the TheraForge Cloud setup pr - **Apple Watch Demo App** - Added a companion WatchOS app for MagicBox - Allow users to check and manage tasks for the current day from their Apple Watch - - **Enhanced Styling of the Profile Screen** - - **New Network Indicator** + - **Enhanced styling of the Profile screen** + - **New network indicator** - Implemented a networking indicator to provide a visual representation of the connection status to TheraForge CloudBox servers - - **New Consent Documents Layout Section in Profile Screen** + - **New Consent documents layout section in Profile screen** - **Accessibility Enhancements** - Enhanced VoiceOver support for the Bold Text and Invert Colors system options for enhanced accessibility - Added support for Bold Text and Invert Colors for enhanced accessibility options - **Design and Assets** - - Incorporated new assets, including more than 360 images and dozens of additional icons/non-Apple SF Symbols (such as social icons), ready to be used inside the iOS app + - Incorporated new assets, including more than 360 images and dozens of additional icons/SF Symbols, ready to be used inside the iOS app - **Compatibility Updates** - - Increased the iOS target version to iOS 14.5 for broader device compatibility and feature support, including all SF Symbols 2.2 + - Increased the iOS target version to iOS 14.5 for broader device compatibility and feature support
@@ -88,8 +107,8 @@ These are its primary characteristics: * Care plan management using Apple's Carekit framework. * Monitoring of health data with Apple's HealthKit framework. * Automatic data synchronization across the Cloud (a la Dropbox) using the OTFToolBox SDK. -* Support for various popular and innovative technologies out of the box: manual and biometric user authentication (Sign in with Apple in addition to standard login) with OAuth2, HIPAA- and GDPR-compliant traffic encryption at rest and in transit (uses TLS 1.3 crypto), real-time app notifications using HTTP2 Server-Sent Events (SSE), end-to-end file cryptography and integrity verification, etc. -* SF Symbols 2.2 support (available in iOS 14.5 and watchOS 7.4, and later releases) +* Support for various popular technologies out of the box: user authentication (Sign in with Apple in addition to standard login) with OAuth2, HIPAA- abd GDPR-compliant traffic encryption at rest and in transit (uses TLS 1.3 crypto), app notifications using HTTP 2 Server-Sent Events (SSE), etc. +* SF Symbols 1.1 support (available on iOS/iPadOS 13 and watchOS 6, and later releases). * CI/CD support via GitHub Actions. @@ -107,7 +126,7 @@ When a user launches an app for the first time, the onboarding process presents ## Consent -The informed consent is the process of a user granting authorization to an application to access specific resources on their behalf (for example, health sensors) and/or to perform certain actions (for example, as part of a medical study). Users will be asked for consent to allow access to their personal data. +The informed consent is the process of a user granting authorization to an application to access specific resources on their behalf (for exammple, health sensors) and/or to perform certain actions (for example, as part of a medical study). Users will be asked for consent to allow access to their personal data.

@@ -119,8 +138,8 @@ The consent form contains the description of the items included in the applicati

-## Consent Document in the Profile Section -In MagicBox users can check out their consent form in the profile screen by tapping on the Consent Documents section, as shown in the figure below. +## Add consent document page in profile section +In MagicBox user can now see their consent form in their profile screen by clicking on the Consent documents section.

@@ -140,23 +159,23 @@ User login credentials are securely stored in the device’s keychain.

-If you want to enable support for Google Sign-in, in Xcode add the GIDClientID parameter string in the info.plist file as shown in the figure. +Addition, add GIDClientID into info.plist file to enable Google login.

-## Biometric Authentication -MagicBox supports biometric authentication: a secure and user-friendly way to authenticate users in iOS by using Face ID or Touch ID, as shown in the figure below. +## Biometric authentications +The App support Biometric authentication. A secure and user-friendly way to authenticate users in iOS applications with the introduction of Face ID and Touch ID. -Users can authenticate by using Face ID or Touch ID. +User can authenticate by using their Face ID or Touch ID. -

+

-## Sign in Using Password AutoFill -MagicBox supports iOS Password AutoFill. With just a few taps, users can create and save new passwords or log in to an existing account. Users don’t need to enter their password, the system handles everything. It also encourages user to select strong passwords hence making user accounts more secure. +## Password-less Login, Autofill Sign in +MagicBox includes AutoFill feature. With just a few taps, users can create and save new passwords or log in to an existing account. Users don’t need to enter their password, the system handles everything. It also encourages user to select strong passwords hence making user account more secure. -

-

+

+

## Passcode @@ -182,15 +201,19 @@ Contacts are cards that contain doctor and family member details, such as addres

-## End-to-end File Encryption (TheraForge CryptoBox) -MagicBox supports class-based end-to-end file encryption using the secure and robust XChaCha20Poly1305 algorithm. It provides an additional layer of secure storage and additional security for communication that prevents third parties from accessing confidential data. Different classes can be used to provide selective access privileges to documents (the default class provides access to all the contacts explicitly approved by the user). Class-based encrypted files can only be decrypted by the intended receiver(s). +## End-to-end File Encrption (TheraForge CryptoBox) +MagicBox includes end-to-end encryption on document sending and receiving by the user. It provides secure storage and additional security for communication that prevents third parties from accessing confidential data. + +Encrypted files can only be decrypted by the intended receiver(s). + ## User Profile -In the profile section, users can manage their current session, edit their profile, contact support or withdraw from a study/project. + +In the profile section, the user can manage his current session, edit their profile, contact support and withdraw from a study.

-There's also a network indicator on top of the user's profile picture, indicating whether the user currently has a connection to the TheraForge CloudBox servers and it even indicates if it's connected via cellular or Wi-Fi. +There's also a network indicator on top of the user's profile picture, indicating whether the user currently has a connection to the TheraForge CloudBox servers and it even indicates if it's connected via cellular or though a wi-fi hotspot. ## TheraForge Secure Cloud with Sync Support @@ -236,9 +259,9 @@ MagicBox app is designed to be compatible with the iOS accessibility features, e |:----------:|:----------:|:----------:| | **Voice Over** | **Voice Control** | **Bold Text** | -## Apple Watch Demo App +## Apple Watch App -The MagicBox Demo Apple Watch App is designed as a companion app for the iPhone MagicBox application. This app is intended for users to quickly glance through their tasks and activities for the day conveniently on their Apple Watch. +The MagicBox Apple Watch App is designed as a companion app for the iPhone MagicBox application. This app is intended for users to quickly glance through their tasks and activities for the day conveniently on their Apple Watch. ![Apple Watch Demo App](Docs/91-apple-watch-demo.png) @@ -252,6 +275,22 @@ The app leverages [OTFCareKit](https://github.com/TheraForge/OTFCareKit) to fetc The Apple Watch app also supports Accessibility features, such as VoiceOver, Bold and Dynamic Text, ensuring that all users, regardless of their abilities, can use our app comfortably. +### Watch Synchronisation ### + - Synchronizes daily tasks from iOS to watchOS and updates their outcomes in both stores. + ```swift + // .mobile: synchronise watchOS store from IOS app + // .watchOS: fetch IOS app store from watchOS + // .watchAppUpdate: notify other device about data update + + CloudantSyncManager.shared.cloudantStore?.synchronize(target: .mobile, completion: { error in + if let error = error { + print(error) + } else { + OTFLog("Synced successfully!") + } + }) + ``` + ## Assets MagicBox includes a variety of assets, such as illustrations, icons, and glyphs, that are available for customization within the app. You can preview all the available assets on our [asset gallery](https://tfmart.github.io/OTFMagicBox/). @@ -263,7 +302,7 @@ You can also check the available assets locally on your machine by opening your ``` To use any of these assets in your project, simply follow these steps: -1. Locate the Images resource in Xcode's sidebar as shown in the figure below +1. Locate the Images resouce in Xcode's sidebar as shown in the figure below

2. Choose an image that you want to use in your application @@ -280,7 +319,7 @@ To review any of the optional assets to select and use them in the code, follow Image("doctor4") ``` -Any installed assets can also be used in the YAML customization files. For example, if we want to use this image on a custom section in the onboarding section of the app: +Any installed assets can also be used in the YAML customization files. For exameple, if we want to use this image on a custom section in the onboarding section of the app: ```yaml summary: "This is custom section." @@ -436,7 +475,7 @@ git clone https://github.com/TheraForge/OTFMagicBox.git -Then change the directory to the newly created OTFMagicBox subdirectory: +Then change the directory to the newly-created OTFMagicBox subdirectory: ``` cd OTFMagicBox @@ -526,38 +565,176 @@ Example: change $(PRODUCT_NAME) to “My Digital App”. ![Alt text](Docs/14-Bundle.png) -## Modify the Style/Design +## Modifying the App's Style + +The appearance of the app is determined by a flexible styling system defined within the AppSysParameters.yml file. This system is based on [CareKit’s custom styling](https://github.com/carekit-apple/CareKit?tab=readme-ov-file#styling). + +It allows you to personalize the app’s style (i.e., theme) according to your preferences, and you can easily switch between different predefined styles. + +### Style Configuration -You can change the tint color, label colors, font type, and size to customize the look of your application. +In the `AppSysParameters.yml` file, you'll discover a list of available styles, each representing a unique visual theme for your app. These styles are referred to as "styles," and they include preset configurations for colors, fonts, and other design elements. -### Colors +#### List of Themes -To customize the colors, please choose the appropriate color codes according to the Human Interface Guidelines from Apple. Refer to [Apple's Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color) for more information. +1. Custom Style + - _Name_: `customStyle` + - _Description_: This style provides a clean and customizable look. Use it as a starting point to create your unique app style. + +2. Health App Style + - _Name_: `healthStyle` + - _Description_: This style provides colors and visuals based on Apple's Health app + +3. CareKit Style Style + - _Name_: `careKitStyle` + - _Description_: A default theme that matches the default CareKit look and feel. It is used as a fallback in case a specific style is not selected. + +#### Selected Style + +The `selectedStyle` field determines the active style. You can switch between styles by updating this field with the desired style name. ```yml # AppSysParameters.yml -designConfig: - # Offset value. - - name: "offset" - textValue: "20" - - # Color codes +# Select the active style +selectedStyle: "customStyle" +``` + +### Creating a New Style + +To create a new style, add a new entry to the styles array with the desired properties. Provide a unique name for the style. + +When picking colors for your custom style, refer to [Apple's Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color) for valid UIKit color values. See: + +1. Semantic UI colors: https://developer.apple.com/documentation/uikit/uicolor/ui_element_colors +2. Adaptable system grey shades: https://developer.apple.com/documentation/uikit/uicolor/standard_colors#3281252 +3. Adaptable system colors: https://developer.apple.com/documentation/uikit/uicolor/standard_colors#3174530 +4. Fixed colors: https://developer.apple.com/documentation/uikit/uicolor/standard_colors#3174519 +5. Adaptable colors in Dark Mode: https://sarunw.com/posts/dark-color-cheat-sheet/#cheat-sheet + +```yml +# AppSysParameters.yml + +# Add a new style entry with a unique name +styles: + - name: "newCustomStyle" + # Background color of the app + backgroundColor: "customBackgroundColor" - # Please choose the colors according to Human Interface Guidelines from Apple. - # Refer here https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color + # Text color used throughout the app + textColor: "customTextColor" - - name: "tintColor" - textValue: "Blue" - - name: "label" - textValue: "Teal" - - name: "secondaryLabel" - textValue: "Brown" - # ... - + # Color of separators between UI elements + separatorColor: "customSeparatorColor" + + # ... (add other properties) +``` + +### Updating Style Properties + +Update the style values to customize its appearance. For example, to update the text color in the "customStyle" theme to green: + +```yml +# AppSysParameters.yml + +# Locate the desired style in the styles array +styles: + - name: "customStyle" + # Update the text color property to "systemGreen" + textColor: "systemGreen" + + # ... (other properties) +``` + +### Automatic Application to Components + +Updating the style values in the selected style section of the YAML file will dynamically reflect on the layout and appearance of various components within the app, including CareKit components, ensuring a consistent and unified visual experience throughout the application. + +For example, if we set the `buttonTextColor` property to `systemRed`, we'll see that the tint and button colors of the app is set to a Red color: + +```yml +# AppSysParameters.yml + +# Locate the selected style in the YAML file +selectedStyle: "customStyle" + +# Update properties within the selected style to customize the appearance +customStyle: + # ... + # Set the text color for buttons to "systemRed" + buttonTextColor: "systemRed" + # ... ``` -### Fonts +| ![Info Card](Docs/93-style-info-card.png) | ![Button Log](Docs/94-style-buttonlog.png) | ![Checklist](Docs/95-style-checklist.png) | ![Numeric Data](Docs/96-style-numeric.png) | +|:-:|:-:|:-:|:-:| + +### Apply Style to New Views + +When creating custom views, you can seamlessly integrate the colors of the current app style by fetching them from the `.otfdsStyle` environment variable. + +For example, if we have the following colors on `customStyle` + +```yml +# AppSysParameters.yml + +# Locate the selected style in the YAML file +selectedStyle: "customStyle" + +# Set specific colors within the selected style to be fetched in views +customStyle: + # Set the text color to "systemGreen" + textColor: "systemGreen" + + # Set the button text color to "systemGreen" + buttonTextColor: "systemGreen" + + # ... (add other properties)ç +``` + +And read them through a View with the `.otfdsStyle` environment variable: + +```swift +struct ContentView: View { + @Environment(\.otfdsStyle) var style: OTFDesignStyler? + + var body: some View { + VStack(spacing: 16) { + Text("Secure your account") + .font(.title) + .foregroundColor(style?.color.label) + Text("Setup two-factor authentication to protect your account and your data") + .foregroundColor(style?.color.secondaryLabel) + + Button("Continue") { + // ... + } + .buttonStyle(.otfPrimary) + .foregroundColor(style?.color.primaryButton) + } + } +} +``` + +The following view would be generated: + + + +Note that attempting to access the current style through the Environment property is not possible outside of a View. To read the style values outside of a View, you can use the `appStyle` property of `YmlReader`: + +```swift +class SecureAccountViewModel { + var appStyle = YmlReader().appStyle + + // ... +} +``` + +### Default Theme + +In case the style under selectedStyle is omitted or fails to be read, the app will gracefully default to a predefined style called careKitStyle. + +## Fonts You can customize the fonts used in your application, including support for the Bold Text accessibility feature. @@ -680,8 +857,7 @@ registration: Go to the Login section in the `ModuleAppSysParameter.yml` file and customize the title and the description. -If you want to use the *Sign up With Google* feature, then change the **showGoogleSignin** key to `true`. Then click on the `Info.plist` file. Xcode will show the contents of the `Info.plist` file as a list of settings (key-value pairs). -Go to the row with the key named “GIDClientID”. Click on the Value column of that row and change the value to the one required by your application which you get from the Google developer portal. Then find the "CFBundleURLSchemes" key in the Info.plist file and add the URLSchemes value, which you can also get from the Google developer portal. Also add the URLSchemes value in the URL Types row as shown in the figure below. +If you want to use the *Sign up With Google* feature, then change the **showGoogleSignin** key to `true`. Then click on the `Info.plist` file. Xcode will show the contents of the `Info.plist` file as a list of settings (key-value pairs). Go to the row with the key named “GIDClientID” Click on the Value column of that row and change the value to your application which you get from the google developer portal. Find the "CFBundleURLSchemes" key in Info.plist file and add the URLSchemes in value you can also get this value from google developer portal. Also add the URLSchemes in URL Types as shown in the figure below. @@ -723,6 +899,30 @@ useCareKit: "true" ``` +## UserInfo Usage + +The Framework `OTFCareKitStore` contains the property *userInfo* in `OCKPatient.swift` class, When you launch the `OTFMagicBox` application you will get a user object of type `OCKPatient` throught which you will able to access the userInfo object and its properties stored in `OTFCareKitStore`. + +You can you *userInfo* object to store your own properties on user level, as an example if you want to store the information of selected theme of application you need to create the `struct` including the property you want to store, assign the data to the property of your `sturct`. As userInfo is a dictunary of type `[String: String]` thats why you need to create a string from for `stuct`, To create string encode your model using `JSONEncoder` that will return `data`, then decode this `data` to string using `UTF8` after that create a key in userInfo and assign that your newely created string to key. + +Then by using shared instance of `CareKitManager` call the method `updatePatient` as and assign the +updated `OCKPatient` object to `updatePatient` method as shown in the example below. + +``` +struct yourStruct { +let isDarkMode: Bool +} +``` + +``` +if let data = try? encoder.encode(your-struct) { + let stingData = String(decoding: data, as: UTF8.self) + user?.userInfo?["Your-Key"] = stingData + CareKitManager.shared.cloudantStore?.updatePatient(user!) +} +``` + + # Registration on Apple Developer Portal If you need to run an application on a physical device (like your personal iPhone) and/or if you need to use TestFlight, then you need to register on the Apple Developer Portal. @@ -731,28 +931,78 @@ Register your project in your Apple developer account by following [these steps] # Register a new API key -- You can register a new API key using this [portal](https://theraforge.org/admin/register). -- You need to add valid details into the given form. After a successful submission, you will be presented with a popup window that will show your registered API key. +- You can register a new API key using this [dashboard](https://stg.theraforge.org/admin/). +- You need to add valid details into the given form. After a successful submission, you will be presented with a popup window that will show your registerd API key. - Make sure to copy that API key and keep it in safe place. -- Once you have registered your API key, our support team will contact you for further assistance. +- Once you have registered your API key, our support team will contact you for further asssistance. - A dashboard (called AdminBox) is used to help clients to access and modify their API keys -- AdminBox can be accessed using the [portal](https://theraforge.org/admin/login). -- Once you log in to the dashboard (as admin), you will be able to see the API key details. +- AdminBox can be accessed using the [Portal](https://stg.theraforge.org/admin/login). +- Once a client is logged in to the dashboard (as admin), he/she will be able to see all API key details based upon their role. - Here are the screenshots for better understanding.

-You can register a new API key using this portal: +Register API key component:

-When a new API key is registered, you can review it and copy it in this popup window: -

-Display API key details: -

+When API key is registered: +

+Showing all API key details to admins: +

# Xcode Setup Set up the Xcode application with your Apple developer account information as [described here](XCODE-SETUP.md). + +# MVVM (Model View ViewModel) Architecture
+ +Whenever we start building a new application, this question always comes in our mind, which architecture pattern to choose for our new project. The most used architectural pattern in iOS is MVC. Most of the developers used the MVC pattern for their projects. Small projects work well with MVC, but when your project size starts increases, it starts making your source code messy. + +I always found the architecture pattern is good to use, but we should not strictly follow an architecture pattern in our project. Not every architecture pattern is good enough to give you everything, there are cons & pros of every architecture pattern. if we have a lot of modules in our project, we can decide the architecture pattern according to the module also. Some module suits well with MVVM, but maybe your new module will not work well with MVVM, so instead use another architecture pattern like MVP, VIPER. So we should not completely rely on a single architecture pattern, instead, we can check it according to the module also. + +So, in OTFMagicBox we are using MVVM as it fullfils all our requirements. +MVVM is the industry-recognized software architecture pattern that overcomes all drawbacks of MVP and MVC design patterns. +MVVM suggests separating the data presentation logic(Views or UI) from the core business logic part of the application. + +## The separate code layers of MVVM + +### 1. Model: +This layer is responsible for the abstraction of the data sources. Model and ViewModel work together to get and save the data. + +### 2. View: +The purpose of this layer is to inform the ViewModel about the user’s action. This layer observes the ViewModel and does not contain any kind of application logic. + +### 3. ViewModel: + It exposes those data streams which are relevant to the View. Moreover, it serves as a link between the Model and the View. + + Some impotent role played by MVVM. + +* ViewModel does not hold any kind of reference to the View. +* Many to-1 relationships exist between View and ViewModel. +* No triggering methods to update the View. + +For better understanding of MVVM architecture view [This Article](https://www.toptal.com/ios/swift-tutorial-introduction-to-mvvm) + +## Ways to Implement MVVM in the Project + +Recommended ways to implement MVVM design pattern in iOS projects: + +* Using RxJava for DataBinding. +* Using combine framework for DataBinding. + +# Combine Framework + +The Combine framework provides a declarative Swift API for processing values over time. These values can represent many kinds of asynchronous events. Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers. + +If you are using swiftUI than it is recommended to use combine framework. + +Here are some link to understand and learn how to use combine framework. + +The [Official Documentation](https://developer.apple.com/documentation/combine/receiving-and-handling-events-with-combine) to understand the combine. + +Also view [This Article](https://medium.com/apple-developer-academy-federico-ii/combine-and-swiftui-9888f7b111bf) for basic understanding of combine framework. + + # CI/CD Setup Configure your project using a CI and CD pipeline via GitHub Actions as [described here](/.github/CICD.md).