mirror of
https://github.com/AU-COVIDSafe/mobile-ios.git
synced 2025-01-18 16:56:33 +00:00
COVIDSafe code from version 1.4 (#3)
This commit is contained in:
parent
56c93f2079
commit
b2e0c5b34c
33 changed files with 6865 additions and 481 deletions
|
@ -36,8 +36,9 @@
|
|||
30BE1CB523F15D47005DCE4F /* OTPViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BE1CB423F15D47005DCE4F /* OTPViewController.swift */; };
|
||||
30E91BE923EFE514002D592A /* UploadDataVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E91BE823EFE514002D592A /* UploadDataVC.swift */; };
|
||||
30E91BEB23EFEA0B002D592A /* CodeInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E91BEA23EFEA0B002D592A /* CodeInputView.swift */; };
|
||||
30FADDAE23F6896C006C125F /* Encounter+Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FADDAD23F6896C006C125F /* Encounter+Event.swift */; };
|
||||
469DD4CFF262D29768A8CBEF /* Pods_CovidSafe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BE2A0527997C5042B9E2A41 /* Pods_CovidSafe.framework */; };
|
||||
3A8951FDED310D7ABA54259E /* Pods_CovidSafe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34E9EB96EA6E42A571E73C8E /* Pods_CovidSafe.framework */; };
|
||||
5904A5C22462471A008C8012 /* EncounterV1toV2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 5904A5C12462471A008C8012 /* EncounterV1toV2.xcmappingmodel */; };
|
||||
5904A5C32462471A008C8012 /* EncounterV1toV2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 5904A5C12462471A008C8012 /* EncounterV1toV2.xcmappingmodel */; };
|
||||
590888AF2431B9E3008C9B9F /* UITextView + Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B55E1912430760500C9E798 /* UITextView + Extensions.swift */; };
|
||||
590888B02431B9E7008C9B9F /* UIColor + Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BC141AD2430685800399FA8 /* UIColor + Extensions.swift */; };
|
||||
590888B12431B9EB008C9B9F /* Question3ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B86119424303F5E00EA4B6B /* Question3ViewController.swift */; };
|
||||
|
@ -52,13 +53,27 @@
|
|||
590C99332432C1C400A5EC71 /* UploadDataHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B69E7E82430C22E00561DD9 /* UploadDataHomeViewController.swift */; };
|
||||
592CBB802441A583001FFCE9 /* PersonalDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 592CBB7F2441A583001FFCE9 /* PersonalDetailsViewController.swift */; };
|
||||
592CBB812441A583001FFCE9 /* PersonalDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 592CBB7F2441A583001FFCE9 /* PersonalDetailsViewController.swift */; };
|
||||
59490B64245FE3DA00C9802B /* EncounterV2Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59490B63245FE3DA00C9802B /* EncounterV2Mapping.swift */; };
|
||||
59490B65245FE3DA00C9802B /* EncounterV2Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59490B63245FE3DA00C9802B /* EncounterV2Mapping.swift */; };
|
||||
594E77BF24736B77009B8B34 /* EncounterDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 594E77BE24736B77009B8B34 /* EncounterDB.swift */; };
|
||||
594E77C024736B77009B8B34 /* EncounterDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 594E77BE24736B77009B8B34 /* EncounterDB.swift */; };
|
||||
594E77C2247387B1009B8B34 /* EncounterDB+migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 594E77C1247387B1009B8B34 /* EncounterDB+migration.swift */; };
|
||||
594E77C3247387B1009B8B34 /* EncounterDB+migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 594E77C1247387B1009B8B34 /* EncounterDB+migration.swift */; };
|
||||
5956CD8F246D44EA00EA4D4A /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5956CD8E246D44EA00EA4D4A /* CoreBluetooth.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
5956CD90246D44F100EA4D4A /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5956CD8E246D44EA00EA4D4A /* CoreBluetooth.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
5957EB67244E936E002F5388 /* UnderSixteenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B7ABF27244D6BE100BB249B /* UnderSixteenViewController.swift */; };
|
||||
5961ABEA2474E358004040DF /* MigrationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5961ABE92474E358004040DF /* MigrationViewController.swift */; };
|
||||
5961ABEB2474E358004040DF /* MigrationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5961ABE92474E358004040DF /* MigrationViewController.swift */; };
|
||||
5961ABED2474E464004040DF /* spinner_migrating_db.json in Resources */ = {isa = PBXBuildFile; fileRef = 5961ABEC2474E464004040DF /* spinner_migrating_db.json */; };
|
||||
5961ABEE2474E464004040DF /* spinner_migrating_db.json in Resources */ = {isa = PBXBuildFile; fileRef = 5961ABEC2474E464004040DF /* spinner_migrating_db.json */; };
|
||||
596B189924496D32003E190F /* Encounter+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596B189824496D32003E190F /* Encounter+Util.swift */; };
|
||||
596B189A24496D32003E190F /* Encounter+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596B189824496D32003E190F /* Encounter+Util.swift */; };
|
||||
596B189C24499591003E190F /* UploadHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596B189B24499591003E190F /* UploadHelper.swift */; };
|
||||
596B189D24499591003E190F /* UploadHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596B189B24499591003E190F /* UploadHelper.swift */; };
|
||||
597BB7CC245FAEC00067A2E2 /* SecKey+CovidSafe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 597BB7CB245FAEC00067A2E2 /* SecKey+CovidSafe.swift */; };
|
||||
597BB7CD245FAEC00067A2E2 /* SecKey+CovidSafe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 597BB7CB245FAEC00067A2E2 /* SecKey+CovidSafe.swift */; };
|
||||
597BB7CF245FB1250067A2E2 /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 597BB7CE245FB1250067A2E2 /* Crypto.swift */; };
|
||||
597BB7D0245FB1250067A2E2 /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 597BB7CE245FB1250067A2E2 /* Crypto.swift */; };
|
||||
59898603245173C200966E61 /* URLHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59898602245173C200966E61 /* URLHelper.swift */; };
|
||||
59898604245173C200966E61 /* URLHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59898602245173C200966E61 /* URLHelper.swift */; };
|
||||
59ACB574242F195A00E63E3C /* InitiateUploadAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59ACB573242F195A00E63E3C /* InitiateUploadAPI.swift */; };
|
||||
|
@ -73,8 +88,6 @@
|
|||
59B7417124514126006E1EEA /* RegistrationConsentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59B7416F24514126006E1EEA /* RegistrationConsentViewController.swift */; };
|
||||
59F25D69245B917A002A7ED8 /* Spinner_home.json in Resources */ = {isa = PBXBuildFile; fileRef = 59F25D68245B917A002A7ED8 /* Spinner_home.json */; };
|
||||
59F25D6A245B917A002A7ED8 /* Spinner_home.json in Resources */ = {isa = PBXBuildFile; fileRef = 59F25D68245B917A002A7ED8 /* Spinner_home.json */; };
|
||||
59F25D6C245BBCA2002A7ED8 /* Spinner_home_upload_complete.json in Resources */ = {isa = PBXBuildFile; fileRef = 59F25D6B245BBCA2002A7ED8 /* Spinner_home_upload_complete.json */; };
|
||||
59F25D6D245BBCA2002A7ED8 /* Spinner_home_upload_complete.json in Resources */ = {isa = PBXBuildFile; fileRef = 59F25D6B245BBCA2002A7ED8 /* Spinner_home_upload_complete.json */; };
|
||||
59F25D6F245BED80002A7ED8 /* Debug.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 59F25D6E245BED80002A7ED8 /* Debug.storyboard */; };
|
||||
5B337AAB245A9BBC00537620 /* UploadDataErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B337AAA245A9BBC00537620 /* UploadDataErrorViewController.swift */; };
|
||||
5B337AAC245A9EEC00537620 /* UploadDataPrefaceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B577814245A584C0088F111 /* UploadDataPrefaceViewController.swift */; };
|
||||
|
@ -96,11 +109,9 @@
|
|||
5B92D674243018040049877B /* BluetraceConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DC7B8D0242B8536008E1715 /* BluetraceConfig.swift */; };
|
||||
5B92D675243018040049877B /* IssueInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A767D300242DF1B000DC9E2A /* IssueInfo.swift */; };
|
||||
5B92D676243018040049877B /* ADGColorPallete.swift in Sources */ = {isa = PBXBuildFile; fileRef = A767D30A242DF1B000DC9E2A /* ADGColorPallete.swift */; };
|
||||
5B92D677243018040049877B /* Encounter+Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FADDAD23F6896C006C125F /* Encounter+Event.swift */; };
|
||||
5B92D678243018040049877B /* UIKitExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A767D2FC242DF1B000DC9E2A /* UIKitExtensions.swift */; };
|
||||
5B92D679243018040049877B /* InitialScreenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FACD53923F25A9A0042A33A /* InitialScreenViewController.swift */; };
|
||||
5B92D67A243018040049877B /* ContactViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D8DD05923E2F08400E097EF /* ContactViewController.swift */; };
|
||||
5B92D67B243018040049877B /* OnboardingStep2cViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C58D817823F16C3900345771 /* OnboardingStep2cViewController.swift */; };
|
||||
5B92D67C243018040049877B /* LogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D8DD05B23E2F0A700E097EF /* LogViewController.swift */; };
|
||||
5B92D67D243018040049877B /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D5F83AF23F045A800770DEF /* HomeViewController.swift */; };
|
||||
5B92D67E243018040049877B /* InfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D8DD05D23E2F0BA00E097EF /* InfoViewController.swift */; };
|
||||
|
@ -188,7 +199,6 @@
|
|||
5DD41D4723DCB03D00FD4AB0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5DD41D4523DCB03D00FD4AB0 /* LaunchScreen.storyboard */; };
|
||||
5DD41D4F23DCB05600FD4AB0 /* CentralController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DD41D4E23DCB05600FD4AB0 /* CentralController.swift */; };
|
||||
5DD41D5323DD4CA400FD4AB0 /* PeripheralController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DD41D5223DD4CA400FD4AB0 /* PeripheralController.swift */; };
|
||||
7AB66BCCCA27E969EE126F9F /* Pods_CovidSafe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BE2A0527997C5042B9E2A41 /* Pods_CovidSafe.framework */; };
|
||||
7F19B4DD23F565850071A11E /* PogoInstructionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F19B4DC23F565850071A11E /* PogoInstructionsViewController.swift */; };
|
||||
7F2F0BA223EFFF75006D7404 /* OnboardingStep2ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F2F0BA123EFFF75006D7404 /* OnboardingStep2ViewController.swift */; };
|
||||
7F36305F23F7F81400CC6E1D /* PushNotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F36305E23F7F81400CC6E1D /* PushNotificationConstants.swift */; };
|
||||
|
@ -223,7 +233,6 @@
|
|||
A767D334242DF1B100DC9E2A /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = A767D309242DF1B000DC9E2A /* Action.swift */; };
|
||||
A767D335242DF1B100DC9E2A /* ADGColorPallete.swift in Sources */ = {isa = PBXBuildFile; fileRef = A767D30A242DF1B000DC9E2A /* ADGColorPallete.swift */; };
|
||||
A767D336242DF1B100DC9E2A /* GetJMCTargetAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A767D30B242DF1B000DC9E2A /* GetJMCTargetAction.swift */; };
|
||||
AC1B51D6C926C60CCC1FB565 /* Pods_CovidSafe_staging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0A3F236B583DE5A31A50F1F /* Pods_CovidSafe_staging.framework */; };
|
||||
B605A7B12427429D008BA819 /* PlistHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B605A7B02427429D008BA819 /* PlistHelper.swift */; };
|
||||
B60F8BE4242659810007A641 /* UILabelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60F8BE3242659810007A641 /* UILabelExtension.swift */; };
|
||||
B615C5A723F8EB1700345969 /* UIProgressView + Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B615C5A623F8EB1700345969 /* UIProgressView + Extension.swift */; };
|
||||
|
@ -233,11 +242,11 @@
|
|||
C56CF43F23F18A15006B05B0 /* OnboardingStep4ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56CF43E23F18A15006B05B0 /* OnboardingStep4ViewController.swift */; };
|
||||
C585C83B23EEB99B0061B7C6 /* GradientButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C585C83A23EEB99B0061B7C6 /* GradientButton.swift */; };
|
||||
C58D817723F169DB00345771 /* OnboardingStep2bViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C58D817623F169DB00345771 /* OnboardingStep2bViewController.swift */; };
|
||||
C58D817923F16C3900345771 /* OnboardingStep2cViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C58D817823F16C3900345771 /* OnboardingStep2cViewController.swift */; };
|
||||
C5D209FC23F4476F007233BE /* UITextViewFixed.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5D209FB23F4476F007233BE /* UITextViewFixed.swift */; };
|
||||
D8DEB6822423AE2E00D99925 /* OnboardingStep1bViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8DEB6812423AE2E00D99925 /* OnboardingStep1bViewController.swift */; };
|
||||
D8EB201B23FA722D001C60EC /* HelpNavController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8EB201A23FA722D001C60EC /* HelpNavController.swift */; };
|
||||
D8EB201D23FBE216001C60EC /* help_center_article_style.css in Resources */ = {isa = PBXBuildFile; fileRef = D8EB201C23FBE216001C60EC /* help_center_article_style.css */; };
|
||||
F4992D5F7DAE4B13FF4BB47D /* Pods_CovidSafe_staging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFB86126400FA51506E1B416 /* Pods_CovidSafe_staging.framework */; };
|
||||
FB12C4C1242F0480007E893B /* RespondToAuthChallengeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB12C4C0242F047F007E893B /* RespondToAuthChallengeAPI.swift */; };
|
||||
FB12C4C3242F0FE9007E893B /* GetTempIdAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB12C4C2242F0FE9007E893B /* GetTempIdAPI.swift */; };
|
||||
FB12C4C524304AF0007E893B /* OnboardingStep1aViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB12C4C424304AF0007E893B /* OnboardingStep1aViewController.swift */; };
|
||||
|
@ -245,6 +254,7 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
03E2D9045555F5F013130375 /* Pods-CovidSafe.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe.release.xcconfig"; path = "Target Support Files/Pods-CovidSafe/Pods-CovidSafe.release.xcconfig"; sourceTree = "<group>"; };
|
||||
0B1810112431EE610005D11F /* PhoneNumberParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneNumberParser.swift; sourceTree = "<group>"; };
|
||||
0B22A56A242F286900D1FE60 /* UINavigationBar+Style.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationBar+Style.swift"; sourceTree = "<group>"; };
|
||||
0B55E1912430760500C9E798 /* UITextView + Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView + Extensions.swift"; sourceTree = "<group>"; };
|
||||
|
@ -255,6 +265,7 @@
|
|||
0BC141AB24305D9C00399FA8 /* NSMutableString + Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableString + Extensions.swift"; sourceTree = "<group>"; };
|
||||
0BC141AD2430685800399FA8 /* UIColor + Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor + Extensions.swift"; sourceTree = "<group>"; };
|
||||
122AF4E79D17C983066C1CEB /* Pods-CovidSafe-staging.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe-staging.release.xcconfig"; path = "Target Support Files/Pods-CovidSafe-staging/Pods-CovidSafe-staging.release.xcconfig"; sourceTree = "<group>"; };
|
||||
1925EA5F4413AD52AC198894 /* Pods-CovidSafe.covid-production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe.covid-production.xcconfig"; path = "Target Support Files/Pods-CovidSafe/Pods-CovidSafe.covid-production.xcconfig"; sourceTree = "<group>"; };
|
||||
1B86118D24303E7D00EA4B6B /* Questions.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Questions.storyboard; sourceTree = "<group>"; };
|
||||
1B86119024303EF200EA4B6B /* Question1ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Question1ViewController.swift; sourceTree = "<group>"; };
|
||||
1B86119224303F4A00EA4B6B /* Question2ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Question2ViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -264,6 +275,7 @@
|
|||
1B86119A24303FA200EA4B6B /* Question3ErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Question3ErrorViewController.swift; sourceTree = "<group>"; };
|
||||
1B86119C24303FC000EA4B6B /* QuestionUploadDataViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionUploadDataViewController.swift; sourceTree = "<group>"; };
|
||||
20A0AADA27329C83CFAB5A7C /* Pods-CovidSafe.covid-staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe.covid-staging.xcconfig"; path = "Target Support Files/Pods-CovidSafe/Pods-CovidSafe.covid-staging.xcconfig"; sourceTree = "<group>"; };
|
||||
2B916D8946F8A94E32E569C7 /* Pods-CovidSafe.covid-staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe.covid-staging.xcconfig"; path = "Target Support Files/Pods-CovidSafe/Pods-CovidSafe.covid-staging.xcconfig"; sourceTree = "<group>"; };
|
||||
30BE1CA923F108BA005DCE4F /* UploadFileData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadFileData.swift; sourceTree = "<group>"; };
|
||||
30BE1CAC23F119FD005DCE4F /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
30BE1CAE23F1349F005DCE4F /* EncounterRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncounterRecord.swift; sourceTree = "<group>"; };
|
||||
|
@ -271,15 +283,27 @@
|
|||
30BE1CB423F15D47005DCE4F /* OTPViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTPViewController.swift; sourceTree = "<group>"; };
|
||||
30E91BE823EFE514002D592A /* UploadDataVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadDataVC.swift; sourceTree = "<group>"; };
|
||||
30E91BEA23EFEA0B002D592A /* CodeInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeInputView.swift; sourceTree = "<group>"; };
|
||||
30FADDAD23F6896C006C125F /* Encounter+Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encounter+Event.swift"; sourceTree = "<group>"; };
|
||||
342FF717762F714E56F4412D /* Pods-CovidSafe.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe.release.xcconfig"; path = "Target Support Files/Pods-CovidSafe/Pods-CovidSafe.release.xcconfig"; sourceTree = "<group>"; };
|
||||
34E9EB96EA6E42A571E73C8E /* Pods_CovidSafe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CovidSafe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
39E21BD3842669F051A5D6D8 /* Pods-CovidSafe.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe.debug.xcconfig"; path = "Target Support Files/Pods-CovidSafe/Pods-CovidSafe.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
3A403F07F3B7C5A94CBFC43D /* Pods-CovidSafe-staging.covid-staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe-staging.covid-staging.xcconfig"; path = "Target Support Files/Pods-CovidSafe-staging/Pods-CovidSafe-staging.covid-staging.xcconfig"; sourceTree = "<group>"; };
|
||||
46A5730925DA6B664DFE9546 /* Pods-CovidSafe-staging.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe-staging.debug.xcconfig"; path = "Target Support Files/Pods-CovidSafe-staging/Pods-CovidSafe-staging.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
46D0C3F015CA753BB4D4787D /* Pods-CovidSafe-staging.covid-production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe-staging.covid-production.xcconfig"; path = "Target Support Files/Pods-CovidSafe-staging/Pods-CovidSafe-staging.covid-production.xcconfig"; sourceTree = "<group>"; };
|
||||
49A22E09D113DF058C94C6E6 /* Pods-CovidSafe-staging.covid-staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe-staging.covid-staging.xcconfig"; path = "Target Support Files/Pods-CovidSafe-staging/Pods-CovidSafe-staging.covid-staging.xcconfig"; sourceTree = "<group>"; };
|
||||
5904A5C12462471A008C8012 /* EncounterV1toV2.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = EncounterV1toV2.xcmappingmodel; sourceTree = "<group>"; };
|
||||
5909E4AA245043C400D41C26 /* CovidPersistentContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CovidPersistentContainer.swift; sourceTree = "<group>"; };
|
||||
592CBB7F2441A583001FFCE9 /* PersonalDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalDetailsViewController.swift; sourceTree = "<group>"; };
|
||||
59490B61245FE22C00C9802B /* ModelV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = ModelV2.xcdatamodel; sourceTree = "<group>"; };
|
||||
59490B63245FE3DA00C9802B /* EncounterV2Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncounterV2Mapping.swift; sourceTree = "<group>"; };
|
||||
594E77BE24736B77009B8B34 /* EncounterDB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncounterDB.swift; sourceTree = "<group>"; };
|
||||
594E77C1247387B1009B8B34 /* EncounterDB+migration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EncounterDB+migration.swift"; sourceTree = "<group>"; };
|
||||
5956CD8E246D44EA00EA4D4A /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
|
||||
5961ABE92474E358004040DF /* MigrationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationViewController.swift; sourceTree = "<group>"; };
|
||||
5961ABEC2474E464004040DF /* spinner_migrating_db.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = spinner_migrating_db.json; sourceTree = "<group>"; };
|
||||
596B189824496D32003E190F /* Encounter+Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encounter+Util.swift"; sourceTree = "<group>"; };
|
||||
596B189B24499591003E190F /* UploadHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadHelper.swift; sourceTree = "<group>"; };
|
||||
597BB7CB245FAEC00067A2E2 /* SecKey+CovidSafe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SecKey+CovidSafe.swift"; sourceTree = "<group>"; };
|
||||
597BB7CE245FB1250067A2E2 /* Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Crypto.swift; sourceTree = "<group>"; };
|
||||
59898602245173C200966E61 /* URLHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLHelper.swift; sourceTree = "<group>"; };
|
||||
59ACB573242F195A00E63E3C /* InitiateUploadAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitiateUploadAPI.swift; sourceTree = "<group>"; };
|
||||
59ACB575242F404500E63E3C /* DataUploadS3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataUploadS3.swift; sourceTree = "<group>"; };
|
||||
|
@ -288,7 +312,6 @@
|
|||
59AF2EB12435A38100ACCAF2 /* CovidRequestRetrier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CovidRequestRetrier.swift; sourceTree = "<group>"; };
|
||||
59B7416F24514126006E1EEA /* RegistrationConsentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationConsentViewController.swift; sourceTree = "<group>"; };
|
||||
59F25D68245B917A002A7ED8 /* Spinner_home.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Spinner_home.json; sourceTree = "<group>"; };
|
||||
59F25D6B245BBCA2002A7ED8 /* Spinner_home_upload_complete.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Spinner_home_upload_complete.json; sourceTree = "<group>"; };
|
||||
59F25D6E245BED80002A7ED8 /* Debug.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Debug.storyboard; sourceTree = "<group>"; };
|
||||
5B337AAA245A9BBC00537620 /* UploadDataErrorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadDataErrorViewController.swift; sourceTree = "<group>"; };
|
||||
5B337AAE245AA26300537620 /* Spinner_upload.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Spinner_upload.json; sourceTree = "<group>"; };
|
||||
|
@ -299,7 +322,6 @@
|
|||
5B92D666243012330049877B /* CovidSafe-config.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "CovidSafe-config.plist"; path = "Resources/STG/CovidSafe-config.plist"; sourceTree = "<group>"; };
|
||||
5B92D6D9243018040049877B /* COVIDSafe-staging.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "COVIDSafe-staging.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5BD3EE8224330E1A0004A007 /* UploadDataStep2VC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadDataStep2VC.swift; sourceTree = "<group>"; };
|
||||
5BE2A0527997C5042B9E2A41 /* Pods_CovidSafe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CovidSafe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5BFFD94A242EC120003AEF4F /* PhoneValidationAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneValidationAPI.swift; sourceTree = "<group>"; };
|
||||
5D269C0A23E22CC400ADF2DE /* DeviceIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceIdentifier.swift; sourceTree = "<group>"; };
|
||||
5D269C0C23E2958F00ADF2DE /* BluetraceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetraceManager.swift; sourceTree = "<group>"; };
|
||||
|
@ -331,6 +353,7 @@
|
|||
7FACD53923F25A9A0042A33A /* InitialScreenViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialScreenViewController.swift; sourceTree = "<group>"; };
|
||||
7FEC361423F16A1E00127AFB /* UIViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewExtension.swift; sourceTree = "<group>"; };
|
||||
7FF75C212429FEE800C11FEA /* CountriesData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountriesData.swift; sourceTree = "<group>"; };
|
||||
81B28CDCE1F29BA0F1D30CCE /* Pods-CovidSafe-staging.covid-production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe-staging.covid-production.xcconfig"; path = "Target Support Files/Pods-CovidSafe-staging/Pods-CovidSafe-staging.covid-production.xcconfig"; sourceTree = "<group>"; };
|
||||
A767D2B6242DF1B000DC9E2A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Feedback.strings; sourceTree = "<group>"; };
|
||||
A767D2B7242DF1B000DC9E2A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/NewFeedbackFlow.strings; sourceTree = "<group>"; };
|
||||
A767D2D1242DF1B000DC9E2A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/NewFeedbackFlow.storyboard; sourceTree = "<group>"; };
|
||||
|
@ -369,9 +392,7 @@
|
|||
C56CF43E23F18A15006B05B0 /* OnboardingStep4ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingStep4ViewController.swift; sourceTree = "<group>"; };
|
||||
C585C83A23EEB99B0061B7C6 /* GradientButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientButton.swift; sourceTree = "<group>"; };
|
||||
C58D817623F169DB00345771 /* OnboardingStep2bViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingStep2bViewController.swift; sourceTree = "<group>"; };
|
||||
C58D817823F16C3900345771 /* OnboardingStep2cViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingStep2cViewController.swift; sourceTree = "<group>"; };
|
||||
C5D209FB23F4476F007233BE /* UITextViewFixed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITextViewFixed.swift; sourceTree = "<group>"; };
|
||||
D0A3F236B583DE5A31A50F1F /* Pods_CovidSafe_staging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CovidSafe_staging.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D8DEB6812423AE2E00D99925 /* OnboardingStep1bViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingStep1bViewController.swift; sourceTree = "<group>"; };
|
||||
D8EB201A23FA722D001C60EC /* HelpNavController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpNavController.swift; sourceTree = "<group>"; };
|
||||
D8EB201C23FBE216001C60EC /* help_center_article_style.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = help_center_article_style.css; sourceTree = "<group>"; };
|
||||
|
@ -380,6 +401,8 @@
|
|||
FB12C4C0242F047F007E893B /* RespondToAuthChallengeAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RespondToAuthChallengeAPI.swift; sourceTree = "<group>"; };
|
||||
FB12C4C2242F0FE9007E893B /* GetTempIdAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetTempIdAPI.swift; sourceTree = "<group>"; };
|
||||
FB12C4C424304AF0007E893B /* OnboardingStep1aViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingStep1aViewController.swift; sourceTree = "<group>"; };
|
||||
FB81BAD81D73C6FD42202A04 /* Pods-CovidSafe-staging.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe-staging.release.xcconfig"; path = "Target Support Files/Pods-CovidSafe-staging/Pods-CovidSafe-staging.release.xcconfig"; sourceTree = "<group>"; };
|
||||
FFB86126400FA51506E1B416 /* Pods_CovidSafe_staging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CovidSafe_staging.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -388,7 +411,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5956CD8F246D44EA00EA4D4A /* CoreBluetooth.framework in Frameworks */,
|
||||
AC1B51D6C926C60CCC1FB565 /* Pods_CovidCare_staging.framework in Frameworks */,
|
||||
F4992D5F7DAE4B13FF4BB47D /* Pods_CovidSafe_staging.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -397,8 +420,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5956CD90246D44F100EA4D4A /* CoreBluetooth.framework in Frameworks */,
|
||||
469DD4CFF262D29768A8CBEF /* Pods_CovidCare.framework in Frameworks */,
|
||||
7AB66BCCCA27E969EE126F9F /* Pods_CovidCare.framework in Frameworks */,
|
||||
3A8951FDED310D7ABA54259E /* Pods_CovidSafe.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -432,9 +454,9 @@
|
|||
30BE1CB223F13B26005DCE4F /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59490B62245FE3BD00C9802B /* V2 */,
|
||||
5D8DD05F23E319B300E097EF /* Encounter+CoreDataClass.swift */,
|
||||
5D8DD06023E319B300E097EF /* Encounter+CoreDataProperties.swift */,
|
||||
30FADDAD23F6896C006C125F /* Encounter+Event.swift */,
|
||||
596B189824496D32003E190F /* Encounter+Util.swift */,
|
||||
);
|
||||
name = Models;
|
||||
|
@ -449,7 +471,6 @@
|
|||
FB12C4C424304AF0007E893B /* OnboardingStep1aViewController.swift */,
|
||||
7F2F0BA123EFFF75006D7404 /* OnboardingStep2ViewController.swift */,
|
||||
C58D817623F169DB00345771 /* OnboardingStep2bViewController.swift */,
|
||||
C58D817823F16C3900345771 /* OnboardingStep2cViewController.swift */,
|
||||
C56CF43E23F18A15006B05B0 /* OnboardingStep4ViewController.swift */,
|
||||
5D8DD05923E2F08400E097EF /* ContactViewController.swift */,
|
||||
5D8DD05B23E2F0A700E097EF /* LogViewController.swift */,
|
||||
|
@ -465,6 +486,7 @@
|
|||
5B7ABF24244D3BC600BB249B /* IsolationSuccessViewController.swift */,
|
||||
5B7ABF27244D6BE100BB249B /* UnderSixteenViewController.swift */,
|
||||
59B7416F24514126006E1EEA /* RegistrationConsentViewController.swift */,
|
||||
5961ABE92474E358004040DF /* MigrationViewController.swift */,
|
||||
);
|
||||
name = "View Controllers";
|
||||
sourceTree = "<group>";
|
||||
|
@ -510,20 +532,40 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
5909E4AA245043C400D41C26 /* CovidPersistentContainer.swift */,
|
||||
594E77BE24736B77009B8B34 /* EncounterDB.swift */,
|
||||
594E77C1247387B1009B8B34 /* EncounterDB+migration.swift */,
|
||||
);
|
||||
name = CoreData;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
59490B62245FE3BD00C9802B /* V2 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59490B63245FE3DA00C9802B /* EncounterV2Mapping.swift */,
|
||||
5904A5C12462471A008C8012 /* EncounterV1toV2.xcmappingmodel */,
|
||||
);
|
||||
name = V2;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5949DC522434859600AE76BC /* lottie */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5961ABEC2474E464004040DF /* spinner_migrating_db.json */,
|
||||
5B337AAE245AA26300537620 /* Spinner_upload.json */,
|
||||
59F25D68245B917A002A7ED8 /* Spinner_home.json */,
|
||||
59F25D6B245BBCA2002A7ED8 /* Spinner_home_upload_complete.json */,
|
||||
);
|
||||
name = lottie;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
597BB7CA245FACE20067A2E2 /* Crypto */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
597BB7CB245FAEC00067A2E2 /* SecKey+CovidSafe.swift */,
|
||||
597BB7CE245FB1250067A2E2 /* Crypto.swift */,
|
||||
);
|
||||
name = Crypto;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
59AF2E97243552FB00ACCAF2 /* Certificates */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -603,6 +645,7 @@
|
|||
5DD41D3923DCB03B00FD4AB0 /* CovidSafe */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
597BB7CA245FACE20067A2E2 /* Crypto */,
|
||||
5949DC522434859600AE76BC /* lottie */,
|
||||
5B92D661243005B10049877B /* Resources */,
|
||||
A767D2AE242DF1B000DC9E2A /* Feedback */,
|
||||
|
@ -700,8 +743,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
5956CD8E246D44EA00EA4D4A /* CoreBluetooth.framework */,
|
||||
5BE2A0527997C5042B9E2A41 /* Pods_CovidCare.framework */,
|
||||
D0A3F236B583DE5A31A50F1F /* Pods_CovidCare_staging.framework */,
|
||||
34E9EB96EA6E42A571E73C8E /* Pods_CovidSafe.framework */,
|
||||
FFB86126400FA51506E1B416 /* Pods_CovidSafe_staging.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
@ -732,6 +775,14 @@
|
|||
342FF717762F714E56F4412D /* Pods-CovidSafe.release.xcconfig */,
|
||||
E3B9CCF78D93EFF0EF2A0ADB /* Pods-CovidSafe-staging.debug.xcconfig */,
|
||||
122AF4E79D17C983066C1CEB /* Pods-CovidSafe-staging.release.xcconfig */,
|
||||
39E21BD3842669F051A5D6D8 /* Pods-CovidSafe.debug.xcconfig */,
|
||||
2B916D8946F8A94E32E569C7 /* Pods-CovidSafe.covid-staging.xcconfig */,
|
||||
03E2D9045555F5F013130375 /* Pods-CovidSafe.release.xcconfig */,
|
||||
1925EA5F4413AD52AC198894 /* Pods-CovidSafe.covid-production.xcconfig */,
|
||||
46A5730925DA6B664DFE9546 /* Pods-CovidSafe-staging.debug.xcconfig */,
|
||||
49A22E09D113DF058C94C6E6 /* Pods-CovidSafe-staging.covid-staging.xcconfig */,
|
||||
FB81BAD81D73C6FD42202A04 /* Pods-CovidSafe-staging.release.xcconfig */,
|
||||
81B28CDCE1F29BA0F1D30CCE /* Pods-CovidSafe-staging.covid-production.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
|
@ -868,10 +919,11 @@
|
|||
5B92D6C2243018040049877B /* Localizable.strings in Resources */,
|
||||
5B92D6C7243018040049877B /* CovidSafe-config.plist in Resources */,
|
||||
5B92D6C8243018040049877B /* NewFeedbackFlow.strings in Resources */,
|
||||
5961ABEE2474E464004040DF /* spinner_migrating_db.json in Resources */,
|
||||
59AF2EAD2435801400ACCAF2 /* AmazonRootCA4.cer in Resources */,
|
||||
59F25D6F245BED80002A7ED8 /* Debug.storyboard in Resources */,
|
||||
5B92D6C9243018040049877B /* LaunchScreen.storyboard in Resources */,
|
||||
5B92D6CB243018040049877B /* Assets.xcassets in Resources */,
|
||||
59F25D6D245BBCA2002A7ED8 /* Spinner_home_upload_complete.json in Resources */,
|
||||
5B92D6CC243018040049877B /* Feedback.strings in Resources */,
|
||||
5B337AB0245AA26300537620 /* Spinner_upload.json in Resources */,
|
||||
5B92D6CF243018040049877B /* Main.storyboard in Resources */,
|
||||
|
@ -893,9 +945,10 @@
|
|||
A767D30F242DF1B000DC9E2A /* NewFeedbackFlow.strings in Resources */,
|
||||
5DD41D4723DCB03D00FD4AB0 /* LaunchScreen.storyboard in Resources */,
|
||||
5DD41D4423DCB03D00FD4AB0 /* Assets.xcassets in Resources */,
|
||||
59F25D6C245BBCA2002A7ED8 /* Spinner_home_upload_complete.json in Resources */,
|
||||
A767D30E242DF1B000DC9E2A /* Feedback.strings in Resources */,
|
||||
5B337AAF245AA26300537620 /* Spinner_upload.json in Resources */,
|
||||
59AF2EAA2435801400ACCAF2 /* AmazonRootCA3.cer in Resources */,
|
||||
5961ABED2474E464004040DF /* spinner_migrating_db.json in Resources */,
|
||||
5DD41D4223DCB03B00FD4AB0 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -998,16 +1051,16 @@
|
|||
5B92D674243018040049877B /* BluetraceConfig.swift in Sources */,
|
||||
5B92D675243018040049877B /* IssueInfo.swift in Sources */,
|
||||
5B92D676243018040049877B /* ADGColorPallete.swift in Sources */,
|
||||
5B92D677243018040049877B /* Encounter+Event.swift in Sources */,
|
||||
5B92D678243018040049877B /* UIKitExtensions.swift in Sources */,
|
||||
5B92D679243018040049877B /* InitialScreenViewController.swift in Sources */,
|
||||
59490B65245FE3DA00C9802B /* EncounterV2Mapping.swift in Sources */,
|
||||
5B92D67A243018040049877B /* ContactViewController.swift in Sources */,
|
||||
5B92D67B243018040049877B /* OnboardingStep2cViewController.swift in Sources */,
|
||||
5B92D67C243018040049877B /* LogViewController.swift in Sources */,
|
||||
5B92D67D243018040049877B /* HomeViewController.swift in Sources */,
|
||||
5B92D67E243018040049877B /* InfoViewController.swift in Sources */,
|
||||
5B92D67F243018040049877B /* PogoInstructionsViewController.swift in Sources */,
|
||||
FBBBFCE82430A933002B174D /* OnboardingStep1aViewController.swift in Sources */,
|
||||
594E77C3247387B1009B8B34 /* EncounterDB+migration.swift in Sources */,
|
||||
590C99332432C1C400A5EC71 /* UploadDataHomeViewController.swift in Sources */,
|
||||
59B7417124514126006E1EEA /* RegistrationConsentViewController.swift in Sources */,
|
||||
5B92D680243018040049877B /* CodeInputView.swift in Sources */,
|
||||
|
@ -1020,11 +1073,13 @@
|
|||
5B92D685243018040049877B /* UILabelExtension.swift in Sources */,
|
||||
5B92D686243018040049877B /* AppDelegate.swift in Sources */,
|
||||
5B92D687243018040049877B /* PhoneNumberViewController.swift in Sources */,
|
||||
5961ABEB2474E358004040DF /* MigrationViewController.swift in Sources */,
|
||||
5B92D688243018040049877B /* BluetraceUtils.swift in Sources */,
|
||||
5B92D689243018040049877B /* NewFeedbackFlowController.swift in Sources */,
|
||||
5B92D68A243018040049877B /* Outcome.swift in Sources */,
|
||||
5B92D68B243018040049877B /* Encounter+EncounterRecord.swift in Sources */,
|
||||
0B42D0DE2432B39E00E4F44C /* Question2ErrorViewController.swift in Sources */,
|
||||
594E77C024736B77009B8B34 /* EncounterDB.swift in Sources */,
|
||||
590888B42431B9F5008C9B9F /* UploadDataNavigationController.swift in Sources */,
|
||||
5B92D68C243018040049877B /* GetJMCTargetAction.swift in Sources */,
|
||||
5B92D68D243018040049877B /* Logging.swift in Sources */,
|
||||
|
@ -1032,9 +1087,12 @@
|
|||
5B92D68E243018040049877B /* HelpNavController.swift in Sources */,
|
||||
5B92D68F243018040049877B /* OTPViewController.swift in Sources */,
|
||||
596B189A24496D32003E190F /* Encounter+Util.swift in Sources */,
|
||||
5904A5C32462471A008C8012 /* EncounterV1toV2.xcmappingmodel in Sources */,
|
||||
5B92D690243018040049877B /* Encounter+CoreDataClass.swift in Sources */,
|
||||
5B92D691243018040049877B /* RespondToAuthChallengeAPI.swift in Sources */,
|
||||
5B92D692243018040049877B /* BluetraceManager.swift in Sources */,
|
||||
597BB7CD245FAEC00067A2E2 /* SecKey+CovidSafe.swift in Sources */,
|
||||
597BB7D0245FB1250067A2E2 /* Crypto.swift in Sources */,
|
||||
5B92D693243018040049877B /* UIColor+Hex.swift in Sources */,
|
||||
5B92D694243018040049877B /* OnboardingStep1ViewController.swift in Sources */,
|
||||
5B92D695243018040049877B /* DeviceInfoExtension.swift in Sources */,
|
||||
|
@ -1113,17 +1171,17 @@
|
|||
0B69E7EB2430CF4100561DD9 /* UploadDataThankYouHomeViewController.swift in Sources */,
|
||||
1B86119924303F9600EA4B6B /* Question2ErrorViewController.swift in Sources */,
|
||||
A767D335242DF1B100DC9E2A /* ADGColorPallete.swift in Sources */,
|
||||
30FADDAE23F6896C006C125F /* Encounter+Event.swift in Sources */,
|
||||
A767D327242DF1B100DC9E2A /* UIKitExtensions.swift in Sources */,
|
||||
7FACD53A23F25A9A0042A33A /* InitialScreenViewController.swift in Sources */,
|
||||
C58D817923F16C3900345771 /* OnboardingStep2cViewController.swift in Sources */,
|
||||
59B7417024514126006E1EEA /* RegistrationConsentViewController.swift in Sources */,
|
||||
5D5F83B023F045A800770DEF /* HomeViewController.swift in Sources */,
|
||||
5B337AAB245A9BBC00537620 /* UploadDataErrorViewController.swift in Sources */,
|
||||
FB12C4C524304AF0007E893B /* OnboardingStep1aViewController.swift in Sources */,
|
||||
7F19B4DD23F565850071A11E /* PogoInstructionsViewController.swift in Sources */,
|
||||
30E91BEB23EFEA0B002D592A /* CodeInputView.swift in Sources */,
|
||||
597BB7CF245FB1250067A2E2 /* Crypto.swift in Sources */,
|
||||
30BE1CAF23F1349F005DCE4F /* EncounterRecord.swift in Sources */,
|
||||
59490B64245FE3DA00C9802B /* EncounterV2Mapping.swift in Sources */,
|
||||
C58D817723F169DB00345771 /* OnboardingStep2bViewController.swift in Sources */,
|
||||
59ACB574242F195A00E63E3C /* InitiateUploadAPI.swift in Sources */,
|
||||
A767D324242DF1B100DC9E2A /* AsyncAction.swift in Sources */,
|
||||
|
@ -1138,8 +1196,10 @@
|
|||
A767D316242DF1B000DC9E2A /* Logging.swift in Sources */,
|
||||
D8EB201B23FA722D001C60EC /* HelpNavController.swift in Sources */,
|
||||
596B189924496D32003E190F /* Encounter+Util.swift in Sources */,
|
||||
5961ABEA2474E358004040DF /* MigrationViewController.swift in Sources */,
|
||||
30BE1CB523F15D47005DCE4F /* OTPViewController.swift in Sources */,
|
||||
5D8DD06123E319B300E097EF /* Encounter+CoreDataClass.swift in Sources */,
|
||||
594E77BF24736B77009B8B34 /* EncounterDB.swift in Sources */,
|
||||
FB12C4C1242F0480007E893B /* RespondToAuthChallengeAPI.swift in Sources */,
|
||||
5D269C0D23E2958F00ADF2DE /* BluetraceManager.swift in Sources */,
|
||||
1B86119124303EF200EA4B6B /* Question1ViewController.swift in Sources */,
|
||||
|
@ -1153,6 +1213,7 @@
|
|||
A767D325242DF1B100DC9E2A /* SendFeedbackAction.swift in Sources */,
|
||||
C5D209FC23F4476F007233BE /* UITextViewFixed.swift in Sources */,
|
||||
C585C83B23EEB99B0061B7C6 /* GradientButton.swift in Sources */,
|
||||
597BB7CC245FAEC00067A2E2 /* SecKey+CovidSafe.swift in Sources */,
|
||||
5B7ABF25244D3BC600BB249B /* IsolationSuccessViewController.swift in Sources */,
|
||||
A767D331242DF1B100DC9E2A /* ViewControllerFactory.swift in Sources */,
|
||||
0BA617CE242E09B200E6C631 /* FeedbackViewController.swift in Sources */,
|
||||
|
@ -1186,6 +1247,7 @@
|
|||
A767D334242DF1B100DC9E2A /* Action.swift in Sources */,
|
||||
59AF2E992435533A00ACCAF2 /* CovidCertificates.swift in Sources */,
|
||||
7F2F0BA223EFFF75006D7404 /* OnboardingStep2ViewController.swift in Sources */,
|
||||
594E77C2247387B1009B8B34 /* EncounterDB+migration.swift in Sources */,
|
||||
59898603245173C200966E61 /* URLHelper.swift in Sources */,
|
||||
A767D31F242DF1B000DC9E2A /* HTTPPostFeedbackAction.swift in Sources */,
|
||||
7F36305F23F7F81400CC6E1D /* PushNotificationConstants.swift in Sources */,
|
||||
|
@ -1196,6 +1258,7 @@
|
|||
1B86119324303F4A00EA4B6B /* Question2ViewController.swift in Sources */,
|
||||
5D8DD06223E319B300E097EF /* Encounter+CoreDataProperties.swift in Sources */,
|
||||
A767D32A242DF1B100DC9E2A /* Issue.swift in Sources */,
|
||||
5904A5C22462471A008C8012 /* EncounterV1toV2.xcmappingmodel in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1308,21 +1371,21 @@
|
|||
};
|
||||
59E766DD242CBC590015EA07 /* covid-staging */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 20A0AADA27329C83CFAB5A7C /* Pods-CovidSafe.covid-staging.xcconfig */;
|
||||
baseConfigurationReference = 2B916D8946F8A94E32E569C7 /* Pods-CovidSafe.covid-staging.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
DEVELOPMENT_TEAM = 45792XH5L8;
|
||||
INFOPLIST_FILE = CovidSafe/Info.plist;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3;
|
||||
MARKETING_VERSION = 1.4;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe;
|
||||
PRODUCT_NAME = COVIDSafe;
|
||||
|
@ -1391,21 +1454,21 @@
|
|||
};
|
||||
59E766DF242CBC8C0015EA07 /* covid-production */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 679DE00E3E364DA756795844 /* Pods-CovidSafe.covid-production.xcconfig */;
|
||||
baseConfigurationReference = 1925EA5F4413AD52AC198894 /* Pods-CovidSafe.covid-production.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
DEVELOPMENT_TEAM = 45792XH5L8;
|
||||
INFOPLIST_FILE = CovidSafe/Info.plist;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3;
|
||||
MARKETING_VERSION = 1.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe;
|
||||
PRODUCT_NAME = COVIDSafe;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1419,24 +1482,25 @@
|
|||
};
|
||||
5B92D6D5243018040049877B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = E3B9CCF78D93EFF0EF2A0ADB /* Pods-CovidSafe-staging.debug.xcconfig */;
|
||||
baseConfigurationReference = 46A5730925DA6B664DFE9546 /* Pods-CovidSafe-staging.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
DEVELOPMENT_TEAM = 45792XH5L8;
|
||||
INFOPLIST_FILE = CovidSafe/Info.plist;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3;
|
||||
MARKETING_VERSION = 1.4;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe;
|
||||
PRODUCT_MODULE_NAME = COVIDSafe;
|
||||
PRODUCT_NAME = "COVIDSafe-staging";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SERVICE_UUID = "CC0AC8B7-03B5-4252-8D84-44D199E16065";
|
||||
|
@ -1448,24 +1512,25 @@
|
|||
};
|
||||
5B92D6D6243018040049877B /* covid-staging */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3A403F07F3B7C5A94CBFC43D /* Pods-CovidSafe-staging.covid-staging.xcconfig */;
|
||||
baseConfigurationReference = 49A22E09D113DF058C94C6E6 /* Pods-CovidSafe-staging.covid-staging.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
DEVELOPMENT_TEAM = 45792XH5L8;
|
||||
INFOPLIST_FILE = CovidSafe/Info.plist;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3;
|
||||
MARKETING_VERSION = 1.4;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe;
|
||||
PRODUCT_MODULE_NAME = COVIDSafe;
|
||||
PRODUCT_NAME = "COVIDSafe-staging";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SERVICE_UUID = "CC0AC8B7-03B5-4252-8D84-44D199E16065";
|
||||
|
@ -1477,23 +1542,24 @@
|
|||
};
|
||||
5B92D6D7243018040049877B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 122AF4E79D17C983066C1CEB /* Pods-CovidSafe-staging.release.xcconfig */;
|
||||
baseConfigurationReference = FB81BAD81D73C6FD42202A04 /* Pods-CovidSafe-staging.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
DEVELOPMENT_TEAM = 45792XH5L8;
|
||||
INFOPLIST_FILE = CovidSafe/Info.plist;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3;
|
||||
MARKETING_VERSION = 1.4;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe;
|
||||
PRODUCT_MODULE_NAME = COVIDSafe;
|
||||
PRODUCT_NAME = "COVIDSafe-staging";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SERVICE_UUID = "CC0AC8B7-03B5-4252-8D84-44D199E16065";
|
||||
|
@ -1506,23 +1572,24 @@
|
|||
};
|
||||
5B92D6D8243018040049877B /* covid-production */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 46D0C3F015CA753BB4D4787D /* Pods-CovidSafe-staging.covid-production.xcconfig */;
|
||||
baseConfigurationReference = 81B28CDCE1F29BA0F1D30CCE /* Pods-CovidSafe-staging.covid-production.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
DEVELOPMENT_TEAM = 45792XH5L8;
|
||||
INFOPLIST_FILE = CovidSafe/Info.plist;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3;
|
||||
MARKETING_VERSION = 1.4;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe;
|
||||
PRODUCT_MODULE_NAME = COVIDSafe;
|
||||
PRODUCT_NAME = "COVIDSafe-staging";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SERVICE_UUID = "CC0AC8B7-03B5-4252-8D84-44D199E16065";
|
||||
|
@ -1651,21 +1718,21 @@
|
|||
};
|
||||
5DD41D4C23DCB03D00FD4AB0 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 6EBCA1AD6D10F8DF7BBDC660 /* Pods-CovidSafe.debug.xcconfig */;
|
||||
baseConfigurationReference = 39E21BD3842669F051A5D6D8 /* Pods-CovidSafe.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
DEVELOPMENT_TEAM = 45792XH5L8;
|
||||
INFOPLIST_FILE = CovidSafe/Info.plist;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3;
|
||||
MARKETING_VERSION = 1.4;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe;
|
||||
PRODUCT_NAME = COVIDSafe;
|
||||
|
@ -1679,21 +1746,21 @@
|
|||
};
|
||||
5DD41D4D23DCB03D00FD4AB0 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 342FF717762F714E56F4412D /* Pods-CovidSafe.release.xcconfig */;
|
||||
baseConfigurationReference = 03E2D9045555F5F013130375 /* Pods-CovidSafe.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
DEVELOPMENT_TEAM = 45792XH5L8;
|
||||
INFOPLIST_FILE = CovidSafe/Info.plist;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3;
|
||||
MARKETING_VERSION = 1.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe;
|
||||
PRODUCT_NAME = COVIDSafe;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1747,9 +1814,10 @@
|
|||
5DD41D7723DE141700FD4AB0 /* tracer.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
59490B61245FE22C00C9802B /* ModelV2.xcdatamodel */,
|
||||
5DD41D7823DE141700FD4AB0 /* Model.xcdatamodel */,
|
||||
);
|
||||
currentVersion = 5DD41D7823DE141700FD4AB0 /* Model.xcdatamodel */;
|
||||
currentVersion = 59490B61245FE22C00C9802B /* ModelV2.xcdatamodel */;
|
||||
path = tracer.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
|
|
|
@ -50,6 +50,12 @@
|
|||
ReferencedContainer = "container:CovidSafe.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.MigrationDebug 1"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
|
|
@ -19,7 +19,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
setupCoredataDir()
|
||||
Encounter.timestamp(for: .appStarted)
|
||||
let firstRun = UserDefaults.standard.bool(forKey: "HasBeenLaunched")
|
||||
if( !firstRun ) {
|
||||
let keychain = KeychainSwift()
|
||||
|
@ -164,27 +163,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
scheduleReminderNotifications()
|
||||
}
|
||||
|
||||
// MARK: - Core Data stack
|
||||
|
||||
lazy var persistentContainer: CovidPersistentContainer = {
|
||||
/*
|
||||
The persistent container for the application. This implementation
|
||||
creates and returns a container, having loaded the store for the
|
||||
application to it. This property is optional since there are legitimate
|
||||
error conditions that could cause the creation of the store to fail.
|
||||
*/
|
||||
let container = CovidPersistentContainer(name: "tracer")
|
||||
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
|
||||
if let error = error as NSError? {
|
||||
fatalError("Unresolved error \(error), \(error.userInfo)")
|
||||
}
|
||||
})
|
||||
return container
|
||||
}()
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
DLog("applicationDidBecomeActive")
|
||||
Encounter.timestamp(for: .appEnteredForeground)
|
||||
|
||||
startAccelerometerUpdates()
|
||||
clearOldDataInContext()
|
||||
|
@ -199,7 +179,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
DLog("applicationDidEnterBackground")
|
||||
Encounter.timestamp(for: .appEnteredBackground)
|
||||
|
||||
self.dismissBlackscreen()
|
||||
stopAccelerometerUpdates()
|
||||
|
@ -214,25 +193,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
DLog("applicationWillTerminate")
|
||||
Encounter.timestamp(for: .appTerminating)
|
||||
|
||||
stopAccelerometerUpdates()
|
||||
}
|
||||
|
||||
// MARK: - Core Data Saving support
|
||||
|
||||
func saveContext () {
|
||||
let context = persistentContainer.viewContext
|
||||
if context.hasChanges {
|
||||
do {
|
||||
try context.save()
|
||||
} catch {
|
||||
let nserror = error as NSError
|
||||
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func clearOldDataInContext() {
|
||||
var calendar = Calendar.current
|
||||
calendar.timeZone = NSTimeZone.local
|
||||
|
@ -250,7 +214,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
registerBackgroundTask()
|
||||
let dispatchQueue = DispatchQueue(label: "DeleteOldData", qos: .background)
|
||||
dispatchQueue.async{
|
||||
let managedContext = self.persistentContainer.viewContext
|
||||
guard let persistentContainer = EncounterDB.shared.persistentContainer else {
|
||||
self.endBackgroundTask()
|
||||
return
|
||||
}
|
||||
let managedContext = persistentContainer.viewContext
|
||||
if let oldFetchRequest = Encounter.fetchOldEncounters() {
|
||||
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: oldFetchRequest)
|
||||
do {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="586"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ow2-rP-ZcP" userLabel="ContentView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="429"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="472"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="AppPermissions2" translatesAutoresizingMaskIntoConstraints="NO" id="zzU-xp-IaB">
|
||||
<rect key="frame" x="32" y="8" width="311" height="188"/>
|
||||
|
@ -38,9 +38,9 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" usesAttributedText="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="x1u-Qk-m74">
|
||||
<rect key="frame" x="32" y="311" width="311" height="43"/>
|
||||
<rect key="frame" x="32" y="311" width="311" height="64.5"/>
|
||||
<attributedString key="attributedText">
|
||||
<fragment content="1. Keep your phone with you when you leave home. ">
|
||||
<fragment content="1. When you leave home, keep your phone with you and make sure COVIDSafe is active.">
|
||||
<attributes>
|
||||
<font key="NSFont" metaFont="system" size="18"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" headIndent="18" tighteningFactorForTruncation="0.0"/>
|
||||
|
@ -49,16 +49,30 @@
|
|||
</attributedString>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2. Keep the app running. " textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sHp-C7-xCZ">
|
||||
<rect key="frame" x="32" y="370" width="311" height="21.5"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2. Bluetooth® should be kept ON." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sHp-C7-xCZ">
|
||||
<rect key="frame" x="32" y="391.5" width="311" height="21.5"/>
|
||||
<fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="18"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" usesAttributedText="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="04D-Hy-djY">
|
||||
<rect key="frame" x="32" y="407.5" width="311" height="21.5"/>
|
||||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" usesAttributedText="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="04D-Hy-djY">
|
||||
<rect key="frame" x="32" y="429" width="311" height="43"/>
|
||||
<attributedString key="attributedText">
|
||||
<fragment content="3. Keep Bluetooth® on.">
|
||||
<fragment content="3. COVIDSafe does not send pairing requests. ">
|
||||
<attributes>
|
||||
<font key="NSFont" metaFont="system" size="18"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" headIndent="18" tighteningFactorForTruncation="0.0"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content="Learn more">
|
||||
<attributes>
|
||||
<color key="NSColor" red="0.0" green="0.54117647059999996" blue="0.13725490200000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<font key="NSFont" metaFont="system" size="18"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" headIndent="18" tighteningFactorForTruncation="0.0"/>
|
||||
<integer key="NSUnderline" value="1"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content=".">
|
||||
<attributes>
|
||||
<font key="NSFont" metaFont="system" size="18"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" headIndent="18" tighteningFactorForTruncation="0.0"/>
|
||||
|
@ -66,6 +80,9 @@
|
|||
</fragment>
|
||||
</attributedString>
|
||||
<nil key="highlightedColor"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="0yI-MG-Vp0" appends="YES" id="Gwy-3W-KzG"/>
|
||||
</connections>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
|
@ -107,7 +124,7 @@
|
|||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<segue destination="yl1-rG-jXE" kind="presentation" modalPresentationStyle="fullScreen" id="JfD-5U-gMM"/>
|
||||
<action selector="continueBtnTapped:" destination="GaQ-f5-ei6" eventType="touchUpInside" id="ksa-Q1-bFw"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
|
@ -125,10 +142,18 @@
|
|||
<viewLayoutGuide key="safeArea" id="PHO-4j-w6y"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="Qmi-E0-d5C"/>
|
||||
<connections>
|
||||
<segue destination="yl1-rG-jXE" kind="presentation" identifier="showHomeSegue" modalPresentationStyle="fullScreen" id="Yi1-Hr-f9s"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="SqF-IF-P8L" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
<tapGestureRecognizer id="0yI-MG-Vp0" userLabel="LearnMoreTapped">
|
||||
<connections>
|
||||
<action selector="learnMoreTapped:" destination="GaQ-f5-ei6" id="UJg-09-Jdt"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-3423" y="4081"/>
|
||||
<point key="canvasLocation" x="-2980" y="3394"/>
|
||||
</scene>
|
||||
<!--Onboarding Step 1 View Controller-->
|
||||
<scene sceneID="26D-Zd-57d">
|
||||
|
@ -239,7 +264,7 @@ Together we can help stop the spread and stay healthy.</string>
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="543"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SpU-i1-aUA" userLabel="ContentView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="522.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="587"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="BEd-YX-6P6" userLabel="BackButton">
|
||||
<rect key="frame" x="16" y="16" width="44" height="44"/>
|
||||
|
@ -281,8 +306,11 @@ Together we can help stop the spread and stay healthy.</string>
|
|||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2. Notifications" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DAg-5r-Sgd">
|
||||
<rect key="frame" x="32" y="485" width="311" height="21.5"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DAg-5r-Sgd">
|
||||
<rect key="frame" x="32" y="485" width="311" height="86"/>
|
||||
<string key="text">2. Notifications
|
||||
|
||||
COVIDSafe does not send pairing requests.</string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -329,8 +357,7 @@ Together we can help stop the spread and stay healthy.</string>
|
|||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="allowPermissionsBtn:" destination="eME-NJ-Fcz" eventType="touchUpInside" id="siX-i4-aS7"/>
|
||||
<segue destination="jtV-53-sil" kind="show" id="9GC-gr-FFS"/>
|
||||
<segue destination="GaQ-f5-ei6" kind="show" id="DrV-xU-Plc"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CdG-cy-ocX" userLabel="ProgressView">
|
||||
|
@ -952,7 +979,6 @@ They will need to register using their own device and phone number so that COVID
|
|||
<outlet property="verifyButton" destination="lQY-RW-yBL" id="0Zf-Wz-kba"/>
|
||||
<outlet property="wrongNumberButton" destination="K7X-Ux-SAc" id="yCf-mF-ngh"/>
|
||||
<segue destination="eME-NJ-Fcz" kind="show" identifier="showAllowPermissionsFromOTPSegue" id="4eL-1Z-MtW"/>
|
||||
<segue destination="jtV-53-sil" kind="show" identifier="OTPToTurnOnBtSegue" id="Qc8-cY-neO"/>
|
||||
<segue destination="yl1-rG-jXE" kind="presentation" identifier="OTPToHomeSegue" modalPresentationStyle="fullScreen" id="8rs-ZD-VFl"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
|
@ -960,73 +986,6 @@ They will need to register using their own device and phone number so that COVID
|
|||
</objects>
|
||||
<point key="canvasLocation" x="-2870" y="1012"/>
|
||||
</scene>
|
||||
<!--Onboarding Step 2c View Controller-->
|
||||
<scene sceneID="s5a-9i-aLg">
|
||||
<objects>
|
||||
<viewController modalTransitionStyle="crossDissolve" modalPresentationStyle="fullScreen" id="jtV-53-sil" userLabel="Onboarding Step 2c View Controller" customClass="OnboardingStep2cViewController" customModule="COVIDSafe" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="nnw-PT-xcy">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QGC-4P-Xbk">
|
||||
<rect key="frame" x="32" y="586" width="311" height="49"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.40000000000000002" blue="0.1058823529" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="49" id="MDf-og-8ou"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
|
||||
<state key="normal" title="Continue">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="enabledBluetoothBtn:" destination="jtV-53-sil" eventType="touchUpInside" id="OhZ-8d-ygC"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="AppNoPermissions" translatesAutoresizingMaskIntoConstraints="NO" id="jcN-AE-FsG">
|
||||
<rect key="frame" x="32" y="8" width="311" height="188"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Turn on your Bluetooth®" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ahv-yZ-Jd3">
|
||||
<rect key="frame" x="32" y="199" width="311" height="29"/>
|
||||
<accessibility key="accessibilityConfiguration">
|
||||
<accessibilityTraits key="traits" staticText="YES" header="YES"/>
|
||||
</accessibility>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="24"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Please go to your Settings or Control Center to turn on Bluetooth®.
Then come back to the COVIDSafe app to confirm." lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tjL-QF-W6s">
|
||||
<rect key="frame" x="32" y="236" width="311" height="107.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="uhC-er-6bV" firstAttribute="trailing" secondItem="QGC-4P-Xbk" secondAttribute="trailing" constant="32" id="9gn-Mz-yYE"/>
|
||||
<constraint firstItem="jcN-AE-FsG" firstAttribute="centerX" secondItem="uhC-er-6bV" secondAttribute="centerX" id="Afx-qn-ugT"/>
|
||||
<constraint firstItem="uhC-er-6bV" firstAttribute="trailing" secondItem="Ahv-yZ-Jd3" secondAttribute="trailing" constant="32" id="ESD-TG-nCp"/>
|
||||
<constraint firstItem="uhC-er-6bV" firstAttribute="trailing" secondItem="tjL-QF-W6s" secondAttribute="trailing" constant="32" id="ba8-1O-KOC"/>
|
||||
<constraint firstItem="uhC-er-6bV" firstAttribute="bottom" secondItem="QGC-4P-Xbk" secondAttribute="bottom" constant="32" id="cZR-Lx-IIe"/>
|
||||
<constraint firstItem="Ahv-yZ-Jd3" firstAttribute="leading" secondItem="uhC-er-6bV" secondAttribute="leading" constant="32" id="gE6-B8-Ukk"/>
|
||||
<constraint firstItem="QGC-4P-Xbk" firstAttribute="leading" secondItem="uhC-er-6bV" secondAttribute="leading" constant="32" id="ghH-cO-PBt"/>
|
||||
<constraint firstItem="Ahv-yZ-Jd3" firstAttribute="top" secondItem="jcN-AE-FsG" secondAttribute="bottom" constant="3" id="lAO-nD-Vwl"/>
|
||||
<constraint firstItem="jcN-AE-FsG" firstAttribute="top" secondItem="uhC-er-6bV" secondAttribute="top" constant="8" id="mQu-H9-RzN"/>
|
||||
<constraint firstItem="tjL-QF-W6s" firstAttribute="leading" secondItem="uhC-er-6bV" secondAttribute="leading" constant="32" id="sTj-BQ-Nhj"/>
|
||||
<constraint firstItem="tjL-QF-W6s" firstAttribute="top" secondItem="Ahv-yZ-Jd3" secondAttribute="bottom" constant="8" id="xuJ-ia-nAM"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="uhC-er-6bV"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="wa8-bd-DB6"/>
|
||||
<connections>
|
||||
<segue destination="GaQ-f5-ei6" kind="show" identifier="showFullySetUpFromTurnOnBtSegue" id="sbt-WA-Zmh"/>
|
||||
<segue destination="yl1-rG-jXE" kind="presentation" identifier="showHomeFromTurnOnBtSegue" modalPresentationStyle="fullScreen" id="9Us-JB-oI0"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="yOi-Ce-xh5" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-3422" y="3134"/>
|
||||
</scene>
|
||||
<!--Home-->
|
||||
<scene sceneID="ExA-0f-AvY">
|
||||
<objects>
|
||||
|
@ -1039,7 +998,7 @@ They will need to register using their own device and phone number so that COVID
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="2301"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a1C-2s-72y" userLabel="Home Header View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="775"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="725"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="u6A-MV-WzM">
|
||||
<rect key="frame" x="317" y="22" width="50" height="50"/>
|
||||
|
@ -1074,54 +1033,56 @@ They will need to register using their own device and phone number so that COVID
|
|||
<constraint firstAttribute="width" constant="240" id="yaP-9d-JNY"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="7vU-Zc-lZj">
|
||||
<rect key="frame" x="32" y="423" width="311" height="256"/>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="7vU-Zc-lZj">
|
||||
<rect key="frame" x="32" y="468" width="311" height="161"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="AxN-oX-9aS" userLabel="ThanksForHelp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="311" height="128"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Thank you for helping stop the spread of COVID-19. Your information has been uploaded." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="J3y-tK-eCX">
|
||||
<rect key="frame" x="0.0" y="0.0" width="311" height="78"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vk7-vj-SYv" userLabel="seperator">
|
||||
<rect key="frame" x="75.5" y="102" width="160" height="2"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="2" id="2Yz-2U-XRU"/>
|
||||
<constraint firstAttribute="width" constant="160" id="Pmr-1g-1qw"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="J3y-tK-eCX" secondAttribute="trailing" id="0oL-pQ-gRj"/>
|
||||
<constraint firstItem="J3y-tK-eCX" firstAttribute="top" secondItem="AxN-oX-9aS" secondAttribute="top" id="2vb-QH-79r"/>
|
||||
<constraint firstItem="J3y-tK-eCX" firstAttribute="leading" secondItem="AxN-oX-9aS" secondAttribute="leading" id="BAH-sg-Cwn"/>
|
||||
<constraint firstItem="vk7-vj-SYv" firstAttribute="centerX" secondItem="AxN-oX-9aS" secondAttribute="centerX" id="BSo-tr-gI3"/>
|
||||
<constraint firstAttribute="bottom" secondItem="vk7-vj-SYv" secondAttribute="bottom" constant="24" id="eNR-8l-aqT"/>
|
||||
<constraint firstItem="vk7-vj-SYv" firstAttribute="top" secondItem="J3y-tK-eCX" secondAttribute="bottom" constant="24" id="syN-9Z-JWd"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GHB-bi-tze" userLabel="Status">
|
||||
<rect key="frame" x="0.0" y="128" width="311" height="128"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="COVIDSafe is active. No further action is required." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="49x-lt-ifR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="311" height="128"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="49x-lt-ifR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="311" height="43"/>
|
||||
<string key="text">COVIDSafe is active.
|
||||
No further action is required.</string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Your information was uploaded on 19 May 2020." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SdZ-6A-VIB">
|
||||
<rect key="frame" x="0.0" y="59" width="311" height="43"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" usesAttributedText="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vKm-pz-Cun">
|
||||
<rect key="frame" x="0.0" y="118" width="311" height="43"/>
|
||||
<attributedString key="attributedText">
|
||||
<fragment content="COVIDSafe does not send ">
|
||||
<attributes>
|
||||
<font key="NSFont" metaFont="system" size="18"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content="pairing requests">
|
||||
<attributes>
|
||||
<font key="NSFont" metaFont="system" size="18"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
|
||||
<integer key="NSUnderline" value="1"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content=".">
|
||||
<attributes>
|
||||
<font key="NSFont" metaFont="system" size="18"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
</attributedString>
|
||||
<nil key="highlightedColor"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="f47-5X-eXP" appends="YES" id="5Yi-Zr-9XG"/>
|
||||
</connections>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="49x-lt-ifR" secondAttribute="trailing" id="9a6-CD-3Oz"/>
|
||||
<constraint firstItem="49x-lt-ifR" firstAttribute="leading" secondItem="GHB-bi-tze" secondAttribute="leading" id="Jyn-4S-Q8t"/>
|
||||
<constraint firstItem="49x-lt-ifR" firstAttribute="top" secondItem="GHB-bi-tze" secondAttribute="top" id="tdZ-OR-TpQ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="49x-lt-ifR" secondAttribute="bottom" id="xnQ-zn-FwO"/>
|
||||
<constraint firstItem="49x-lt-ifR" firstAttribute="top" secondItem="7vU-Zc-lZj" secondAttribute="top" id="fpf-Dy-hQb"/>
|
||||
<constraint firstAttribute="bottom" secondItem="vKm-pz-Cun" secondAttribute="bottom" id="ozd-TP-CpW"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.78431372549019607" green="1" blue="0.72549019607843135" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
|
@ -1133,12 +1094,12 @@ They will need to register using their own device and phone number so that COVID
|
|||
<constraint firstItem="g8W-pe-Zjl" firstAttribute="top" secondItem="a1C-2s-72y" secondAttribute="top" constant="168" id="SXW-DN-uaa"/>
|
||||
<constraint firstAttribute="bottom" secondItem="7vU-Zc-lZj" secondAttribute="bottom" constant="96" id="Sn6-eI-OWc"/>
|
||||
<constraint firstAttribute="trailing" secondItem="u6A-MV-WzM" secondAttribute="trailing" constant="8" id="TPp-ft-aBl"/>
|
||||
<constraint firstItem="7vU-Zc-lZj" firstAttribute="top" secondItem="g8W-pe-Zjl" secondAttribute="bottom" constant="15" id="l3p-ND-WnZ"/>
|
||||
<constraint firstItem="7vU-Zc-lZj" firstAttribute="top" secondItem="g8W-pe-Zjl" secondAttribute="bottom" constant="60" id="l3p-ND-WnZ"/>
|
||||
<constraint firstItem="7vU-Zc-lZj" firstAttribute="leading" secondItem="a1C-2s-72y" secondAttribute="leading" constant="32" id="vAy-Ic-q12"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Eim-Z7-BkO">
|
||||
<rect key="frame" x="0.0" y="719" width="375" height="1658"/>
|
||||
<rect key="frame" x="0.0" y="669" width="375" height="1658"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ewx-Jj-gLM" userLabel="PermissionsView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="832"/>
|
||||
|
@ -2054,11 +2015,10 @@ They will need to register using their own device and phone number so that COVID
|
|||
<outlet property="pushNotificationStatusLabel" destination="tdm-Nt-WrT" id="1fz-Dj-kEt"/>
|
||||
<outlet property="pushNotificationStatusTitle" destination="gx3-nF-2OD" id="A6K-y6-BFD"/>
|
||||
<outlet property="screenStack" destination="Eim-Z7-BkO" id="vQc-mn-6mJ"/>
|
||||
<outlet property="thanksForTheHelp" destination="AxN-oX-9aS" id="QhO-zB-K4o"/>
|
||||
<outlet property="uploadDateLabel" destination="SdZ-6A-VIB" id="2Xb-Nr-mtf"/>
|
||||
<outlet property="uploadView" destination="2xp-v3-22Q" id="diq-zr-YJL"/>
|
||||
<outlet property="versionNumberLabel" destination="CD7-Ft-bQU" id="Lqj-N3-DqH"/>
|
||||
<outlet property="versionView" destination="KEs-yq-szw" id="zPn-dc-ce9"/>
|
||||
<segue destination="8dk-ge-2YL" kind="presentation" identifier="IsolationSuccessSegue" modalPresentationStyle="fullScreen" id="mjO-TD-7Iq"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="nJa-Mu-MXq" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
|
@ -2067,6 +2027,11 @@ They will need to register using their own device and phone number so that COVID
|
|||
<action selector="onSettingsTapped:" destination="yl1-rG-jXE" id="A5D-v5-Mvt"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
<tapGestureRecognizer id="f47-5X-eXP" userLabel="BluetoothPairingLabelTapped">
|
||||
<connections>
|
||||
<action selector="bluetoothPairingTapped:" destination="yl1-rG-jXE" id="SAI-Sq-Jsb"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
<tapGestureRecognizer id="3K8-or-mMv" userLabel="HelpTopicsTapped">
|
||||
<connections>
|
||||
<action selector="onHelpButtonTapped:" destination="yl1-rG-jXE" id="hpf-bA-ZiK"/>
|
||||
|
@ -2105,75 +2070,6 @@ They will need to register using their own device and phone number so that COVID
|
|||
</objects>
|
||||
<point key="canvasLocation" x="2189.5999999999999" y="-1882.7586206896553"/>
|
||||
</scene>
|
||||
<!--Isolation Success View Controller-->
|
||||
<scene sceneID="0nZ-xq-WN5">
|
||||
<objects>
|
||||
<viewController id="8dk-ge-2YL" customClass="IsolationSuccessViewController" customModule="COVIDSafe" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Lla-H0-kdm">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dz7-Q3-qhF">
|
||||
<rect key="frame" x="32" y="586" width="311" height="49"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.40000000000000002" blue="0.1058823529" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="49" id="VZc-Co-WlR"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
|
||||
<color key="tintColor" red="0.0" green="0.54117647059999996" blue="0.13725490200000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<state key="normal" title="Continue">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="doneOntap:" destination="8dk-ge-2YL" eventType="touchUpInside" id="1cX-HR-u8X"/>
|
||||
<action selector="enabledBluetoothBtn:" destination="jtV-53-sil" eventType="touchUpInside" id="EQT-3K-YYd"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Upload_Success" translatesAutoresizingMaskIntoConstraints="NO" id="NS0-JW-dF4">
|
||||
<rect key="frame" x="32" y="8" width="311" height="188"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="NS0-JW-dF4" secondAttribute="height" multiplier="311:188" id="zWE-QF-0JR"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Thank you for helping stop the spread of COVID-19!" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="asx-BK-7er">
|
||||
<rect key="frame" x="32" y="230" width="311" height="57.5"/>
|
||||
<accessibility key="accessibilityConfiguration">
|
||||
<accessibilityTraits key="traits" staticText="YES" header="YES"/>
|
||||
</accessibility>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="24"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="You’ve kept others safe while helping to stop the spread of COVID-19 during self-isolation." lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="izB-Kk-H7a">
|
||||
<rect key="frame" x="32" y="303.5" width="311" height="57.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="NS0-JW-dF4" firstAttribute="top" secondItem="G4r-4V-vDo" secondAttribute="top" constant="8" id="0G3-Aw-ixP"/>
|
||||
<constraint firstItem="G4r-4V-vDo" firstAttribute="bottom" secondItem="dz7-Q3-qhF" secondAttribute="bottom" constant="32" id="0eC-1X-bDL"/>
|
||||
<constraint firstItem="NS0-JW-dF4" firstAttribute="centerX" secondItem="Lla-H0-kdm" secondAttribute="centerX" id="DNO-R2-eaP"/>
|
||||
<constraint firstItem="izB-Kk-H7a" firstAttribute="leading" secondItem="G4r-4V-vDo" secondAttribute="leading" constant="32" id="Kiq-ZY-i0o"/>
|
||||
<constraint firstItem="asx-BK-7er" firstAttribute="leading" secondItem="G4r-4V-vDo" secondAttribute="leading" constant="32" id="SLj-yu-lFS"/>
|
||||
<constraint firstItem="dz7-Q3-qhF" firstAttribute="leading" secondItem="G4r-4V-vDo" secondAttribute="leading" constant="32" id="SXg-8D-MkV"/>
|
||||
<constraint firstItem="NS0-JW-dF4" firstAttribute="leading" secondItem="G4r-4V-vDo" secondAttribute="leading" constant="32" id="Xbo-8Q-ynp"/>
|
||||
<constraint firstItem="G4r-4V-vDo" firstAttribute="trailing" secondItem="NS0-JW-dF4" secondAttribute="trailing" constant="32" id="bt0-k6-uvx"/>
|
||||
<constraint firstItem="G4r-4V-vDo" firstAttribute="trailing" secondItem="izB-Kk-H7a" secondAttribute="trailing" constant="32" id="dWa-qW-8kE"/>
|
||||
<constraint firstItem="G4r-4V-vDo" firstAttribute="trailing" secondItem="dz7-Q3-qhF" secondAttribute="trailing" constant="32" id="oUZ-cg-Zif"/>
|
||||
<constraint firstItem="izB-Kk-H7a" firstAttribute="top" secondItem="asx-BK-7er" secondAttribute="bottom" constant="16" id="qfJ-8d-Do5"/>
|
||||
<constraint firstItem="G4r-4V-vDo" firstAttribute="trailing" secondItem="asx-BK-7er" secondAttribute="trailing" constant="32" id="r5t-C4-RAX"/>
|
||||
<constraint firstItem="asx-BK-7er" firstAttribute="top" secondItem="NS0-JW-dF4" secondAttribute="bottom" constant="34" id="zvw-yT-oOA"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="G4r-4V-vDo"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="q84-vG-DNL" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3380" y="-2840"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="39N-pk-1gr">
|
||||
<objects>
|
||||
|
@ -2247,16 +2143,77 @@ and save lives.</string>
|
|||
<segue destination="8nR-hO-fWt" kind="show" identifier="initialScreenToIWantToHelpSegue" id="eMC-CV-hVS"/>
|
||||
<segue destination="mND-9i-sIw" kind="show" identifier="initialScreenToGetOTPSegue" id="rHc-rZ-59x"/>
|
||||
<segue destination="eME-NJ-Fcz" kind="show" identifier="initialScreenToAllowPermissionsSegue" id="XiO-Zp-pOg"/>
|
||||
<segue destination="jtV-53-sil" kind="show" identifier="initialScreenToTurnOnBtSegue" id="ap4-2a-3fH"/>
|
||||
<segue destination="yl1-rG-jXE" kind="presentation" identifier="initialScreenToHomeSegue" modalPresentationStyle="fullScreen" id="Eya-O4-CPO"/>
|
||||
<segue destination="2XR-xi-raR" kind="show" identifier="initialScreenToConsentSegue" id="ntT-Wx-kqK"/>
|
||||
<segue destination="tmd-7A-Wz4" kind="show" identifier="initialPersonalDetailsSegue" id="cLu-Ng-v4y"/>
|
||||
<segue destination="wD9-lR-1wv" kind="presentation" identifier="presentMigrationSegue" id="w3o-Dg-9eW"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="29g-dC-yWi" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-8290" y="339"/>
|
||||
</scene>
|
||||
<!--Migration View Controller-->
|
||||
<scene sceneID="1KH-mM-D5F">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="migrationInProgress" modalPresentationStyle="fullScreen" id="wD9-lR-1wv" customClass="MigrationViewController" customModule="COVIDSafe" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="cPl-cO-Fbz">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="govLogoWhite" translatesAutoresizingMaskIntoConstraints="NO" id="Qov-O8-A7L">
|
||||
<rect key="frame" x="113.5" y="30" width="148" height="77"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="Qov-O8-A7L" secondAttribute="height" multiplier="148:77" id="aqp-uc-4R5"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SLW-8v-OdL" userLabel="Blue background view">
|
||||
<rect key="frame" x="0.0" y="137" width="375" height="530"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="COVIDSafe update is in progress.
Please make sure your phone is not switched off until the update is complete." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1Wo-Qe-Wye">
|
||||
<rect key="frame" x="32" y="40" width="311" height="107.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SOF-ig-kwj" userLabel="AnimatingView">
|
||||
<rect key="frame" x="67.5" y="189.5" width="240" height="240"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="240" id="kxC-N2-PH3"/>
|
||||
<constraint firstAttribute="height" constant="240" id="ryn-nk-rKK"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.7843137255" green="1" blue="0.72549019609999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="1Wo-Qe-Wye" secondAttribute="trailing" constant="32" id="8LA-9O-xXW"/>
|
||||
<constraint firstItem="1Wo-Qe-Wye" firstAttribute="top" secondItem="SLW-8v-OdL" secondAttribute="top" constant="40" id="D5D-Ij-J3b"/>
|
||||
<constraint firstItem="SOF-ig-kwj" firstAttribute="top" secondItem="1Wo-Qe-Wye" secondAttribute="bottom" constant="42" id="QeO-v6-n9q"/>
|
||||
<constraint firstItem="SOF-ig-kwj" firstAttribute="centerX" secondItem="SLW-8v-OdL" secondAttribute="centerX" id="TVj-vF-v4H"/>
|
||||
<constraint firstItem="1Wo-Qe-Wye" firstAttribute="leading" secondItem="SLW-8v-OdL" secondAttribute="leading" constant="32" id="wrG-HY-APO"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Qov-O8-A7L" firstAttribute="width" secondItem="Qov-O8-A7L" secondAttribute="height" multiplier="148:77" id="1iI-wS-6LY"/>
|
||||
<constraint firstItem="SLW-8v-OdL" firstAttribute="leading" secondItem="ZLv-lh-E2f" secondAttribute="leading" id="5do-pU-Abn"/>
|
||||
<constraint firstItem="SLW-8v-OdL" firstAttribute="trailing" secondItem="ZLv-lh-E2f" secondAttribute="trailing" id="PDr-fw-RgW"/>
|
||||
<constraint firstItem="ZLv-lh-E2f" firstAttribute="bottom" secondItem="SLW-8v-OdL" secondAttribute="bottom" id="Tlz-3G-C3g"/>
|
||||
<constraint firstItem="Qov-O8-A7L" firstAttribute="centerX" secondItem="cPl-cO-Fbz" secondAttribute="centerX" id="faB-hs-F95"/>
|
||||
<constraint firstItem="SLW-8v-OdL" firstAttribute="top" secondItem="Qov-O8-A7L" secondAttribute="bottom" constant="30" id="nKo-BV-iiu"/>
|
||||
<constraint firstItem="Qov-O8-A7L" firstAttribute="top" secondItem="ZLv-lh-E2f" secondAttribute="top" constant="30" id="u5Z-1m-FSD"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="ZLv-lh-E2f"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="animationContainer" destination="SOF-ig-kwj" id="24K-l5-R3z"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="3IU-Mp-wPy" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-8561" y="1143"/>
|
||||
</scene>
|
||||
<!--Onboarding Step 1b View Controller-->
|
||||
<scene sceneID="f3t-QQ-sex">
|
||||
<objects>
|
||||
|
@ -2722,7 +2679,7 @@ See the COVIDSafe *privacy policy* for further details about your rights about y
|
|||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Full name (first, last)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EIF-xa-lvX">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Full name (First Last)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EIF-xa-lvX">
|
||||
<rect key="frame" x="32" y="109.5" width="311" height="21.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
<nil key="textColor"/>
|
||||
|
@ -2755,7 +2712,7 @@ See the COVIDSafe *privacy policy* for further details about your rights about y
|
|||
<constraint firstAttribute="width" constant="12" id="QNs-P4-1Be"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Postcode (eg 3000)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7RM-TO-7v0">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Postcode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7RM-TO-7v0">
|
||||
<rect key="frame" x="32" y="293.5" width="311" height="21.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
<nil key="textColor"/>
|
||||
|
@ -3094,22 +3051,19 @@ See the COVIDSafe *privacy policy* for further details about your rights about y
|
|||
</scene>
|
||||
</scenes>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="h8R-i7-zdK"/>
|
||||
<segue reference="ALe-An-dsT"/>
|
||||
<segue reference="8rs-ZD-VFl"/>
|
||||
<segue reference="Qc8-cY-neO"/>
|
||||
<segue reference="bMl-IY-pjw"/>
|
||||
<segue reference="WC1-tG-bo5"/>
|
||||
<segue reference="cLu-Ng-v4y"/>
|
||||
<segue reference="ntT-Wx-kqK"/>
|
||||
<segue reference="Eya-O4-CPO"/>
|
||||
<segue reference="iUa-3s-4XB"/>
|
||||
<segue reference="XiO-Zp-pOg"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
<resources>
|
||||
<image name="AppNoPermissions" width="311" height="188"/>
|
||||
<image name="AppPermissions1" width="311" height="188"/>
|
||||
<image name="AppPermissions2" width="311" height="188"/>
|
||||
<image name="ChevronRight" width="24" height="24"/>
|
||||
<image name="CovidPermissionsOff" width="240" height="240"/>
|
||||
<image name="ShareApp" width="24" height="24"/>
|
||||
<image name="Splash_logo" width="240" height="240"/>
|
||||
<image name="Upload_Success" width="311" height="188"/>
|
||||
<image name="WhiteSmallGovCrest" width="44" height="31"/>
|
||||
<image name="arrow-left" width="24" height="24"/>
|
||||
<image name="bell 1" width="40" height="40"/>
|
||||
|
|
|
@ -13,8 +13,12 @@ struct BluetraceConfig {
|
|||
static let BluetoothServiceID = CBUUID(string: "\(PlistHelper.getvalueFromInfoPlist(withKey: "TRACER_SVC_ID") ?? "B82AB3FC-1595-4F6A-80F0-FE094CC218F9")")
|
||||
|
||||
static let OrgID = "AU_DTA"
|
||||
static let ProtocolVersion = 1
|
||||
static let ProtocolVersion = 2
|
||||
|
||||
static let CentralScanInterval = 60.0 // in seconds
|
||||
static let CentralScanDuration = 10 // in seconds
|
||||
|
||||
static let DummyModel = ""
|
||||
static let DummyRSSI = 999
|
||||
static let DummyTxPower = 999
|
||||
}
|
||||
|
|
|
@ -65,22 +65,30 @@ class CentralController: NSObject {
|
|||
|
||||
func shouldRecordEncounter(_ encounter: EncounterRecord) -> Bool {
|
||||
guard let scannedDate = encounter.timestamp else {
|
||||
DLog("Not recorded encounter before \(encounter)")
|
||||
return true
|
||||
}
|
||||
if abs(scannedDate.timeIntervalSinceNow) > BluetraceConfig.CentralScanInterval {
|
||||
DLog("Encounter last recorded \(abs(scannedDate.timeIntervalSinceNow)) seconds ago")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func shouldReconnectToPeripheral(peripheral: CBPeripheral) -> Bool {
|
||||
guard peripheral.state == .disconnected else {
|
||||
return false
|
||||
}
|
||||
guard let encounteredPeripheral = scannedPeripherals[peripheral.identifier] else {
|
||||
DLog("Not previously encountered CBPeripheral \(String(describing: peripheral.name))")
|
||||
return true
|
||||
}
|
||||
guard let scannedDate = encounteredPeripheral.encounter.timestamp else {
|
||||
DLog("Not previously recorded an encounter with \(encounteredPeripheral)")
|
||||
return true
|
||||
}
|
||||
if abs(scannedDate.timeIntervalSinceNow) > BluetraceConfig.CentralScanInterval {
|
||||
DLog("Peripheral last recorded \(abs(scannedDate.timeIntervalSinceNow)) seconds ago")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -110,7 +118,6 @@ extension CentralController: CBCentralManagerDelegate {
|
|||
switch central.state {
|
||||
case .poweredOn:
|
||||
DLog("CC Starting a scan")
|
||||
Encounter.timestamp(for: .scanningStarted)
|
||||
|
||||
// for all peripherals that are not disconnected, disconnect them
|
||||
self.scannedPeripherals.forEach { (scannedPeri) in
|
||||
|
@ -128,7 +135,7 @@ extension CentralController: CBCentralManagerDelegate {
|
|||
central.connect(recoveredPeripheral)
|
||||
}
|
||||
|
||||
central.scanForPeripherals(withServices: [BluetraceConfig.BluetoothServiceID], options: [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(true)])
|
||||
central.scanForPeripherals(withServices: [BluetraceConfig.BluetoothServiceID], options:nil)
|
||||
default:
|
||||
DLog("State chnged to \(central.state)")
|
||||
}
|
||||
|
@ -196,10 +203,8 @@ extension CentralController: CBCentralManagerDelegate {
|
|||
if let encounteredPeripheral = scannedPeripherals[peripheral.identifier] {
|
||||
if shouldReconnectToPeripheral(peripheral: encounteredPeripheral.peripheral) {
|
||||
peripheral.delegate = self
|
||||
if peripheral.state != .connected {
|
||||
central.connect(peripheral)
|
||||
DLog("found previous peripheral from more than 60 seconds ago")
|
||||
}
|
||||
} else {
|
||||
DLog("iOS Peripheral \(peripheral) has been discovered already in this window, will not attempt to connect to it again")
|
||||
if let scannedDate = encounteredPeripheral.encounter.timestamp {
|
||||
|
@ -217,7 +222,8 @@ extension CentralController: CBCentralManagerDelegate {
|
|||
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
let peripheralStateString = BluetraceUtils.peripheralStateToString(peripheral.state)
|
||||
DLog("CC didConnect peripheral peripheralCentral state: \(BluetraceUtils.centralStateToString(central.state)), Peripheral state: \(peripheralStateString)")
|
||||
guard shouldReconnectToPeripheral(peripheral: peripheral) else {
|
||||
|
||||
guard let seenPeripheral = scannedPeripherals[peripheral.identifier], shouldRecordEncounter(seenPeripheral.encounter) else {
|
||||
central.cancelPeripheralConnection(peripheral)
|
||||
return
|
||||
}
|
||||
|
@ -283,15 +289,22 @@ extension CentralController: CBPeripheralDelegate {
|
|||
DLog("rssi should be present in \(currEncounter.encounter)")
|
||||
return
|
||||
}
|
||||
|
||||
let dataToWrite = CentralWriteData(modelC: DeviceIdentifier.getModel(),
|
||||
let encounterToBroadcast = EncounterBlob(modelC: DeviceIdentifier.getModel(),
|
||||
rssi: rssi,
|
||||
txPower: currEncounter.encounter.txPower,
|
||||
msg: tempId,
|
||||
org: BluetraceConfig.OrgID,
|
||||
v: BluetraceConfig.ProtocolVersion)
|
||||
modelP: nil,
|
||||
msg: tempId)
|
||||
|
||||
|
||||
do {
|
||||
let jsonMsg = try JSONEncoder().encode(encounterToBroadcast)
|
||||
let encryptedMsg = try Crypto.encrypt(dataToEncrypt: jsonMsg)
|
||||
let dataToWrite = CentralWriteData(modelC: BluetraceConfig.DummyModel,
|
||||
rssi: Double(BluetraceConfig.DummyRSSI),
|
||||
txPower: Double(BluetraceConfig.DummyTxPower),
|
||||
msg: encryptedMsg,
|
||||
org: BluetraceConfig.OrgID,
|
||||
v: BluetraceConfig.ProtocolVersion)
|
||||
let encodedData = try JSONEncoder().encode(dataToWrite)
|
||||
peripheral.writeValue(encodedData, for: characteristic, type: .withResponse)
|
||||
} catch {
|
||||
|
@ -314,8 +327,7 @@ extension CentralController: CBPeripheralDelegate {
|
|||
|
||||
if let scannedPeri = scannedPeripherals[peripheral.identifier],
|
||||
let characteristicValue = characteristic.value,
|
||||
shouldRecordEncounter(scannedPeri.encounter)
|
||||
{
|
||||
shouldRecordEncounter(scannedPeri.encounter) {
|
||||
do {
|
||||
let peripheralCharData = try JSONDecoder().decode(PeripheralCharacteristicsData.self, from: characteristicValue)
|
||||
var encounterStruct = scannedPeri.encounter
|
||||
|
@ -325,10 +337,12 @@ extension CentralController: CBPeripheralDelegate {
|
|||
encounterStruct.v = peripheralCharData.v
|
||||
encounterStruct.timestamp = Date()
|
||||
scannedPeripherals.updateValue((scannedPeri.peripheral, encounterStruct), forKey: peripheral.identifier)
|
||||
encounterStruct.saveToCoreData()
|
||||
// here the remote blob will be msg and modelp if v1, msg if v2
|
||||
// local blob will be rssi, txpower, modelc
|
||||
try encounterStruct.saveRemotePeripheralToCoreData()
|
||||
DLog("Central recorded encounter with \(String(describing: scannedPeri.peripheral.name))")
|
||||
} catch {
|
||||
DLog("Error: \(error). CharacteristicValue is \(characteristicValue)")
|
||||
DLog("Error: \(error). CharacteristicValue is \(String(data: characteristicValue, encoding: .utf8) ?? "<nil>")")
|
||||
}
|
||||
} else {
|
||||
DLog("Error: scannedPeripherals[peripheral.identifier] is \(String(describing: scannedPeripherals[peripheral.identifier])), characteristic.value is \(String(describing: characteristic.value))")
|
||||
|
|
|
@ -19,12 +19,13 @@ final class ContactViewController: UIViewController {
|
|||
}
|
||||
|
||||
func fetchContacts() {
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
|
||||
guard let persistentContainer =
|
||||
EncounterDB.shared.persistentContainer else {
|
||||
return
|
||||
}
|
||||
let managedContext = appDelegate.persistentContainer.viewContext
|
||||
let managedContext = persistentContainer.viewContext
|
||||
let fetchRequest = Encounter.fetchRequestForRecords()
|
||||
let sortByContactId = NSSortDescriptor(key: "msg", ascending: false)
|
||||
let sortByContactId = NSSortDescriptor(key: "timestamp", ascending: false)
|
||||
fetchRequest.sortDescriptors = [sortByContactId]
|
||||
fetchedResultsController = NSFetchedResultsController<Encounter>(fetchRequest: fetchRequest, managedObjectContext: managedContext, sectionNameKeyPath: nil, cacheName: nil)
|
||||
fetchedResultsController?.delegate = self
|
||||
|
@ -44,11 +45,11 @@ final class ContactViewController: UIViewController {
|
|||
}
|
||||
var contactCounts: [String: Int] = [:]
|
||||
for encounter in encounters {
|
||||
if encounter.msg != nil {
|
||||
if contactCounts[encounter.msg!] == nil {
|
||||
contactCounts[encounter.msg!] = 0
|
||||
if encounter.remoteBlob != nil {
|
||||
if contactCounts[encounter.remoteBlob!] == nil {
|
||||
contactCounts[encounter.remoteBlob!] = 0
|
||||
}
|
||||
contactCounts[encounter.msg!]! += 1
|
||||
contactCounts[encounter.remoteBlob!]! += 1
|
||||
}
|
||||
}
|
||||
var contactTuples = contactCounts.map { ($0.key, $0.value) }
|
||||
|
|
196
CovidSafe/Crypto.swift
Normal file
196
CovidSafe/Crypto.swift
Normal file
|
@ -0,0 +1,196 @@
|
|||
//
|
||||
// Crypto.swift
|
||||
// CovidSafe
|
||||
//
|
||||
// Copyright © 2020 Australian Government. All rights reserved.
|
||||
//
|
||||
|
||||
import CommonCrypto
|
||||
import Foundation
|
||||
import Security
|
||||
|
||||
enum SecurityError: Error {
|
||||
case PublicKeyCopyError
|
||||
case EncryptionFailedError(_ status: CCCryptorStatus)
|
||||
case DigestFailedError
|
||||
case EncryptionLengthError
|
||||
case EncryptionKeyLengthError
|
||||
case UnexpectedNilKeys
|
||||
}
|
||||
|
||||
|
||||
class Crypto {
|
||||
private static var cachedExportPublicKey: Data?
|
||||
private static var cachedAesKey: Data?
|
||||
private static var cachedMacKey: Data?
|
||||
private static var keyGenTime: Int64 = Int64.min
|
||||
private static var counter: UInt16 = 0
|
||||
private static let NONCE_PADDING: Data = Data([UInt8](repeating: UInt8(0x0E), count: 14))
|
||||
private static let keyCacheQueue = DispatchQueue(label: "au.gov.health.covidsafe.crypto")
|
||||
private static let KEY_GEN_TIME_DELTA: Int64 = 450 // 7.5 minutes
|
||||
#if DEBUG
|
||||
private static let publicKey = Data(base64Encoded: "BNrAcR+C6nkCpIYS9KWYt0Z5Sbleh7UybHmIT2T9YzuR9RzTh3YZcMBjr1K6smeDJW7sPCvMFJNWVPkk3exqjkQ=")
|
||||
#else
|
||||
private static let publicKey = Data(base64Encoded: "BDQbOM4lxeK6ed9br26qvcwsYgaUK9w3CozIHP1gOhR7+qwb7vrh0kSSUUtsayekard9EHElA9RNn/3dJW9hr7I=")
|
||||
#endif
|
||||
|
||||
/**
|
||||
Get a series of secrets that can be decrypted by the server key. The returned data is:
|
||||
1. the ephemeral public key used for decrypting
|
||||
2. the AES encryption key
|
||||
3. the HMAC signature key
|
||||
4. the IV for AES encryption
|
||||
- Parameter serverKey: X9.63 formatted P-256 public key for the server
|
||||
- Throws: Errors from Security framework, or `SecurityError.PublicKeyCopyError`
|
||||
if function failed to derive public key from the ephemeral private key
|
||||
- Returns:
|
||||
- publicKey: exported public P-256 key (compressed form)
|
||||
- aesKey: ephemeral 16-byte AES-128 key
|
||||
- macKey: ephemeral 16-byte key for HMAC
|
||||
- iv: ephemeral 16-byte AES-128 IV
|
||||
*/
|
||||
private static func getEphemeralSecrets(_ serverKey: Data) throws -> (publicKey: Data, aesKey: Data, macKey: Data) {
|
||||
// Server public key
|
||||
var err: Unmanaged<CFError>?
|
||||
let serverKeyOptions: [CFString: Any] = [
|
||||
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
|
||||
kSecAttrKeySizeInBits: 256,
|
||||
kSecAttrKeyClass: kSecAttrKeyClassPublic,
|
||||
]
|
||||
guard let serverPublicKey = SecKeyCreateWithData(serverKey as CFData, serverKeyOptions as CFDictionary, &err) else {
|
||||
throw err!.takeRetainedValue() as Error
|
||||
}
|
||||
|
||||
// CREATE A LOCAL EPHEMERAL P-256 KEYPAIR
|
||||
let ephereralPublicKeyAttributes: [CFString: Any] = [
|
||||
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
|
||||
kSecAttrKeySizeInBits: 256,
|
||||
]
|
||||
|
||||
guard let ephemeralPrivateKey = SecKeyCreateRandomKey(ephereralPublicKeyAttributes as CFDictionary, &err) else {
|
||||
throw err!.takeRetainedValue() as Error
|
||||
}
|
||||
guard let ephemeralPublicKey = SecKeyCopyPublicKey(ephemeralPrivateKey) else {
|
||||
throw SecurityError.PublicKeyCopyError
|
||||
}
|
||||
|
||||
// Exported ephemeral public key for sending/MACing later (compressed format, per ANSI X9.62)
|
||||
let exportPublicKey = try ephemeralPublicKey.CopyCompressedECPublicKey()
|
||||
|
||||
// COMPUTE SHARED SECRET
|
||||
let params = [SecKeyKeyExchangeParameter.requestedSize.rawValue: 32]
|
||||
guard let sharedSecret = SecKeyCopyKeyExchangeResult(ephemeralPrivateKey,
|
||||
SecKeyAlgorithm.ecdhKeyExchangeStandard,
|
||||
serverPublicKey,
|
||||
params as CFDictionary,
|
||||
&err) as Data? else {
|
||||
throw err!.takeRetainedValue() as Error
|
||||
}
|
||||
|
||||
// KDF THE SHARED SECRET TO GET ENC KEY, MAC KEY
|
||||
var keysHashCtx = CC_SHA256_CTX()
|
||||
|
||||
// For keys we'll be using SHA256(sharedSecret)
|
||||
var res: Int32
|
||||
var keysHashValue = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
|
||||
CC_SHA256_Init(&keysHashCtx)
|
||||
res = sharedSecret.withUnsafeBytes {
|
||||
return CC_SHA256_Update(&keysHashCtx, $0.baseAddress, CC_LONG(sharedSecret.count))
|
||||
}
|
||||
guard res == 1 else { throw SecurityError.DigestFailedError }
|
||||
res = keysHashValue.withUnsafeMutableBytes {
|
||||
return CC_SHA256_Final($0.bindMemory(to: UInt8.self).baseAddress, &keysHashCtx)
|
||||
}
|
||||
guard res == 1 else { throw SecurityError.DigestFailedError }
|
||||
|
||||
// Form the keys
|
||||
let aesKey = keysHashValue[..<kCCKeySizeAES128]
|
||||
let macKey = keysHashValue[kCCKeySizeAES128...]
|
||||
|
||||
// At return, the refs to ephemeralPrivateKey and sharedSecret will be dropped and they will be cleared
|
||||
return (exportPublicKey, aesKey, macKey)
|
||||
}
|
||||
|
||||
static func buildSecretData(_ serverPublicKey: Data, _ plaintext: Data) throws -> Data {
|
||||
// Get our ephemeral secrets that will de disposed at the end of this function
|
||||
let (cachedExportPublicKey, cachedAESKey, cachedMacKey, nonce) = try keyCacheQueue.sync { () -> (Data?, Data?, Data?, Data) in
|
||||
if Crypto.keyGenTime <= Int64(Date().timeIntervalSince1970) - KEY_GEN_TIME_DELTA || Crypto.counter >= 65535 {
|
||||
(Crypto.cachedExportPublicKey, Crypto.cachedAesKey, Crypto.cachedMacKey) = try getEphemeralSecrets(serverPublicKey)
|
||||
Crypto.keyGenTime = Int64(Date().timeIntervalSince1970)
|
||||
Crypto.counter = 0
|
||||
} else {
|
||||
Crypto.counter += 1
|
||||
}
|
||||
let nonce = withUnsafeBytes(of: Crypto.counter.bigEndian) { Data($0) }
|
||||
return (Crypto.cachedExportPublicKey, Crypto.cachedAesKey, Crypto.cachedMacKey, nonce)
|
||||
}
|
||||
guard let exportPublicKey = cachedExportPublicKey, let aesKey = cachedAESKey, let macKey = cachedMacKey else {
|
||||
throw SecurityError.UnexpectedNilKeys
|
||||
}
|
||||
|
||||
|
||||
// AES ENCRYPT DATA
|
||||
// IV = AES(ctr, iv=null), AES(plaintext, iv=IV) === AES(ctr_with_padding || plaintext, iv=null)
|
||||
// Using the latter construction to reduce key expansions
|
||||
|
||||
// Under PKCS#7 padding, we pad out to a complete blocksize but if the input is an exact multiple of blocksize,
|
||||
// then we add an extra block on. So in both cases it's 16 bytes + (dataLen/16 + 1) * 16 bytes long
|
||||
let outputLen = ((plaintext.count / kCCBlockSizeAES128) + 2) * kCCBlockSizeAES128
|
||||
|
||||
let nullIV = Data(count: 16)
|
||||
var plaintextWithIV = Data(capacity: plaintext.count + 16)
|
||||
plaintextWithIV.append(nonce)
|
||||
plaintextWithIV.append(NONCE_PADDING)
|
||||
plaintextWithIV.append(plaintext)
|
||||
|
||||
var ciphertextWithIV = Data(count: outputLen)
|
||||
var dataWrittenLen = 0
|
||||
let status = ciphertextWithIV.withUnsafeMutableBytes { ciphertextPtr in
|
||||
plaintextWithIV.withUnsafeBytes { plaintextPtr in
|
||||
nullIV.withUnsafeBytes { ivPtr in
|
||||
aesKey.withUnsafeBytes { aesKeyPtr in
|
||||
return CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES), CCOptions(kCCOptionPKCS7Padding),
|
||||
aesKeyPtr.baseAddress, kCCKeySizeAES128, ivPtr.baseAddress,
|
||||
plaintextPtr.baseAddress, plaintextWithIV.count,
|
||||
ciphertextPtr.baseAddress, outputLen,
|
||||
&dataWrittenLen)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
guard status == kCCSuccess else {
|
||||
throw SecurityError.EncryptionFailedError(status)
|
||||
}
|
||||
guard outputLen == dataWrittenLen else {
|
||||
throw SecurityError.EncryptionLengthError
|
||||
}
|
||||
|
||||
let ciphertext = ciphertextWithIV[16...]
|
||||
|
||||
// HMAC
|
||||
var macValue = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
|
||||
var hmacContext = CCHmacContext()
|
||||
macKey.withUnsafeBytes { CCHmacInit(&hmacContext, CCHmacAlgorithm(kCCHmacAlgSHA256), $0.baseAddress, macKey.count) }
|
||||
exportPublicKey.withUnsafeBytes { CCHmacUpdate(&hmacContext, $0.baseAddress, exportPublicKey.count) }
|
||||
nonce.withUnsafeBytes { CCHmacUpdate(&hmacContext, $0.baseAddress, nonce.count) }
|
||||
ciphertext.withUnsafeBytes { CCHmacUpdate(&hmacContext, $0.baseAddress, ciphertext.count) }
|
||||
macValue.withUnsafeMutableBytes { CCHmacFinal(&hmacContext, $0.bindMemory(to: UInt8.self).baseAddress) }
|
||||
|
||||
// Build the final payload: ephemeral public key || nonce || encrypted data || HMAC
|
||||
var finalData = Data(capacity: exportPublicKey.count + ciphertext.count + 18)
|
||||
finalData.append(exportPublicKey)
|
||||
finalData.append(nonce)
|
||||
finalData.append(ciphertext)
|
||||
finalData.append(macValue[..<16])
|
||||
|
||||
return finalData
|
||||
}
|
||||
|
||||
public static func encrypt(dataToEncrypt: Data) throws -> String {
|
||||
guard let publicKey = publicKey else {
|
||||
throw SecurityError.PublicKeyCopyError
|
||||
}
|
||||
let encryptedData = try buildSecretData(publicKey, dataToEncrypt)
|
||||
return encryptedData.base64EncodedString()
|
||||
}
|
||||
}
|
|
@ -117,12 +117,12 @@
|
|||
<action selector="logoutBtn:" destination="dhe-6o-fvJ" eventType="touchUpInside" id="wv7-nj-02U"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EKG-5D-Wyg">
|
||||
<rect key="frame" x="16" y="493" width="155" height="30"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FMQ-oF-sLW">
|
||||
<rect key="frame" x="161" y="59" width="70" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" title="Request Upload PIN"/>
|
||||
<state key="normal" title="Export DB"/>
|
||||
<connections>
|
||||
<action selector="requestUploadOTP:" destination="dhe-6o-fvJ" eventType="touchUpInside" id="C8K-BY-12Z"/>
|
||||
<action selector="dumpDBpressed:" destination="dhe-6o-fvJ" eventType="touchUpInside" id="4VP-XF-A4v"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
|
|
|
@ -15,13 +15,10 @@ extension Encounter {
|
|||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case timestamp
|
||||
case msg
|
||||
case modelC
|
||||
case modelP
|
||||
case rssi
|
||||
case txPower
|
||||
case org
|
||||
case v
|
||||
case localBlob
|
||||
case remoteBlob
|
||||
}
|
||||
|
||||
@nonobjc public class func fetchRequest() -> NSFetchRequest<Encounter> {
|
||||
|
@ -30,24 +27,6 @@ extension Encounter {
|
|||
|
||||
@nonobjc public class func fetchRequestForRecords() -> NSFetchRequest<Encounter> {
|
||||
let fetchRequest = NSFetchRequest<Encounter>(entityName: "Encounter")
|
||||
let predicateString = Encounter.Event
|
||||
.allCases
|
||||
.map { "msg != '\($0.rawValue)'" }
|
||||
.joined(separator: " and ")
|
||||
|
||||
fetchRequest.predicate = NSPredicate(format: predicateString)
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: true)]
|
||||
return fetchRequest
|
||||
}
|
||||
|
||||
@nonobjc public class func fetchRequestForEvents() -> NSFetchRequest<Encounter> {
|
||||
let fetchRequest = NSFetchRequest<Encounter>(entityName: "Encounter")
|
||||
let predicateString = Encounter.Event
|
||||
.allCases
|
||||
.map { "msg = '\($0.rawValue)'" }
|
||||
.joined(separator: " or ")
|
||||
|
||||
fetchRequest.predicate = NSPredicate(format: predicateString)
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: true)]
|
||||
return fetchRequest
|
||||
}
|
||||
|
@ -70,39 +49,33 @@ extension Encounter {
|
|||
}
|
||||
|
||||
@NSManaged public var timestamp: Date?
|
||||
@NSManaged public var msg: String?
|
||||
@NSManaged public var modelC: String?
|
||||
@NSManaged public var modelP: String?
|
||||
@NSManaged public var rssi: NSNumber?
|
||||
@NSManaged public var txPower: NSNumber?
|
||||
@NSManaged public var org: String?
|
||||
@NSManaged public var v: NSNumber?
|
||||
@NSManaged public var localBlob: String?
|
||||
@NSManaged public var remoteBlob: String?
|
||||
|
||||
func set(encounterStruct: EncounterRecord) {
|
||||
func set(encounterStruct: EncounterRecord, remoteBlob: String, localBlob: String) {
|
||||
setValue(encounterStruct.timestamp, forKeyPath: "timestamp")
|
||||
setValue(encounterStruct.msg, forKeyPath: "msg")
|
||||
setValue(encounterStruct.modelC, forKeyPath: "modelC")
|
||||
setValue(encounterStruct.modelP, forKeyPath: "modelP")
|
||||
setValue(encounterStruct.rssi, forKeyPath: "rssi")
|
||||
setValue(encounterStruct.txPower, forKeyPath: "txPower")
|
||||
setValue(encounterStruct.org, forKeyPath: "org")
|
||||
// when we save locally we've already converted v1 messages to encrypted v2 spec, so we save the record as a v2 record
|
||||
if (encounterStruct.v == 1) {
|
||||
setValue(BluetraceConfig.ProtocolVersion, forKeyPath: "v")
|
||||
} else {
|
||||
setValue(encounterStruct.v, forKeyPath: "v")
|
||||
}
|
||||
setValue(remoteBlob, forKey: "remoteBlob")
|
||||
setValue(localBlob, forKey: "localBlob")
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Encodable
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(Int(timestamp!.timeIntervalSince1970), forKey: .timestamp)
|
||||
try container.encode(msg, forKey: .msg)
|
||||
|
||||
if let modelC = modelC, let modelP = modelP {
|
||||
try container.encode(modelC, forKey: .modelC)
|
||||
try container.encode(modelP, forKey: .modelP)
|
||||
try container.encode(rssi?.doubleValue, forKey: .rssi)
|
||||
try container.encode(txPower?.doubleValue, forKey: .txPower)
|
||||
try container.encode(localBlob, forKey: .localBlob)
|
||||
try container.encode(remoteBlob, forKey: .remoteBlob)
|
||||
try container.encode(org, forKey: .org)
|
||||
try container.encode(v?.intValue, forKey: .v)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,8 +12,7 @@ extension EncounterRecord {
|
|||
|
||||
func saveToCoreData() {
|
||||
DispatchQueue.main.async {
|
||||
guard let appDelegate =
|
||||
UIApplication.shared.delegate as? AppDelegate else {
|
||||
guard let persistentContainer = EncounterDB.shared.persistentContainer else {
|
||||
return
|
||||
}
|
||||
let managedContext = appDelegate.persistentContainer.viewContext
|
||||
|
|
|
@ -10,10 +10,7 @@ import CoreData
|
|||
|
||||
extension Encounter {
|
||||
@nonobjc public class func deleteAll() {
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
|
||||
return
|
||||
}
|
||||
appDelegate.persistentContainer.performBackgroundTask { (backgroundContext) in
|
||||
EncounterDB.shared.persistentContainer?.performBackgroundTask { (backgroundContext) in
|
||||
let oldFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Encounter")
|
||||
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: oldFetchRequest)
|
||||
do {
|
||||
|
|
110
CovidSafe/EncounterDB+migration.swift
Normal file
110
CovidSafe/EncounterDB+migration.swift
Normal file
|
@ -0,0 +1,110 @@
|
|||
//
|
||||
// EncounterDB+migration.swift
|
||||
// CovidSafe
|
||||
//
|
||||
// Copyright © 2020 Australian Government. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
protocol EncounterDBMigrationProgress {
|
||||
func migrationBegun()
|
||||
func migrationComplete()
|
||||
func migrationFailed(error: Error)
|
||||
}
|
||||
|
||||
enum MigrationError: Error {
|
||||
case unableToRetrieveSourceModel
|
||||
}
|
||||
|
||||
extension EncounterDB {
|
||||
|
||||
func store(_ storeURL:URL, isCompatibleWithModel model:NSManagedObjectModel) -> Bool {
|
||||
|
||||
do {
|
||||
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: NSSQLiteStoreType, at: storeURL, options: nil)
|
||||
if model.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) {
|
||||
return true
|
||||
}
|
||||
} catch {
|
||||
DLog("ERROR getting metadata from \(storeURL) \(error)")
|
||||
}
|
||||
DLog("The store is NOT compatible with the current version of the model")
|
||||
return false
|
||||
}
|
||||
|
||||
func migrateStoreIfNecessary (storeURL:URL, destinationModel:NSManagedObjectModel) {
|
||||
|
||||
guard FileManager.default.fileExists(atPath: storeURL.path) else {
|
||||
return
|
||||
}
|
||||
|
||||
guard store(storeURL, isCompatibleWithModel: destinationModel) == false else {
|
||||
return
|
||||
}
|
||||
registerBackgroundTask()
|
||||
do {
|
||||
self.migrationDelegate?.migrationBegun()
|
||||
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: NSSQLiteStoreType, at: storeURL, options: nil)
|
||||
if let sourceModel = NSManagedObjectModel.mergedModel(from: [Bundle.main], forStoreMetadata: metadata) {
|
||||
//do the migration, on the background
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
do {
|
||||
DLog("STARTING MIGRATION")
|
||||
try self.migrateStore(store: storeURL, sourceModel: sourceModel, destinationModel: destinationModel)
|
||||
DispatchQueue.main.async {
|
||||
self.endBackgroundTask()
|
||||
self.migrationDelegate?.migrationComplete()
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
self.endBackgroundTask()
|
||||
self.migrationDelegate?.migrationFailed(error: error)
|
||||
}
|
||||
DLog("Failed to migrate")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.endBackgroundTask()
|
||||
self.migrationDelegate?.migrationFailed(error: MigrationError.unableToRetrieveSourceModel)
|
||||
}
|
||||
} catch {
|
||||
endBackgroundTask()
|
||||
self.migrationDelegate?.migrationFailed(error: error)
|
||||
print("FAILED to get metadata \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func migrateStore(store:URL, sourceModel:NSManagedObjectModel, destinationModel:NSManagedObjectModel) throws {
|
||||
let tempdir = store.deletingLastPathComponent()
|
||||
let tempStore = tempdir.appendingPathComponent("temp.sqlite", isDirectory: false)
|
||||
let mappingModel = NSMappingModel(from: nil, forSourceModel: sourceModel, destinationModel: destinationModel)
|
||||
let migrationManager = NSMigrationManager(sourceModel: sourceModel, destinationModel: destinationModel)
|
||||
let options = [NSSQLitePragmasOption: ["journal_mode":"DELETE"]]
|
||||
do {
|
||||
try migrationManager.migrateStore(from: store,
|
||||
sourceType: NSSQLiteStoreType,
|
||||
options: options,
|
||||
with: mappingModel,
|
||||
toDestinationURL: tempStore,
|
||||
destinationType: NSSQLiteStoreType,
|
||||
destinationOptions: nil)
|
||||
let psc = NSPersistentStoreCoordinator(managedObjectModel: sourceModel)
|
||||
try psc.replacePersistentStore(at: store,
|
||||
destinationOptions: nil,
|
||||
withPersistentStoreFrom: tempStore,
|
||||
sourceOptions: nil,
|
||||
ofType: NSSQLiteStoreType)
|
||||
try psc.destroyPersistentStore(at: tempStore, ofType: NSSQLiteStoreType, options: [NSSQLitePragmasOption: ["secure_delete": true]])
|
||||
try FileManager.default.removeItem(at: tempStore)
|
||||
|
||||
DLog("SUCCESSFULLY MIGRATED \(store) to the Current Model")
|
||||
} catch {
|
||||
DLog("FAILED MIGRATION: \(error)")
|
||||
if FileManager.default.fileExists(atPath: tempStore.path) {
|
||||
try FileManager.default.removeItem(at: tempStore)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
75
CovidSafe/EncounterDB.swift
Normal file
75
CovidSafe/EncounterDB.swift
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// EncounterDB.swift
|
||||
// CovidSafe
|
||||
//
|
||||
// Copyright © 2020 Australian Government. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreData
|
||||
|
||||
class EncounterDB {
|
||||
static let shared = EncounterDB()
|
||||
private let modelName = "tracer"
|
||||
private var localStoreUrl: URL?
|
||||
private var _persistentContainer: CovidPersistentContainer?
|
||||
var migrationDelegate: EncounterDBMigrationProgress?
|
||||
var backgroundTask: UIBackgroundTaskIdentifier = .invalid
|
||||
|
||||
|
||||
private lazy var managedObjectModel: NSManagedObjectModel = {
|
||||
guard let modelURL = Bundle.main.url(forResource: self.modelName, withExtension: "momd") else {
|
||||
fatalError("Unable to Find Data Model")
|
||||
}
|
||||
|
||||
guard let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL) else {
|
||||
fatalError("Unable to Load Data Model")
|
||||
}
|
||||
|
||||
return managedObjectModel
|
||||
}()
|
||||
|
||||
public var persistentContainer: CovidPersistentContainer? {
|
||||
get {
|
||||
if let container = _persistentContainer {
|
||||
return container
|
||||
}
|
||||
//check if we need to migrate store first
|
||||
if let localStoreUrl = self.localStoreUrl {
|
||||
if FileManager.default.fileExists(atPath: localStoreUrl.path) &&
|
||||
store(localStoreUrl, isCompatibleWithModel: self.managedObjectModel) == false {
|
||||
return nil // Don't return a store if it's not compatible with the model
|
||||
}
|
||||
}
|
||||
|
||||
let container = CovidPersistentContainer(name: self.modelName)
|
||||
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
|
||||
if let error = error as NSError? {
|
||||
fatalError("Unresolved error \(error), \(error.userInfo)")
|
||||
}
|
||||
})
|
||||
_persistentContainer = container
|
||||
return _persistentContainer
|
||||
}
|
||||
}
|
||||
|
||||
func registerBackgroundTask() {
|
||||
backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
|
||||
self?.endBackgroundTask()
|
||||
}
|
||||
assert(backgroundTask != .invalid)
|
||||
}
|
||||
|
||||
func endBackgroundTask() {
|
||||
if(backgroundTask != .invalid){
|
||||
UIApplication.shared.endBackgroundTask(backgroundTask)
|
||||
backgroundTask = .invalid
|
||||
}
|
||||
}
|
||||
|
||||
func setup(migrationDelegate: EncounterDBMigrationProgress?) {
|
||||
self.migrationDelegate = migrationDelegate
|
||||
self.localStoreUrl = CovidPersistentContainer.defaultDirectoryURL().appendingPathComponent(self.modelName, isDirectory: true).appendingPathExtension("sqlite")
|
||||
migrateStoreIfNecessary(storeURL: self.localStoreUrl!, destinationModel: self.managedObjectModel)
|
||||
}
|
||||
}
|
|
@ -12,7 +12,19 @@ class EncounterMessageManager {
|
|||
}
|
||||
|
||||
var advertisedPayload: Data? {
|
||||
return UserDefaults.standard.data(forKey: userDefaultsAdvtKey)
|
||||
do {
|
||||
let broadcastPayload = EncounterBlob(modelC: nil,
|
||||
rssi: nil,
|
||||
txPower: nil,
|
||||
modelP: DeviceIdentifier.getModel(),
|
||||
msg: tempId)
|
||||
let jsonMsg = try JSONEncoder().encode(broadcastPayload)
|
||||
let encryptedJsonMsg = try Crypto.encrypt(dataToEncrypt: jsonMsg)
|
||||
let peripheralCharStruct = PeripheralCharacteristicsData(modelP: BluetraceConfig.DummyModel, msg: encryptedJsonMsg, org: BluetraceConfig.OrgID, v: BluetraceConfig.ProtocolVersion)
|
||||
return try JSONEncoder().encode(peripheralCharStruct)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// This variable stores the expiry date of the broadcast message. At the same time, we will use this expiry date as the expiry date for the encryted advertisement payload
|
||||
|
@ -29,7 +41,6 @@ class EncounterMessageManager {
|
|||
DLog("No response, Error: \(String(describing: error))")
|
||||
return
|
||||
}
|
||||
_ = self.setAdvertisementPayloadIntoUserDefaults(response)
|
||||
UserDefaults.standard.set(response.tempId, forKey: self.userDefaultsTempIdKey)
|
||||
}
|
||||
}
|
||||
|
@ -72,8 +83,10 @@ class EncounterMessageManager {
|
|||
onComplete(nil)
|
||||
return
|
||||
}
|
||||
UserDefaults.standard.set(response.tempId, forKey: self.userDefaultsTempIdKey)
|
||||
UserDefaults.standard.set(response.expiry, forKey: self.userDefaultsAdvtExpiryKey)
|
||||
|
||||
if let newPayload = self.setAdvertisementPayloadIntoUserDefaults(response) {
|
||||
if let newPayload = self.advertisedPayload {
|
||||
onComplete(newPayload)
|
||||
}
|
||||
onComplete(nil)
|
||||
|
@ -122,18 +135,4 @@ class EncounterMessageManager {
|
|||
onComplete?(nil, (tempId, date))
|
||||
}
|
||||
}
|
||||
|
||||
private func setAdvertisementPayloadIntoUserDefaults(_ response: (tempId: String, expiry: Date)) -> Data? {
|
||||
let peripheralCharStruct = PeripheralCharacteristicsData(modelP: DeviceIdentifier.getModel(), msg: response.tempId, org: BluetraceConfig.OrgID, v: BluetraceConfig.ProtocolVersion)
|
||||
do {
|
||||
let encodedPeriCharStruct = try JSONEncoder().encode(peripheralCharStruct)
|
||||
UserDefaults.standard.set(encodedPeriCharStruct, forKey: self.userDefaultsAdvtKey)
|
||||
UserDefaults.standard.set(response.expiry, forKey: self.userDefaultsAdvtExpiryKey)
|
||||
return encodedPeriCharStruct
|
||||
} catch {
|
||||
DLog("Error: \(error)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,14 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
struct EncounterBlob: Encodable {
|
||||
var modelC: String?
|
||||
var rssi: Double?
|
||||
var txPower: Double?
|
||||
var modelP: String?
|
||||
var msg: String?
|
||||
}
|
||||
|
||||
struct EncounterRecord: Encodable {
|
||||
var timestamp: Date?
|
||||
var msg: String?
|
||||
|
|
91
CovidSafe/EncounterV1toV2.xcmappingmodel/xcmapping.xml
Normal file
91
CovidSafe/EncounterV1toV2.xcmappingmodel/xcmapping.xml
Normal file
File diff suppressed because one or more lines are too long
102
CovidSafe/EncounterV2Mapping.swift
Normal file
102
CovidSafe/EncounterV2Mapping.swift
Normal file
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// EncounterV2Mapping.swift
|
||||
// CovidSafe
|
||||
//
|
||||
// Copyright © 2020 Australian Government. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
struct MigrationRemoteBlob: Encodable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case msg
|
||||
case modelC
|
||||
case modelP
|
||||
case rssi
|
||||
case txPower
|
||||
}
|
||||
var msg: String?
|
||||
var modelC: String?
|
||||
var modelP: String?
|
||||
var rssi: NSNumber?
|
||||
var txPower: NSNumber?
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
if let msg = msg {
|
||||
try container.encode(msg, forKey: .msg)
|
||||
}
|
||||
|
||||
if let modelC = modelC, modelC != BluetraceConfig.DummyModel{
|
||||
try container.encode(modelC, forKey: .modelC)
|
||||
}
|
||||
if let modelP = modelP, modelP != BluetraceConfig.DummyModel {
|
||||
try container.encode(modelP, forKey: .modelP)
|
||||
}
|
||||
if let rssi = rssi, rssi.intValue != BluetraceConfig.DummyRSSI {
|
||||
try container.encode(rssi.doubleValue, forKey: .rssi)
|
||||
}
|
||||
if let txPower = txPower, txPower.intValue != BluetraceConfig.DummyTxPower {
|
||||
try container.encode(txPower.doubleValue, forKey: .txPower)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class EncounterV2Mapping: NSEntityMigrationPolicy {
|
||||
var localEmptyBlob: String = ""
|
||||
override func begin(_ mapping: NSEntityMapping, with manager: NSMigrationManager) throws {
|
||||
try super.begin(mapping, with: manager)
|
||||
let emptyLocal = try JSONEncoder().encode(MigrationRemoteBlob())
|
||||
localEmptyBlob = try Crypto.encrypt(dataToEncrypt: emptyLocal)
|
||||
}
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
|
||||
if (sInstance.entity.name == "Encounter") {
|
||||
guard let version = sInstance.primitiveValue(forKey: "v") as? Int64 else {
|
||||
return
|
||||
}
|
||||
let encounterV2 = NSEntityDescription.insertNewObject(forEntityName: "Encounter", into: manager.destinationContext)
|
||||
let msg = sInstance.primitiveValue(forKey: "msg") as? String
|
||||
let modelC = sInstance.primitiveValue(forKey: "modelC") as? String
|
||||
let modelP = sInstance.primitiveValue(forKey: "modelP") as? String
|
||||
let rssi = sInstance.primitiveValue(forKey: "rssi") as? NSNumber
|
||||
let txPower = sInstance.primitiveValue(forKey: "txPower") as? NSNumber
|
||||
let org = sInstance.primitiveValue(forKey: "org") as? String
|
||||
let timestamp = sInstance.primitiveValue(forKey: "timestamp") as? Date
|
||||
|
||||
|
||||
encounterV2.setPrimitiveValue(org, forKey: "org")
|
||||
encounterV2.setPrimitiveValue(BluetraceConfig.ProtocolVersion, forKey: "v")
|
||||
encounterV2.setPrimitiveValue(timestamp, forKey: "timestamp")
|
||||
do {
|
||||
try autoreleasepool {
|
||||
if version == 1 {
|
||||
//convert a regular old v1 entry
|
||||
encounterV2.setPrimitiveValue(localEmptyBlob, forKey: "localBlob")
|
||||
let remoteBlob = MigrationRemoteBlob(msg: msg, modelC: modelC, modelP: modelP, rssi: rssi, txPower: txPower)
|
||||
|
||||
let blobJson = try JSONEncoder().encode(remoteBlob)
|
||||
let remoteBlobEncrypted = try Crypto.encrypt(dataToEncrypt: blobJson)
|
||||
encounterV2.setPrimitiveValue(remoteBlobEncrypted, forKey: "remoteBlob")
|
||||
manager.associate(sourceInstance: sInstance, withDestinationInstance: encounterV2, for: mapping)
|
||||
|
||||
} else if version == 2 {
|
||||
//convert an entry that was recieved from an already updated app (the msg will already be encrypted)
|
||||
let localMigrationBlob = MigrationRemoteBlob(msg: nil, modelC: modelC, modelP: modelP, rssi: rssi, txPower: txPower)
|
||||
let jsonLocal = try JSONEncoder().encode(localMigrationBlob)
|
||||
let localBlob = try Crypto.encrypt(dataToEncrypt: jsonLocal)
|
||||
encounterV2.setPrimitiveValue(localBlob, forKey: "localBlob")
|
||||
encounterV2.setPrimitiveValue(msg, forKey: "remoteBlob")
|
||||
manager.associate(sourceInstance: sInstance, withDestinationInstance: encounterV2, for: mapping)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
throw(error)
|
||||
}
|
||||
// we're dropping all the debug messages save to the db during the migration as they're unnessecary
|
||||
}
|
||||
}
|
||||
}
|
94
CovidSafe/Feedback/README.md
Normal file
94
CovidSafe/Feedback/README.md
Normal file
|
@ -0,0 +1,94 @@
|
|||
# Feedback
|
||||
|
||||
Provides a way for users or testers to send feedback into your JIRA instance from within the app along with a screenshot.
|
||||
|
||||
## Configuration
|
||||
|
||||
#### JIRA
|
||||
|
||||
JIRA Mobile Connect needs to be enabled on a per project basis, otherwise it will not work with your app. Remember, if you are hosting your own JIRA instance, you will need to install the JIRA Mobile Connect plugin on your server before you can enable it.
|
||||
|
||||
To enable JIRA Mobile Connect for a project:
|
||||
|
||||
1. Navigate to the desired project > **Project Settings**.
|
||||
2. Find the **Settings** section on the page and click **Enable** for the **JIRA Mobile Connect** setting.
|
||||
This will enable the JIRA Mobile Connect plugin for the project, as well as create a user ('jiraconnectuser') in JIRA that is used to create all feedback and crash reports.
|
||||
3. To enable the user to create tickets, you must grant it permission to create issues in the project. To do this, grant the 'Create Issues' permission to the 'jiraconnectuser' user. You can do this by adding the user to a group or project role that has the 'Create Issues' permission or grant the permission to the user directly (see [Managing project permissions](https://confluence.atlassian.com/display/AdminJIRACloud/Managing+project+permissions) for help).
|
||||
|
||||
#### iOS
|
||||
|
||||
Before you can use JIRA Mobile Connect with iOS, you need to identify the JIRA instance that feedback will be sent to. This is done via a JSON file named **JMCTarget**. You'll need to create this **JMCTarget.json** file in your Xcode project and include it in the iOS app's target so it gets bundled with the app.
|
||||
|
||||
1. Right-click your project in Xcode and click **New File...**
|
||||
2. Select **Other** in the **iOS** section and click **Next**.
|
||||
3. In the **Save As** field, type 'JMCTarget.JSON' then select the desired **Targets**.
|
||||
4. Click **Create**.
|
||||
5. Add the following code to your new** JMCTarget.JSON** file. Make sure to replace the values with your own:
|
||||
```
|
||||
{
|
||||
"host": "example-dev.atlassian.net",
|
||||
"projectKey": "EXAMPLEKEY",
|
||||
"apiKey": "myApiKey"
|
||||
}
|
||||
```
|
||||
|
||||
_**Note:** Do not prefix the host with `https://`._
|
||||
|
||||
## Using JIRA Mobile Connect in your app
|
||||
|
||||
### Trigger from the shake-motion event
|
||||
|
||||
The shake-motion event is one of the [motion events](https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/motion_event_basics/motion_event_basics.html#//apple_ref/doc/uid/TP40009541-CH6-SW14) that are detected by the device when it is moved. The following instructions will show you how to trigger a feedback flow (i.e. create a JIRA issue) in your app when the user shakes the device.
|
||||
|
||||
_Note that as of iOS 10, `motionEnded` is no longer called on the `AppDelegate`, so you must override `motionEnded` on a `UIResponder` (subclass `UIWindow` or use a top-level view controller)._
|
||||
|
||||
Wherever you choose to override `motionEnded`, add the following:
|
||||
|
||||
```swift
|
||||
override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) {
|
||||
do {
|
||||
let settings = try FeedbackSettings()
|
||||
<WINDOW>.presentFeedbackIfShakeMotion(motion, promptUser: false, settings: settings)
|
||||
} catch {
|
||||
preconditionFailure("Error retrieving feedback settings: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Programmatic trigger
|
||||
|
||||
You can also trigger a feedback flow in your app from other events, for example, a button that is tapped in the app. This section shows you how to implement this.
|
||||
|
||||
Call `presentFeedback()` on any view controller to present feedback:
|
||||
|
||||
```swift
|
||||
do {
|
||||
let feedbackSettings = try FeedbackSettings()
|
||||
currentViewController.presentFeedback(true, settings: feedbackSettings)
|
||||
} catch {
|
||||
preconditionFailure("Error retrieving feedback settings: \(error.localizedDescription)")
|
||||
}
|
||||
```
|
||||
|
||||
### Additional Configuration
|
||||
|
||||
##### Action sheet prompt
|
||||
|
||||
To present an action sheet prompt before taking the user to the feedback flow, set **`promptUser`** to true.
|
||||
|
||||
```swift
|
||||
// Shake Motion
|
||||
<WINDOW>.presentFeedbackIfShakeMotion(motion, promptUser: true, settings: settings)
|
||||
|
||||
// Programmatic
|
||||
currentViewController.presentFeedback(true, settings: feedbackSettings)
|
||||
```
|
||||
|
||||
##### Reporter details
|
||||
|
||||
To pass a string to identify who is sending the feedback, set **`reporterUsernameOrEmail`** to the reporter's Id string.
|
||||
_**Important**: The current version does not let the user know their ID is being sent. You may want to only use this feature for non-Appstore builds. To do this, just set reporterUsernameOrEmail to `nil` for release builds._
|
||||
|
||||
```swift
|
||||
let settings = try FeedbackSettings(reporterUsernameOrEmail: "someone@example.com")
|
||||
```
|
|
@ -14,7 +14,6 @@ class HomeViewController: UIViewController {
|
|||
@IBOutlet weak var homeHeaderInfoText: UILabel!
|
||||
@IBOutlet weak var homeHeaderPermissionsOffImage: UIImageView!
|
||||
@IBOutlet weak var shareView: UIView!
|
||||
@IBOutlet weak var thanksForTheHelp: UIView!
|
||||
@IBOutlet weak var appPermissionsLabel: UIView!
|
||||
@IBOutlet weak var animatedBluetoothHeader: UIView!
|
||||
@IBOutlet weak var versionNumberLabel: UILabel!
|
||||
|
@ -25,6 +24,7 @@ class HomeViewController: UIViewController {
|
|||
@IBOutlet weak var pushNotificationStatusTitle: UILabel!
|
||||
@IBOutlet weak var pushNotificationStatusIcon: UIImageView!
|
||||
@IBOutlet weak var pushNotificationStatusLabel: UILabel!
|
||||
@IBOutlet weak var uploadDateLabel: UILabel!
|
||||
|
||||
var lottieBluetoothView: AnimationView!
|
||||
|
||||
|
@ -35,13 +35,31 @@ class HomeViewController: UIViewController {
|
|||
var didUploadData: Bool {
|
||||
let uploadTimestamp = UserDefaults.standard.double(forKey: "uploadDataDate")
|
||||
let lastUpload = Date(timeIntervalSince1970: uploadTimestamp)
|
||||
return Date().timeIntervalSince(lastUpload) < 86400 * 21
|
||||
return Date().timeIntervalSince(lastUpload) < 86400 * 14
|
||||
}
|
||||
var shouldShowEndOfIsolationScreen: Bool {
|
||||
let uploadTimestamp = UserDefaults.standard.double(forKey: "firstUploadDataDate")
|
||||
var dataUploadedAttributedString: NSAttributedString? {
|
||||
let uploadTimestamp = UserDefaults.standard.double(forKey: "uploadDataDate")
|
||||
if(uploadTimestamp > 0){
|
||||
let lastUpload = Date(timeIntervalSince1970: uploadTimestamp)
|
||||
return Date().timeIntervalSince(lastUpload) >= 86400 * 21
|
||||
let dateFormatterPrint = DateFormatter()
|
||||
dateFormatterPrint.dateFormat = "dd MMM yyyy"
|
||||
let formattedDate = dateFormatterPrint.string(from: lastUpload)
|
||||
let newAttributedString = NSMutableAttributedString(string: "Your information was uploaded on \(formattedDate).")
|
||||
|
||||
guard let dateRange = newAttributedString.string.range(of: formattedDate) else { return nil }
|
||||
let nsRange = NSRange(dateRange, in: newAttributedString.string)
|
||||
newAttributedString.addAttribute(.font,
|
||||
value: UIFont.boldSystemFont(ofSize: 18),
|
||||
range: nsRange)
|
||||
return newAttributedString
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var shouldShowUploadDate: Bool {
|
||||
let uploadTimestamp = UserDefaults.standard.double(forKey: "uploadDataDate")
|
||||
if(uploadTimestamp > 0){
|
||||
let lastUpload = Date(timeIntervalSince1970: uploadTimestamp)
|
||||
return Date().timeIntervalSince(lastUpload) <= 86400 * 14
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -67,6 +85,7 @@ class HomeViewController: UIViewController {
|
|||
NotificationCenter.default.addObserver(self, selector: #selector(enableUserInteraction(_:)), name: .enableUserInteraction, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(appWillResignActive(_:)), name: UIApplication.willResignActiveNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
|
||||
if let versionNumber = Bundle.main.versionShort, let buildNumber = Bundle.main.version {
|
||||
self.versionNumberLabel.text = "Version number: \(versionNumber) Build: \(buildNumber)"
|
||||
} else {
|
||||
|
@ -89,10 +108,6 @@ class HomeViewController: UIViewController {
|
|||
super.viewDidAppear(animated)
|
||||
self.lottieBluetoothView?.play()
|
||||
self.becomeFirstResponder()
|
||||
|
||||
if(shouldShowEndOfIsolationScreen){
|
||||
self.performSegue(withIdentifier: "IsolationSuccessSegue", sender: self)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
|
@ -133,11 +148,21 @@ class HomeViewController: UIViewController {
|
|||
self?.toggleBluetoothPermissionStatusView()
|
||||
self?.toggleHeaderView()
|
||||
self?.toggleUploadView()
|
||||
self?.toggleUploadDateView()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func toggleUploadDateView() {
|
||||
if shouldShowUploadDate, let lastUploadText = self.dataUploadedAttributedString {
|
||||
uploadDateLabel.attributedText = lastUploadText
|
||||
uploadDateLabel.isHidden = false
|
||||
} else {
|
||||
uploadDateLabel.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func readPermissions(notificationSettings: UNNotificationSettings) {
|
||||
self.bluetoothStatusOn = BluetraceManager.shared.isBluetoothOn()
|
||||
self.bluetoothPermissionOn = BluetraceManager.shared.isBluetoothAuthorized()
|
||||
|
@ -169,15 +194,9 @@ class HomeViewController: UIViewController {
|
|||
fileprivate func toggleHeaderView() {
|
||||
self.allPermissionOn ? self.lottieBluetoothView?.play() : self.lottieBluetoothView?.stop()
|
||||
toggleViewVisibility(view: appPermissionsLabel, isVisible: !self.allPermissionOn)
|
||||
toggleViewVisibility(view: thanksForTheHelp, isVisible: self.allPermissionOn && self.didUploadData)
|
||||
toggleViewVisibility(view: homeHeaderPermissionsOffImage, isVisible: !self.allPermissionOn)
|
||||
toggleViewVisibility(view: lottieBluetoothView, isVisible: self.allPermissionOn)
|
||||
|
||||
if (self.allPermissionOn && self.didUploadData) {
|
||||
self.homeHeaderInfoText.textColor = UIColor.white
|
||||
} else {
|
||||
self.homeHeaderInfoText.textColor = UIColor(0x131313)
|
||||
}
|
||||
self.helpButton.setImage(UIImage(named: "ic-help-selected"), for: .normal)
|
||||
self.helpButton.setTitleColor(UIColor.black, for: .normal)
|
||||
|
||||
|
@ -187,12 +206,6 @@ class HomeViewController: UIViewController {
|
|||
if (!self.allPermissionOn) {
|
||||
self.homeHeaderInfoText.text = "COVIDSafe is not active.\nCheck your permissions."
|
||||
self.homeHeaderView.backgroundColor = UIColor.covidHomePermissionErrorColor
|
||||
} else if (self.didUploadData) {
|
||||
self.helpButton.setImage(UIImage(named: "ic-help"), for: .normal)
|
||||
self.helpButton.setTitleColor(UIColor.white, for: .normal)
|
||||
self.homeHeaderInfoText.font = UIFont.systemFont(ofSize: 18, weight: .bold)
|
||||
self.homeHeaderView.backgroundColor = UIColor.covidSafeButtonDarkerColor
|
||||
updateAnimationViewWithAnimationName(name: "Spinner_home_upload_complete")
|
||||
} else {
|
||||
self.homeHeaderView.backgroundColor = UIColor.covidHomeActiveColor
|
||||
updateAnimationViewWithAnimationName(name: "Spinner_home")
|
||||
|
@ -279,6 +292,15 @@ class HomeViewController: UIViewController {
|
|||
present(safariVC, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func bluetoothPairingTapped(_ sender: Any) {
|
||||
guard let url = URL(string: "https://www.covidsafe.gov.au/help-topics.html#bluetooth-pairing-request") else {
|
||||
return
|
||||
}
|
||||
|
||||
let safariVC = SFSafariViewController(url: url)
|
||||
present(safariVC, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func onPositiveButtonTapped(_ sender: UITapGestureRecognizer) {
|
||||
guard let helpVC = UIStoryboard(name: "UploadData", bundle: nil).instantiateInitialViewController() else {
|
||||
return
|
||||
|
|
|
@ -54,15 +54,16 @@ final class InfoViewController: UIViewController {
|
|||
}
|
||||
|
||||
func fetchDevicesEncounteredCount() {
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
|
||||
guard let persistentContainer =
|
||||
EncounterDB.shared.persistentContainer else {
|
||||
return
|
||||
}
|
||||
let managedContext = appDelegate.persistentContainer.viewContext
|
||||
let managedContext = persistentContainer.viewContext
|
||||
let fetchRequest = Encounter.fetchRequestForRecords()
|
||||
|
||||
do {
|
||||
let devicesEncountered = try managedContext.fetch(fetchRequest)
|
||||
let uniqueIDs = Set(devicesEncountered.map { $0.msg })
|
||||
let uniqueIDs = Set(devicesEncountered.map { $0.timestamp })
|
||||
self.devicesEncounteredLabel.text = String(uniqueIDs.count)
|
||||
} catch let error as NSError {
|
||||
print("Could not fetch. \(error), \(error.userInfo)")
|
||||
|
@ -79,12 +80,29 @@ final class InfoViewController: UIViewController {
|
|||
BluetraceManager.shared.toggleScanning(mySwitch.isOn)
|
||||
}
|
||||
|
||||
@IBAction func dumpDBpressed(_ sender: UIButton) {
|
||||
var activityItems: [Any] = []
|
||||
let localStoreUrl = CovidPersistentContainer.defaultDirectoryURL().appendingPathComponent("tracer", isDirectory: false).appendingPathExtension("sqlite")
|
||||
activityItems.append(localStoreUrl)
|
||||
let localStoreUrlshm = CovidPersistentContainer.defaultDirectoryURL().appendingPathComponent("tracer", isDirectory: false).appendingPathExtension("sqlite-shm")
|
||||
if FileManager.default.fileExists(atPath: localStoreUrlshm.path) {
|
||||
activityItems.append(localStoreUrlshm)
|
||||
}
|
||||
let localStoreUrlwal = CovidPersistentContainer.defaultDirectoryURL().appendingPathComponent("tracer", isDirectory: false).appendingPathExtension("sqlite-wal")
|
||||
if FileManager.default.fileExists(atPath: localStoreUrlwal.path) {
|
||||
activityItems.append(localStoreUrlwal)
|
||||
}
|
||||
let activity = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
|
||||
present(activity, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
func clearLogsButtonClicked() {
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
|
||||
guard let persistentContainer =
|
||||
EncounterDB.shared.persistentContainer else {
|
||||
return
|
||||
}
|
||||
let managedContext = appDelegate.persistentContainer.viewContext
|
||||
let managedContext = persistentContainer.viewContext
|
||||
let fetchRequest = NSFetchRequest<Encounter>(entityName: "Encounter")
|
||||
fetchRequest.includesPropertyValues = false
|
||||
do {
|
||||
|
|
|
@ -8,14 +8,17 @@
|
|||
import UIKit
|
||||
import KeychainSwift
|
||||
|
||||
class InitialScreenViewController: UIViewController {
|
||||
class InitialScreenViewController: UIViewController, EncounterDBMigrationProgress {
|
||||
|
||||
let displayTimeSeconds: Int = 4
|
||||
let displayTimeSeconds = 4.0
|
||||
let giveupTimeSeconds = 8.0
|
||||
var migrationStart: Date?
|
||||
var isKeychainAvailable = false
|
||||
var isDisplayTimeElapsed = false
|
||||
let keychain = KeychainSwift()
|
||||
var giveupTimer: Timer?
|
||||
var initialDelayTimer: Timer?
|
||||
var migrationViewController: UIViewController?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
@ -27,23 +30,26 @@ class InitialScreenViewController: UIViewController {
|
|||
NotificationCenter.default.addObserver(self, selector: #selector(setKeychainAvailable(_:)), name: UIApplication.protectedDataDidBecomeAvailableNotification, object: nil)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
view.window?.tintColor = .covidSafeColor
|
||||
|
||||
let showAppDelay = DispatchTime.now() + .seconds(displayTimeSeconds)
|
||||
DispatchQueue.main.asyncAfter(deadline: showAppDelay, execute: {
|
||||
continueAfterDelay(delay: displayTimeSeconds)
|
||||
// add give up action in case the keychain notification in not received after 8 seconds
|
||||
giveupTimer = Timer.scheduledTimer(withTimeInterval: giveupTimeSeconds, repeats: false) { timer in
|
||||
self.performSegue(withIdentifier: "initialPersonalDetailsSegue", sender: self)
|
||||
}
|
||||
EncounterDB.shared.setup(migrationDelegate: self)
|
||||
}
|
||||
|
||||
func continueAfterDelay(delay: TimeInterval) {
|
||||
initialDelayTimer = Timer.scheduledTimer(withTimeInterval: delay,
|
||||
repeats: false,
|
||||
block: { (_) in
|
||||
self.isDisplayTimeElapsed = true
|
||||
if(self.proceedWithChecks()) {
|
||||
self.performCheck()
|
||||
}
|
||||
})
|
||||
// add give up action in case the keychain notification in not received after 8 seconds
|
||||
giveupTimer = Timer.scheduledTimer(withTimeInterval: giveupTimeSeconds, repeats: false) { timer in
|
||||
self.performSegue(withIdentifier: "initialPersonalDetailsSegue", sender: self)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -61,9 +67,12 @@ class InitialScreenViewController: UIViewController {
|
|||
|
||||
private func performCheck() {
|
||||
giveupTimer?.invalidate()
|
||||
initialDelayTimer?.invalidate()
|
||||
if let migrationVc = migrationViewController {
|
||||
migrationVc.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
let isLoggedIn: Bool = (keychain.get("JWT_TOKEN") != nil)
|
||||
if !UserDefaults.standard.bool(forKey: "completedIWantToHelp") {
|
||||
// old app signed out here
|
||||
keychain.delete("JWT_TOKEN")
|
||||
self.performSegue(withIdentifier: "initialScreenToIWantToHelpSegue", sender: self)
|
||||
} else if !UserDefaults.standard.bool(forKey: "hasConsented") {
|
||||
|
@ -72,10 +81,40 @@ class InitialScreenViewController: UIViewController {
|
|||
self.performSegue(withIdentifier: "initialPersonalDetailsSegue", sender: self)
|
||||
} else if !UserDefaults.standard.bool(forKey: "allowedPermissions") {
|
||||
self.performSegue(withIdentifier: "initialScreenToAllowPermissionsSegue", sender: self)
|
||||
} else if !UserDefaults.standard.bool(forKey: "turnedOnBluetooth") {
|
||||
self.performSegue(withIdentifier: "initialScreenToTurnOnBtSegue", sender: self)
|
||||
} else {
|
||||
self.performSegue(withIdentifier: "initialScreenToHomeSegue", sender: self)
|
||||
}
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == "presentMigrationSegue" {
|
||||
migrationViewController = segue.destination
|
||||
}
|
||||
}
|
||||
|
||||
func migrationBegun() {
|
||||
DLog("MIGRATION BEGUN")
|
||||
giveupTimer?.invalidate()
|
||||
initialDelayTimer?.invalidate()
|
||||
migrationStart = Date()
|
||||
performSegue(withIdentifier: "presentMigrationSegue", sender: nil)
|
||||
}
|
||||
|
||||
func migrationComplete() {
|
||||
DLog("MIGRATION COMPLETE")
|
||||
if let migrationStart = migrationStart {
|
||||
let migrationDuration = abs(migrationStart.timeIntervalSinceNow)
|
||||
if migrationDuration > displayTimeSeconds {
|
||||
performCheck()
|
||||
} else {
|
||||
// migration was quick, still need to delay minimum 4 seconds
|
||||
DLog("Migration too quick, waiting \(displayTimeSeconds - migrationDuration) seconds")
|
||||
continueAfterDelay(delay: displayTimeSeconds - migrationDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func migrationFailed(error: Error) {
|
||||
fatalError("Migration Failed \(error)")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,11 @@ final class LogViewController: UIViewController {
|
|||
}
|
||||
|
||||
func fetchEncounters() {
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
|
||||
guard let persistentContainer =
|
||||
EncounterDB.shared.persistentContainer else {
|
||||
return
|
||||
}
|
||||
let managedContext = appDelegate.persistentContainer.viewContext
|
||||
let managedContext = persistentContainer.viewContext
|
||||
let fetchRequest = NSFetchRequest<Encounter>(entityName: "Encounter")
|
||||
let sortByDate = NSSortDescriptor(key: "timestamp", ascending: false)
|
||||
fetchRequest.sortDescriptors = [sortByDate]
|
||||
|
@ -62,26 +63,23 @@ extension LogViewController: UITableViewDataSource {
|
|||
return
|
||||
}
|
||||
let datetime = encounter.timestamp
|
||||
let msg = encounter.msg
|
||||
// let msg = encounter.msg
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.timeStyle = .medium
|
||||
let timeString = "\(datetime == nil ? "<NONE>" : dateFormatter.string(from: datetime!))"
|
||||
|
||||
if let rawMessage = encounter.msg, let event = Encounter.Event(rawValue: rawMessage) {
|
||||
cell.textLabel?.text = "\(timeString) - \(event.rawValue)"
|
||||
} else {
|
||||
// if let rawMessage = encounter.msg, let event = Encounter.Event(rawValue: rawMessage) {
|
||||
// cell.textLabel?.text = "\(timeString) - \(event.rawValue)"
|
||||
// } else {
|
||||
cell.textLabel?.text = """
|
||||
\(timeString)
|
||||
msg: \(msg ?? "<MISSING>")
|
||||
modelC: \(encounter.modelC != nil ? "\(encounter.modelC!)" : "nil")
|
||||
modelP: \(encounter.modelP != nil ? "\(encounter.modelP!)" : "nil")
|
||||
RSSI: \(encounter.rssi != nil ? "\(encounter.rssi!)" : "nil")
|
||||
txPower: \(encounter.txPower != nil ? "\(encounter.txPower!)" : "nil")
|
||||
org: \(encounter.org != nil ? "\(encounter.org!)" : "nil")
|
||||
v: \(encounter.v != nil ? "\(encounter.v!)" : "nil")
|
||||
remoteBlob: \(encounter.remoteBlob ?? "nil")
|
||||
localBlob: \(encounter.localBlob ?? "nil")
|
||||
"""
|
||||
cell.textLabel?.numberOfLines = 0
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
22
CovidSafe/MigrationViewController.swift
Normal file
22
CovidSafe/MigrationViewController.swift
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// MigrationViewController.swift
|
||||
// CovidSafe
|
||||
//
|
||||
// Copyright © 2020 Australian Government. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Lottie
|
||||
|
||||
class MigrationViewController: UIViewController {
|
||||
@IBOutlet weak var animationContainer: UIView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
let migrationAnimation = AnimationView(name: "spinner_migrating_db")
|
||||
migrationAnimation.loopMode = .loop
|
||||
migrationAnimation.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: self.animationContainer.frame.size)
|
||||
self.animationContainer.addSubview(migrationAnimation)
|
||||
migrationAnimation.play()
|
||||
}
|
||||
}
|
|
@ -237,8 +237,6 @@ class OTPViewController: UIViewController, RegistrationHandler {
|
|||
}
|
||||
if !UserDefaults.standard.bool(forKey: "allowedPermissions") {
|
||||
viewController.performSegue(withIdentifier: "showAllowPermissionsFromOTPSegue", sender: self)
|
||||
} else if !UserDefaults.standard.bool(forKey: "turnedOnBluetooth") {
|
||||
self.performSegue(withIdentifier: "OTPToTurnOnBtSegue", sender: self)
|
||||
} else {
|
||||
self.performSegue(withIdentifier: "OTPToHomeSegue", sender: self)
|
||||
}
|
||||
|
|
|
@ -20,8 +20,10 @@ public class PeripheralController: NSObject {
|
|||
}
|
||||
|
||||
var didUpdateState: ((String) -> Void)?
|
||||
private let encounteredCentralExpiryTime:TimeInterval = 1800.0 // 30 minutes
|
||||
private let restoreIdentifierKey = "com.joelkek.tracer.peripheral"
|
||||
private let peripheralName: String
|
||||
private var encounteredCentrals = [UUID: (EncounterRecord)]()
|
||||
|
||||
private var characteristicData: PeripheralCharacteristicsData
|
||||
|
||||
|
@ -99,7 +101,13 @@ extension PeripheralController: CBPeripheralManagerDelegate {
|
|||
if let characteristicValue = request.value {
|
||||
let dataFromCentral = try JSONDecoder().decode(CentralWriteData.self, from: characteristicValue)
|
||||
let encounter = EncounterRecord(from: dataFromCentral)
|
||||
encounter.saveToCoreData()
|
||||
if (shouldRecordEncounterWithCentral(request.central)) {
|
||||
try encounter.saveRemoteCentralToCoreData()
|
||||
encounteredCentrals.updateValue(encounter, forKey: request.central.identifier)
|
||||
removeOldEncounters()
|
||||
} else {
|
||||
DLog("Encounterd central too recently, not recording")
|
||||
}
|
||||
}
|
||||
}
|
||||
peripheral.respond(to: requests[0], withResult: .success)
|
||||
|
@ -107,6 +115,28 @@ extension PeripheralController: CBPeripheralManagerDelegate {
|
|||
DLog("Error: \(error)")
|
||||
peripheral.respond(to: requests[0], withResult: .unlikelyError)
|
||||
}
|
||||
}
|
||||
|
||||
private func removeOldEncounters() {
|
||||
encounteredCentrals = encounteredCentrals.filter { (uuid, encounter) -> Bool in
|
||||
guard let encDate = encounter.timestamp else {
|
||||
return true
|
||||
}
|
||||
return abs(encDate.timeIntervalSinceNow) < encounteredCentralExpiryTime
|
||||
}
|
||||
}
|
||||
|
||||
private func shouldRecordEncounterWithCentral(_ central: CBCentral) -> Bool {
|
||||
guard let previousEncounter = encounteredCentrals[central.identifier] else {
|
||||
return true
|
||||
}
|
||||
guard let lastEncDate = previousEncounter.timestamp else {
|
||||
return true
|
||||
}
|
||||
|
||||
if abs(lastEncDate.timeIntervalSinceNow) > BluetraceConfig.CentralScanInterval {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ struct PushNotificationConstants {
|
|||
// Bluetooth Status
|
||||
static let btStatusPushNotifContents = [
|
||||
[
|
||||
"contentTitle": "Turned Bluetooth off by mistake?",
|
||||
"contentBody": "Help stop the spread of COVID-19 by keeping your phone’s Bluetooth on until the outbreak is over."
|
||||
"contentTitle": "COVIDSafe is currently inactive",
|
||||
"contentBody": "Make sure it's active before you leave home and when in public places by enabling Bluetooth®"
|
||||
]
|
||||
]
|
||||
|
||||
|
|
67
CovidSafe/SecKey+CovidSafe.swift
Normal file
67
CovidSafe/SecKey+CovidSafe.swift
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// SecKey+CovidSafe.swift
|
||||
// CovidSafe
|
||||
//
|
||||
// Copyright © 2020 Australian Government. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension SecKey {
|
||||
enum SecKeyError: Error {
|
||||
case UnableToInspectAttributesError
|
||||
case UnsupportedKeyTypeError
|
||||
case InvalidUncompressedRepresentationError
|
||||
}
|
||||
|
||||
/**
|
||||
Copy the compressed elliptic-curve public key representation as defined in
|
||||
section 4.3.6 of ANSI X9.62.
|
||||
|
||||
- Throws:
|
||||
- `SecKeyError.UnableToInspectAttributesError`: if `SecKeyCopyAttributes()` fails on the key
|
||||
- `SecKeyError.UnsupportedKeyTypeError`: if the key isn't of type `kSecAttrKeyTypeECSECPrimeRandom`
|
||||
- `SecKeyError.InvalidUncompressedRepresentationError`: if parsing the uncompressed representation
|
||||
of the key failed (from `SecKeyCopyExternalRepresentation()`)
|
||||
|
||||
- Returns: Data with 1 + key size bytes, representing the public key
|
||||
*/
|
||||
func CopyCompressedECPublicKey() throws -> Data {
|
||||
// Validate the key is of EC type
|
||||
guard let attributes = SecKeyCopyAttributes(self) as? [CFString: AnyObject] else {
|
||||
throw SecKeyError.UnableToInspectAttributesError
|
||||
}
|
||||
guard attributes[kSecAttrKeyType] as! CFNumber == kSecAttrKeyTypeECSECPrimeRandom else {
|
||||
throw SecKeyError.UnsupportedKeyTypeError
|
||||
}
|
||||
// Get key size in bytes
|
||||
let keySize = Int(truncating: attributes[kSecAttrKeySizeInBits] as! CFNumber) / 8
|
||||
|
||||
// Get the uncompressed key representation
|
||||
var err: Unmanaged<CFError>?
|
||||
guard let uncompressed = SecKeyCopyExternalRepresentation(self, &err) as Data? else {
|
||||
throw err!.takeRetainedValue() as Error
|
||||
}
|
||||
// Uncompressed begins with 0x04 per section 4.3.6 of X9.62
|
||||
guard uncompressed[0] == 4 else {
|
||||
throw SecKeyError.InvalidUncompressedRepresentationError
|
||||
}
|
||||
// Uncompressed public key will be 1 + keysize * 2, private has K appended to public
|
||||
guard uncompressed.count >= 1 + keySize * 2 else {
|
||||
throw SecKeyError.InvalidUncompressedRepresentationError
|
||||
}
|
||||
|
||||
// To compress, take the X coordinate
|
||||
let x = uncompressed[1...keySize]
|
||||
// And determine whether Y coordinate is odd or even
|
||||
let y_lsb = uncompressed[keySize*2] & 1
|
||||
|
||||
// Compressed format is PC || X_1
|
||||
var compressed = Data(capacity: 1 + keySize)
|
||||
// PC: 0x02 if even, 0x03 if odd
|
||||
compressed.append(2 | y_lsb)
|
||||
compressed.append(x)
|
||||
|
||||
return compressed
|
||||
}
|
||||
}
|
|
@ -13,11 +13,12 @@ final class UploadHelper {
|
|||
|
||||
public static func uploadEncounterData(pin: String?, _ result: @escaping (UploadResult) -> Void) {
|
||||
let keychain = KeychainSwift()
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
|
||||
|
||||
guard let managedContext = EncounterDB.shared.persistentContainer?.viewContext else {
|
||||
result(.Failed)
|
||||
return
|
||||
}
|
||||
|
||||
let managedContext = appDelegate.persistentContainer.viewContext
|
||||
|
||||
let recordsFetchRequest: NSFetchRequest<Encounter> = Encounter.fetchRequestForRecords()
|
||||
|
||||
|
|
5514
CovidSafe/spinner_migrating_db.json
Normal file
5514
CovidSafe/spinner_migrating_db.json
Normal file
File diff suppressed because it is too large
Load diff
16
CovidSafe/tracer.xcdatamodeld/ModelV2.xcdatamodel/contents
Normal file
16
CovidSafe/tracer.xcdatamodeld/ModelV2.xcdatamodel/contents
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19E266" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Encounter" representedClassName="Encounter" syncable="YES">
|
||||
<attribute name="localBlob" optional="YES" attributeType="String"/>
|
||||
<attribute name="org" optional="YES" attributeType="String"/>
|
||||
<attribute name="remoteBlob" optional="YES" attributeType="String"/>
|
||||
<attribute name="timestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="v" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<fetchedProperty name="fetchedProperty" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="Encounter"/>
|
||||
</fetchedProperty>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Encounter" positionX="-63" positionY="-18" width="128" height="146"/>
|
||||
</elements>
|
||||
</model>
|
|
@ -19,6 +19,6 @@ SPEC CHECKSUMS:
|
|||
KeychainSwift: a06190cf933ad46b1e0abc3d77d29c06331715c7
|
||||
lottie-ios: 85ce835dd8c53e02509f20729fc7d6a4e6645a0a
|
||||
|
||||
PODFILE CHECKSUM: 8bc87fadafd4dd4f9d03ad3edbfbd84d778c1b19
|
||||
PODFILE CHECKSUM: 267f7fcda5f8a86683b76b362dfc6c6703e3033f
|
||||
|
||||
COCOAPODS: 1.9.1
|
||||
|
|
Loading…
Reference in a new issue