From f14aa60482df05669e3f8389de5b6259454b6805 Mon Sep 17 00:00:00 2001 From: COVIDSafe Support <64945427+covidsafe-support@users.noreply.github.com> Date: Tue, 2 Feb 2021 11:04:43 +1100 Subject: [PATCH] COVIDSafe code from version 2.2 (#42) --- CovidSafe.xcodeproj/project.pbxproj | 90 ++++- CovidSafe/API/ChangePostcodeAPI.swift | 58 ++++ CovidSafe/API/DataUploadS3.swift | 8 +- CovidSafe/API/InitiateUploadAPI.swift | 30 +- CovidSafe/API/StatisticsAPI.swift | 36 +- CovidSafe/AppSettingsViewController.swift | 2 +- .../CovidSafe/activity.imageset/Contents.json | 12 + .../activity.imageset/activity 1.pdf | 127 +++++++ .../alert-triangle.imageset/Contents.json | 12 + .../alert-triangle 1.pdf | 228 +++++++++++++ .../check-green.imageset/Contents.json | 12 + .../check-green.imageset/check 1.pdf | 92 ++++++ .../external-link.imageset/Contents.json | 12 + .../external-link 1.pdf | 198 +++++++++++ .../CovidSafe/home.imageset/Contents.json | 12 + .../CovidSafe/home.imageset/home.pdf | 182 +++++++++++ .../CovidSafe/map-pin.imageset/Contents.json | 12 + .../CovidSafe/map-pin.imageset/map-pin 1.pdf | 251 ++++++++++++++ CovidSafe/Base.lproj/Main.storyboard | 24 +- CovidSafe/Base.lproj/UploadData.storyboard | 128 +++++--- CovidSafe/CSGenericContentView.xib | 6 +- CovidSafe/ChangePostcodeViewController.swift | 186 +++++++++++ CovidSafe/ChangePostcodeViewController.xib | 197 +++++++++++ CovidSafe/CovidStatisticsViewController.swift | 309 +++++++++++++----- CovidSafe/Encounter+CoreDataProperties.swift | 17 + CovidSafe/EncounterMessageManager.swift | 7 +- CovidSafe/ExternalLinkTableViewCell.swift | 26 ++ CovidSafe/ExternalLinkTableViewCell.xib | 84 +++++ CovidSafe/Herald/Sensor/BLE/BLEDatabase.swift | 4 +- CovidSafe/Herald/Sensor/BLE/BLEReceiver.swift | 35 +- .../Herald/Sensor/BLE/BLETransmitter.swift | 28 +- CovidSafe/HomeView.xib | 28 +- CovidSafe/HomeViewController.swift | 43 +-- CovidSafe/MainStatisticsHeader.xib | 51 ++- CovidSafe/PrivacyPolicyViewController.swift | 2 +- .../RegistrationSuccessViewController.swift | 3 + .../SelectStateTerritoryViewController.swift | 152 +++++++++ .../SelectStateTerritoryViewController.xib | 35 ++ CovidSafe/SettingsView.xib | 148 ++++++++- CovidSafe/SettingsViewController.swift | 6 + CovidSafe/StateTerritoryTableViewCell.swift | 24 ++ CovidSafe/StateTerritoryTableViewCell.xib | 56 ++++ CovidSafe/String+Localization.swift | 2 +- CovidSafe/URLHelper.swift | 9 + CovidSafe/UploadDataErrorViewController.swift | 12 +- CovidSafe/UploadDataStep2VC.swift | 36 +- CovidSafe/UploadHelper.swift | 30 +- CovidSafe/ar.lproj/InfoPlist.strings | 3 + CovidSafe/ar.lproj/Localizable.strings | 94 +++++- CovidSafe/el.lproj/InfoPlist.strings | 5 +- CovidSafe/el.lproj/Localizable.strings | 140 ++++++-- CovidSafe/en.lproj/InfoPlist.strings | 6 +- CovidSafe/en.lproj/Localizable.strings | 80 ++++- CovidSafe/it.lproj/InfoPlist.strings | 7 +- CovidSafe/it.lproj/Localizable.strings | 130 ++++++-- CovidSafe/ko.lproj/InfoPlist.strings | 3 + CovidSafe/ko.lproj/Localizable.strings | 94 +++++- CovidSafe/pa-IN.lproj/InfoPlist.strings | 3 + CovidSafe/pa-IN.lproj/Localizable.strings | 94 +++++- CovidSafe/tr.lproj/InfoPlist.strings | 3 + CovidSafe/tr.lproj/Localizable.strings | 94 +++++- CovidSafe/vi.lproj/InfoPlist.strings | 3 + CovidSafe/vi.lproj/Localizable.strings | 94 +++++- CovidSafe/zh-Hans.lproj/InfoPlist.strings | 3 + CovidSafe/zh-Hans.lproj/Localizable.strings | 94 +++++- CovidSafe/zh-Hant.lproj/InfoPlist.strings | 3 + CovidSafe/zh-Hant.lproj/Localizable.strings | 94 +++++- 67 files changed, 3645 insertions(+), 464 deletions(-) create mode 100644 CovidSafe/API/ChangePostcodeAPI.swift create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/activity.imageset/Contents.json create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/activity.imageset/activity 1.pdf create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/alert-triangle.imageset/Contents.json create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/alert-triangle.imageset/alert-triangle 1.pdf create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/check-green.imageset/Contents.json create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/check-green.imageset/check 1.pdf create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/external-link.imageset/Contents.json create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/external-link.imageset/external-link 1.pdf create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/home.imageset/Contents.json create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/home.imageset/home.pdf create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/map-pin.imageset/Contents.json create mode 100644 CovidSafe/Assets.xcassets/CovidSafe/map-pin.imageset/map-pin 1.pdf create mode 100644 CovidSafe/ChangePostcodeViewController.swift create mode 100644 CovidSafe/ChangePostcodeViewController.xib create mode 100644 CovidSafe/ExternalLinkTableViewCell.swift create mode 100644 CovidSafe/ExternalLinkTableViewCell.xib create mode 100644 CovidSafe/SelectStateTerritoryViewController.swift create mode 100644 CovidSafe/SelectStateTerritoryViewController.xib create mode 100644 CovidSafe/StateTerritoryTableViewCell.swift create mode 100644 CovidSafe/StateTerritoryTableViewCell.xib diff --git a/CovidSafe.xcodeproj/project.pbxproj b/CovidSafe.xcodeproj/project.pbxproj index edfdb97..6fd65ec 100644 --- a/CovidSafe.xcodeproj/project.pbxproj +++ b/CovidSafe.xcodeproj/project.pbxproj @@ -133,6 +133,8 @@ 5B04074224BC0CEA00FAAFD0 /* MessageAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B04074024BC0CEA00FAAFD0 /* MessageAPI.swift */; }; 5B110C10248F275B00B68291 /* SelectCountryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B110C0F248F275A00B68291 /* SelectCountryViewController.swift */; }; 5B110C11248F275B00B68291 /* SelectCountryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B110C0F248F275A00B68291 /* SelectCountryViewController.swift */; }; + 5B2E5B1B25AD156E00A021B0 /* ChangePostcodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2E5B1A25AD156E00A021B0 /* ChangePostcodeAPI.swift */; }; + 5B2E5B1C25AD156E00A021B0 /* ChangePostcodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2E5B1A25AD156E00A021B0 /* ChangePostcodeAPI.swift */; }; 5B30F78924B8179600CDED63 /* LaunchScreen_it.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F78824B8179600CDED63 /* LaunchScreen_it.storyboard */; }; 5B30F78A24B8179600CDED63 /* LaunchScreen_it.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F78824B8179600CDED63 /* LaunchScreen_it.storyboard */; }; 5B30F78C24B817A100CDED63 /* LaunchScreen_el.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F78B24B817A100CDED63 /* LaunchScreen_el.storyboard */; }; @@ -263,6 +265,10 @@ 5B9360FB24F73806008859FC /* StatisticsTableHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B9360F924F73806008859FC /* StatisticsTableHeader.xib */; }; 5B9360FD24F73CE6008859FC /* LoadingViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B9360FC24F73CE6008859FC /* LoadingViewCell.xib */; }; 5B9360FE24F73CE6008859FC /* LoadingViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B9360FC24F73CE6008859FC /* LoadingViewCell.xib */; }; + 5B98B45825A2B1E1009651B7 /* ChangePostcodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B98B45625A2B1E1009651B7 /* ChangePostcodeViewController.swift */; }; + 5B98B45925A2B1E1009651B7 /* ChangePostcodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B98B45625A2B1E1009651B7 /* ChangePostcodeViewController.swift */; }; + 5B98B45A25A2B1E1009651B7 /* ChangePostcodeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B98B45725A2B1E1009651B7 /* ChangePostcodeViewController.xib */; }; + 5B98B45B25A2B1E1009651B7 /* ChangePostcodeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B98B45725A2B1E1009651B7 /* ChangePostcodeViewController.xib */; }; 5B9E410D2521683500434B25 /* CSAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B9E410C2521683500434B25 /* CSAlertView.xib */; }; 5B9E410E2521683500434B25 /* CSAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B9E410C2521683500434B25 /* CSAlertView.xib */; }; 5B9E41122521688700434B25 /* CSAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9E41112521688700434B25 /* CSAlertViewController.swift */; }; @@ -277,6 +283,18 @@ 5BBE61B225633B6D00B8C983 /* CSGenericContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBE61B025633B6D00B8C983 /* CSGenericContentView.xib */; }; 5BBE61B725633E8D00B8C983 /* CSGenericViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BBE61B625633E8D00B8C983 /* CSGenericViewController.swift */; }; 5BBE61B825633E8D00B8C983 /* CSGenericViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BBE61B625633E8D00B8C983 /* CSGenericViewController.swift */; }; + 5BD2419425832A7E00F78822 /* SelectStateTerritoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD2419225832A7E00F78822 /* SelectStateTerritoryViewController.swift */; }; + 5BD2419525832A7E00F78822 /* SelectStateTerritoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD2419225832A7E00F78822 /* SelectStateTerritoryViewController.swift */; }; + 5BD2419625832A7E00F78822 /* SelectStateTerritoryViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BD2419325832A7E00F78822 /* SelectStateTerritoryViewController.xib */; }; + 5BD2419725832A7E00F78822 /* SelectStateTerritoryViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BD2419325832A7E00F78822 /* SelectStateTerritoryViewController.xib */; }; + 5BD2419E25832DA600F78822 /* StateTerritoryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD2419C25832DA600F78822 /* StateTerritoryTableViewCell.swift */; }; + 5BD2419F25832DA600F78822 /* StateTerritoryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD2419C25832DA600F78822 /* StateTerritoryTableViewCell.swift */; }; + 5BD241A025832DA600F78822 /* StateTerritoryTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BD2419D25832DA600F78822 /* StateTerritoryTableViewCell.xib */; }; + 5BD241A125832DA600F78822 /* StateTerritoryTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BD2419D25832DA600F78822 /* StateTerritoryTableViewCell.xib */; }; + 5BD241BC25870B8900F78822 /* ExternalLinkTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD241BA25870B8900F78822 /* ExternalLinkTableViewCell.swift */; }; + 5BD241BD25870B8900F78822 /* ExternalLinkTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD241BA25870B8900F78822 /* ExternalLinkTableViewCell.swift */; }; + 5BD241BE25870B8900F78822 /* ExternalLinkTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BD241BB25870B8900F78822 /* ExternalLinkTableViewCell.xib */; }; + 5BD241BF25870B8900F78822 /* ExternalLinkTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BD241BB25870B8900F78822 /* ExternalLinkTableViewCell.xib */; }; 5BD3EE8324330E1A0004A007 /* UploadDataStep2VC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD3EE8224330E1A0004A007 /* UploadDataStep2VC.swift */; }; 5BD3EE84243313450004A007 /* UploadDataStep2VC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD3EE8224330E1A0004A007 /* UploadDataStep2VC.swift */; }; 5BED1E3A24A96D1C0066C4D2 /* LaunchScreen_ar.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5BED1E3924A96D1C0066C4D2 /* LaunchScreen_ar.storyboard */; }; @@ -430,6 +448,7 @@ 59F25D6E245BED80002A7ED8 /* Debug.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Debug.storyboard; sourceTree = ""; }; 5B04074024BC0CEA00FAAFD0 /* MessageAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageAPI.swift; sourceTree = ""; }; 5B110C0F248F275A00B68291 /* SelectCountryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectCountryViewController.swift; sourceTree = ""; }; + 5B2E5B1A25AD156E00A021B0 /* ChangePostcodeAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangePostcodeAPI.swift; sourceTree = ""; }; 5B30F78424B8171E00CDED63 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 5B30F78524B8171E00CDED63 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; }; 5B30F78624B8172D00CDED63 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = ""; }; @@ -474,6 +493,8 @@ 5B9360F024F619C8008859FC /* MainStatisticsHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainStatisticsHeader.xib; sourceTree = ""; }; 5B9360F924F73806008859FC /* StatisticsTableHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StatisticsTableHeader.xib; sourceTree = ""; }; 5B9360FC24F73CE6008859FC /* LoadingViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LoadingViewCell.xib; sourceTree = ""; }; + 5B98B45625A2B1E1009651B7 /* ChangePostcodeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangePostcodeViewController.swift; sourceTree = ""; }; + 5B98B45725A2B1E1009651B7 /* ChangePostcodeViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ChangePostcodeViewController.xib; sourceTree = ""; }; 5B9E410C2521683500434B25 /* CSAlertView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CSAlertView.xib; sourceTree = ""; }; 5B9E41112521688700434B25 /* CSAlertViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSAlertViewController.swift; sourceTree = ""; }; 5BA33A7A24B3FE2700D12515 /* UIFont + Traits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont + Traits.swift"; sourceTree = ""; }; @@ -483,6 +504,12 @@ 5BBC571C25526F99005E90AA /* staging-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "staging-Info.plist"; sourceTree = ""; }; 5BBE61B025633B6D00B8C983 /* CSGenericContentView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CSGenericContentView.xib; sourceTree = ""; }; 5BBE61B625633E8D00B8C983 /* CSGenericViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CSGenericViewController.swift; sourceTree = ""; }; + 5BD2419225832A7E00F78822 /* SelectStateTerritoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectStateTerritoryViewController.swift; sourceTree = ""; }; + 5BD2419325832A7E00F78822 /* SelectStateTerritoryViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SelectStateTerritoryViewController.xib; sourceTree = ""; }; + 5BD2419C25832DA600F78822 /* StateTerritoryTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateTerritoryTableViewCell.swift; sourceTree = ""; }; + 5BD2419D25832DA600F78822 /* StateTerritoryTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StateTerritoryTableViewCell.xib; sourceTree = ""; }; + 5BD241BA25870B8900F78822 /* ExternalLinkTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLinkTableViewCell.swift; sourceTree = ""; }; + 5BD241BB25870B8900F78822 /* ExternalLinkTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExternalLinkTableViewCell.xib; sourceTree = ""; }; 5BD3EE8224330E1A0004A007 /* UploadDataStep2VC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadDataStep2VC.swift; sourceTree = ""; }; 5BED1E2F24A95ECB0066C4D2 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; 5BED1E3024A95ECB0066C4D2 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -637,7 +664,9 @@ 5BBE61D625637BB100B8C983 /* Debug */, 5BBE61D525637B7600B8C983 /* Registration */, 1B86118F24303ED400EA4B6B /* Questions */, + B6932CE8242627A9003D1810 /* Upload Data */, 5B728B4624B5667000654ABC /* BLELogViewController.swift */, + 5B98B45625A2B1E1009651B7 /* ChangePostcodeViewController.swift */, 5B92B0BF24F4DC3A0069C57D /* CovidStatisticsViewController.swift */, 5B9E41112521688700434B25 /* CSAlertViewController.swift */, 5BBE61B625633E8D00B8C983 /* CSGenericViewController.swift */, @@ -648,6 +677,7 @@ 5B7ABF24244D3BC600BB249B /* IsolationSuccessViewController.swift */, 5961ABE92474E358004040DF /* MigrationViewController.swift */, 7F19B4DC23F565850071A11E /* PogoInstructionsViewController.swift */, + 5BD2419225832A7E00F78822 /* SelectStateTerritoryViewController.swift */, 5B92B0AD24EFADB00069C57D /* SettingsViewController.swift */, B615C5A823FA403400345969 /* UIViewController + Extension.swift */, ); @@ -673,13 +703,16 @@ 0BC141AD2430685800399FA8 /* UIColor + Extensions.swift */, B615C5A623F8EB1700345969 /* UIProgressView + Extension.swift */, 0B55E1912430760500C9E798 /* UITextView + Extensions.swift */, + 5B98B45725A2B1E1009651B7 /* ChangePostcodeViewController.xib */, 5B92B0BC24F4DBE20069C57D /* CovidStatisticsView.xib */, 5B9E410C2521683500434B25 /* CSAlertView.xib */, 5BBE61B025633B6D00B8C983 /* CSGenericContentView.xib */, 5B92B0A424EF61480069C57D /* HomeView.xib */, 5B92B0B324F37E3E0069C57D /* InternetConnectionView.xib */, + 5BD2419325832A7E00F78822 /* SelectStateTerritoryViewController.xib */, 5B92B0AA24EFA3160069C57D /* SettingsView.xib */, 5DD41D4023DCB03B00FD4AB0 /* Main.storyboard */, + 5B51ED58248627A8008CE722 /* UploadData.storyboard */, ); name = Views; sourceTree = ""; @@ -854,10 +887,14 @@ 5B9360EC24F6196A008859FC /* Cells */ = { isa = PBXGroup; children = ( + 5BD241BA25870B8900F78822 /* ExternalLinkTableViewCell.swift */, + 5BD2419C25832DA600F78822 /* StateTerritoryTableViewCell.swift */, 5B9360ED24F619A8008859FC /* StatDetailedCell.xib */, 5B9360F024F619C8008859FC /* MainStatisticsHeader.xib */, 5B9360F924F73806008859FC /* StatisticsTableHeader.xib */, 5B9360FC24F73CE6008859FC /* LoadingViewCell.xib */, + 5BD2419D25832DA600F78822 /* StateTerritoryTableViewCell.xib */, + 5BD241BB25870B8900F78822 /* ExternalLinkTableViewCell.xib */, ); name = Cells; sourceTree = ""; @@ -914,6 +951,7 @@ 59AF2E97243552FB00ACCAF2 /* Certificates */, FB12C4C0242F047F007E893B /* RespondToAuthChallengeAPI.swift */, 5BFFD94A242EC120003AEF4F /* PhoneValidationAPI.swift */, + 5B2E5B1A25AD156E00A021B0 /* ChangePostcodeAPI.swift */, 5B04074024BC0CEA00FAAFD0 /* MessageAPI.swift */, 5B92B0C224F4DE6E0069C57D /* StatisticsAPI.swift */, 59ACB573242F195A00E63E3C /* InitiateUploadAPI.swift */, @@ -954,7 +992,6 @@ 5B92D661243005B10049877B /* Resources */, A767D2AE242DF1B000DC9E2A /* Feedback */, 5BFFD949242EC04D003AEF4F /* API */, - B6932CE8242627A9003D1810 /* Upload Data */, 7F36305D23F7F7EC00CC6E1D /* Constants */, 5DD41D3A23DCB03B00FD4AB0 /* AppDelegate.swift */, C585C83923EEB93A0061B7C6 /* UIElements */, @@ -1052,7 +1089,6 @@ B6932CE8242627A9003D1810 /* Upload Data */ = { isa = PBXGroup; children = ( - 5B51ED58248627A8008CE722 /* UploadData.storyboard */, 30E91BE823EFE514002D592A /* UploadDataVC.swift */, 5BD3EE8224330E1A0004A007 /* UploadDataStep2VC.swift */, 0B69E7E82430C22E00561DD9 /* UploadDataHomeViewController.swift */, @@ -1189,11 +1225,13 @@ files = ( 5B92D6BA243018040049877B /* help_center_article_style.css in Resources */, 5B51ED62248715DE008CE722 /* InfoPlist.strings in Resources */, + 5B98B45B25A2B1E1009651B7 /* ChangePostcodeViewController.xib in Resources */, 5B51ED56248627A8008CE722 /* UploadData.storyboard in Resources */, 5B92B0BE24F4DBE20069C57D /* CovidStatisticsView.xib in Resources */, 5B9360FB24F73806008859FC /* StatisticsTableHeader.xib in Resources */, 5B92D6BD243018040049877B /* JMCTarget.json in Resources */, 5B9360F224F619C8008859FC /* MainStatisticsHeader.xib in Resources */, + 5BD2419725832A7E00F78822 /* SelectStateTerritoryViewController.xib in Resources */, 5B92D6BF243018040049877B /* NewFeedbackFlow.storyboard in Resources */, 59AF2EA92435801400ACCAF2 /* SFSRootCAG2.cer in Resources */, 59F25D6A245B917A002A7ED8 /* Spinner_home.json in Resources */, @@ -1207,6 +1245,7 @@ 59AF2EAD2435801400ACCAF2 /* AmazonRootCA4.cer in Resources */, 59F25D6F245BED80002A7ED8 /* Debug.storyboard in Resources */, 5BED1E3B24A96D1C0066C4D2 /* LaunchScreen_ar.storyboard in Resources */, + 5BD241A125832DA600F78822 /* StateTerritoryTableViewCell.xib in Resources */, 5BED1E4424A98EB60066C4D2 /* LaunchScreen_vi.storyboard in Resources */, 5B30F78D24B817A100CDED63 /* LaunchScreen_el.storyboard in Resources */, 5BBC571D25526F99005E90AA /* staging-Info.plist in Resources */, @@ -1225,6 +1264,7 @@ 5B9360EF24F619A8008859FC /* StatDetailedCell.xib in Resources */, 5BED1E4724A98EC20066C4D2 /* LaunchScreen_ko.storyboard in Resources */, 59AF2EAB2435801400ACCAF2 /* AmazonRootCA3.cer in Resources */, + 5BD241BF25870B8900F78822 /* ExternalLinkTableViewCell.xib in Resources */, 5B92D6CF243018040049877B /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1243,9 +1283,11 @@ 5B92B09F24E0CD070069C57D /* LaunchScreen_tr.storyboard in Resources */, A767D312242DF1B000DC9E2A /* NewFeedbackFlow.storyboard in Resources */, 5B9360F124F619C8008859FC /* MainStatisticsHeader.xib in Resources */, + 5BD241BE25870B8900F78822 /* ExternalLinkTableViewCell.xib in Resources */, 5BED1E3D24A98EA90066C4D2 /* LaunchScreen_zh-Hans.storyboard in Resources */, 5B9360FA24F73806008859FC /* StatisticsTableHeader.xib in Resources */, 59F25D69245B917A002A7ED8 /* Spinner_home.json in Resources */, + 5BD2419625832A7E00F78822 /* SelectStateTerritoryViewController.xib in Resources */, 5B9E410D2521683500434B25 /* CSAlertView.xib in Resources */, 5B92B0B424F37E3E0069C57D /* InternetConnectionView.xib in Resources */, 5BED1E4624A98EC20066C4D2 /* LaunchScreen_ko.storyboard in Resources */, @@ -1267,6 +1309,8 @@ 5DD41D4423DCB03D00FD4AB0 /* Assets.xcassets in Resources */, 5B92B0BD24F4DBE20069C57D /* CovidStatisticsView.xib in Resources */, 5B337AAF245AA26300537620 /* Spinner_upload.json in Resources */, + 5B98B45A25A2B1E1009651B7 /* ChangePostcodeViewController.xib in Resources */, + 5BD241A025832DA600F78822 /* StateTerritoryTableViewCell.xib in Resources */, 59AF2EAA2435801400ACCAF2 /* AmazonRootCA3.cer in Resources */, 5961ABED2474E464004040DF /* spinner_migrating_db.json in Resources */, 5DD41D4223DCB03B00FD4AB0 /* Main.storyboard in Resources */, @@ -1396,6 +1440,7 @@ 5B337AAD245A9EF800537620 /* UploadDataErrorViewController.swift in Sources */, 590888B02431B9E7008C9B9F /* UIColor + Extensions.swift in Sources */, 5B728B4E24B5A26D00654ABC /* debug.xcdatamodeld in Sources */, + 5B2E5B1C25AD156E00A021B0 /* ChangePostcodeAPI.swift in Sources */, 5905460F2543E0F5009B82AD /* BLEDatabase.swift in Sources */, 5B92D74F243022EF0049877B /* DataUploadS3.swift in Sources */, 5B92D683243018040049877B /* RegistrationSuccessViewController.swift in Sources */, @@ -1403,6 +1448,7 @@ 5B92B09524D14AE00069C57D /* InternetConnectionViewController.swift in Sources */, 5B92D684243018040049877B /* AsyncAction.swift in Sources */, 5B92D685243018040049877B /* UILabelExtension.swift in Sources */, + 5BD2419525832A7E00F78822 /* SelectStateTerritoryViewController.swift in Sources */, 5905462B2543E0F6009B82AD /* PayloadDataSupplier.swift in Sources */, 5B92D686243018040049877B /* AppDelegate.swift in Sources */, 5B92D687243018040049877B /* PhoneNumberViewController.swift in Sources */, @@ -1437,6 +1483,7 @@ 5B92D698243018040049877B /* SendFeedbackAction.swift in Sources */, 5B92D699243018040049877B /* UITextViewFixed.swift in Sources */, 590546152543E0F6009B82AD /* BLEReceiver.swift in Sources */, + 5BD241BD25870B8900F78822 /* ExternalLinkTableViewCell.swift in Sources */, 5BA33A7E24B55E7D00D12515 /* BLELogRecord.swift in Sources */, 590888B12431B9EB008C9B9F /* Question3ViewController.swift in Sources */, 5957EB67244E936E002F5388 /* UnderSixteenViewController.swift in Sources */, @@ -1444,6 +1491,7 @@ 5B92D69A243018040049877B /* GradientButton.swift in Sources */, 5B92D69B243018040049877B /* ViewControllerFactory.swift in Sources */, 5B04074224BC0CEA00FAAFD0 /* MessageAPI.swift in Sources */, + 5B98B45925A2B1E1009651B7 /* ChangePostcodeViewController.swift in Sources */, 5B7ABF26244D3BC600BB249B /* IsolationSuccessViewController.swift in Sources */, 5B92D69C243018040049877B /* FeedbackViewController.swift in Sources */, 5B92D69E243018040049877B /* JMCTarget.swift in Sources */, @@ -1492,6 +1540,7 @@ 590888B62431BA7C008C9B9F /* Question3ErrorViewController.swift in Sources */, 590546332543E0F6009B82AD /* SensorLogger.swift in Sources */, 5B900FC22485C4EE00CAA419 /* String+Localization.swift in Sources */, + 5BD2419F25832DA600F78822 /* StateTerritoryTableViewCell.swift in Sources */, 59AF2E9D2435581600ACCAF2 /* CovidNetworking.swift in Sources */, 596B189D24499591003E190F /* UploadHelper.swift in Sources */, 590888AF2431B9E3008C9B9F /* UITextView + Extensions.swift in Sources */, @@ -1534,11 +1583,13 @@ 7F19B4DD23F565850071A11E /* PogoInstructionsViewController.swift in Sources */, 30E91BEB23EFEA0B002D592A /* CodeInputView.swift in Sources */, 597BB7CF245FB1250067A2E2 /* Crypto.swift in Sources */, + 5BD2419E25832DA600F78822 /* StateTerritoryTableViewCell.swift in Sources */, 30BE1CAF23F1349F005DCE4F /* EncounterRecord.swift in Sources */, 590546102543E0F5009B82AD /* BLEUtilities.swift in Sources */, 590546382543E0F6009B82AD /* SensorDelegate.swift in Sources */, 59490B64245FE3DA00C9802B /* EncounterV2Mapping.swift in Sources */, 590546282543E0F6009B82AD /* SensorArray.swift in Sources */, + 5BD241BC25870B8900F78822 /* ExternalLinkTableViewCell.swift in Sources */, C58D817723F169DB00345771 /* RegistrationSuccessViewController.swift in Sources */, 59ACB574242F195A00E63E3C /* InitiateUploadAPI.swift in Sources */, A767D324242DF1B100DC9E2A /* AsyncAction.swift in Sources */, @@ -1579,6 +1630,7 @@ A767D325242DF1B100DC9E2A /* SendFeedbackAction.swift in Sources */, C5D209FC23F4476F007233BE /* UITextViewFixed.swift in Sources */, C585C83B23EEB99B0061B7C6 /* GradientButton.swift in Sources */, + 5B98B45825A2B1E1009651B7 /* ChangePostcodeViewController.swift in Sources */, 590546342543E0F6009B82AD /* ContactLog.swift in Sources */, 597BB7CC245FAEC00067A2E2 /* SecKey+CovidSafe.swift in Sources */, 5B92B0AE24EFADB00069C57D /* SettingsViewController.swift in Sources */, @@ -1601,6 +1653,7 @@ 592CBB802441A583001FFCE9 /* PersonalDetailsViewController.swift in Sources */, A767D330242DF1B100DC9E2A /* UIWindow+TopMost.swift in Sources */, D8DEB6822423AE2E00D99925 /* HowItWorksViewController.swift in Sources */, + 5B2E5B1B25AD156E00A021B0 /* ChangePostcodeAPI.swift in Sources */, 5B92B0C324F4DE6F0069C57D /* StatisticsAPI.swift in Sources */, 5905462C2543E0F6009B82AD /* TextFile.swift in Sources */, C56CF43F23F18A15006B05B0 /* OnboardingStep4ViewController.swift in Sources */, @@ -1625,6 +1678,7 @@ A767D31F242DF1B000DC9E2A /* HTTPPostFeedbackAction.swift in Sources */, 7F36305F23F7F81400CC6E1D /* PushNotificationConstants.swift in Sources */, 59AF2E9C2435581600ACCAF2 /* CovidNetworking.swift in Sources */, + 5BD2419425832A7E00F78822 /* SelectStateTerritoryViewController.swift in Sources */, 596B189C24499591003E190F /* UploadHelper.swift in Sources */, 5B51ED502485D658008CE722 /* UILocalization.swift in Sources */, 1B86119724303F8500EA4B6B /* Question1ErrorViewController.swift in Sources */, @@ -1778,7 +1832,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 95; + CURRENT_PROJECT_VERSION = 108; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1786,7 +1840,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.2; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = COVIDSafe; @@ -1862,7 +1916,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 95; + CURRENT_PROJECT_VERSION = 108; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1870,7 +1924,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.2; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = COVIDSafe; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1890,7 +1944,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 93; + CURRENT_PROJECT_VERSION = 107; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/staging-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1898,7 +1952,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.2; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; @@ -1920,7 +1974,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 93; + CURRENT_PROJECT_VERSION = 107; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/staging-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1928,7 +1982,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.2; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; @@ -1950,7 +2004,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 93; + CURRENT_PROJECT_VERSION = 107; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/staging-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1958,7 +2012,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.2; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_MODULE_NAME = COVIDSafe; @@ -1980,7 +2034,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 93; + CURRENT_PROJECT_VERSION = 107; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/staging-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1988,7 +2042,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.2; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_MODULE_NAME = COVIDSafe; @@ -2128,7 +2182,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 95; + CURRENT_PROJECT_VERSION = 108; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -2136,7 +2190,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.2; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = COVIDSafe; @@ -2156,7 +2210,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 95; + CURRENT_PROJECT_VERSION = 108; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = "$(SRCROOT)/CovidSafe/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -2164,7 +2218,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.2; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = COVIDSafe; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/CovidSafe/API/ChangePostcodeAPI.swift b/CovidSafe/API/ChangePostcodeAPI.swift new file mode 100644 index 0000000..d5bc490 --- /dev/null +++ b/CovidSafe/API/ChangePostcodeAPI.swift @@ -0,0 +1,58 @@ +// +// ChangePostcodeAPI.swift +// CovidSafe +// +// Copyright © 2020 Australian Government. All rights reserved. +// + +import Foundation +import Alamofire + +class ChangePostcodeAPI: CovidSafeAuthenticatedAPI { + + static func changePostcode(newPostcode: String, + completion: @escaping (CovidSafeAPIError?) -> Void) { + + guard let apiHost = PlistHelper.getvalueFromInfoPlist(withKey: "API_Host", plistName: "CovidSafe-config") else { + return + } + + guard let headers = try? authenticatedHeaders() else { + completion(.TokenExpiredError) + return + } + + let params = [ + "postcode": newPostcode, + ] + CovidNetworking.shared.session.request("\(apiHost)/device", + method: .post, + parameters: params, + encoding: JSONEncoding.default, + headers: headers, + interceptor: CovidRequestRetrier(retries:3)).validate().responseDecodable(of: DeviceResponse.self) { (response) in + switch response.result { + case .success: + completion(nil) + case .failure(_): + guard let statusCode = response.response?.statusCode else { + completion(.UnknownError) + return + } + if (statusCode >= 400 && statusCode < 500) { + completion(.RequestError) + return + } + completion(.ServerError) + } + } + } +} + +struct DeviceResponse: Decodable { + let message: String? + + enum CodingKeys: String, CodingKey { + case message + } +} diff --git a/CovidSafe/API/DataUploadS3.swift b/CovidSafe/API/DataUploadS3.swift index 2ca9b31..29a86d3 100644 --- a/CovidSafe/API/DataUploadS3.swift +++ b/CovidSafe/API/DataUploadS3.swift @@ -8,9 +8,9 @@ import Foundation class DataUploadS3 { - static func uploadJSONData(data: Data, presignedUrl: String, completion: @escaping (Bool, Swift.Error?) -> Void) { + static func uploadJSONData(data: Data, presignedUrl: String, completion: @escaping (Bool, Swift.Error?, String?) -> Void) { guard let url = URL(string: presignedUrl) else { - completion(false, nil) + completion(false, nil, "[102] S3") return } var request = URLRequest(url: url) @@ -22,9 +22,9 @@ class DataUploadS3 { ).validate().response { (response) in switch response.result { case .success: - completion(true, nil) + completion(true, nil, nil) case let .failure(error): - completion(false, error) + completion(false, error, "[\(response.response?.statusCode ?? 000))] S3") } } uploadRequest.resume() diff --git a/CovidSafe/API/InitiateUploadAPI.swift b/CovidSafe/API/InitiateUploadAPI.swift index b4071a2..146358a 100644 --- a/CovidSafe/API/InitiateUploadAPI.swift +++ b/CovidSafe/API/InitiateUploadAPI.swift @@ -35,7 +35,7 @@ class InitiateUploadAPI { } } - static func initiateUploadAPI(session: String, pin: String?, completion: @escaping (UploadResponse?, APIError?) -> Void) { + static func initiateUploadAPI(session: String, pin: String?, completion: @escaping (UploadResponse?, APIError?, String?) -> Void) { guard let apiHost = PlistHelper.getvalueFromInfoPlist(withKey: "API_Host", plistName: "CovidSafe-config") else { return } @@ -48,38 +48,30 @@ class InitiateUploadAPI { } guard pin != nil else { - completion(nil, .ServerError) + completion(nil, .ServerError, nil) return } CovidNetworking.shared.session.request("\(apiHost)/initiateDataUpload", method: .get, headers: headers, interceptor: CovidRequestRetrier(retries: 3)).validate().responseData { (response) in guard let respData = response.data else { - completion(nil, .ServerError) + completion(nil, .ServerError, "[100] API") return } + switch response.result { case .success: do { let uploadResponse = try JSONDecoder().decode(UploadResponse.self, from: respData) - completion(uploadResponse, nil) + completion(uploadResponse, nil, nil) } catch { - completion(nil, .ServerError) + completion(nil, .ServerError, "[101] API") } case .failure(_): - if (response.response?.statusCode == 403) { - do { - let uploadResponse = try JSONDecoder().decode(ErrorResponse.self, from: respData) - if uploadResponse.message == "InvalidPin" { - completion(nil, .ServerError) - return - } - } catch { - completion(nil, .ServerError) - return - } - completion(nil, .ExpireSession) - } else { - completion(nil, .ServerError) + do { + let uploadResponse = try JSONDecoder().decode(ErrorResponse.self, from: respData) + completion(nil, .ServerError, "[\(response.response?.statusCode ?? 000)] \(uploadResponse.message)") + } catch { + completion(nil, .ServerError, "[\(response.response?.statusCode ?? 000)] API") } } } diff --git a/CovidSafe/API/StatisticsAPI.swift b/CovidSafe/API/StatisticsAPI.swift index 57f3bf5..9b0fd48 100644 --- a/CovidSafe/API/StatisticsAPI.swift +++ b/CovidSafe/API/StatisticsAPI.swift @@ -12,7 +12,7 @@ class StatisticsAPI: CovidSafeAuthenticatedAPI { static let keyCovidStatistics = "keyCovidStatistics" - static func getStatistics(completion: @escaping (StatisticsResponse?, CovidSafeAPIError?) -> Void) { + static func getStatistics(forState: StateTerritory = StateTerritory.AU, completion: @escaping (StatisticsResponse?, CovidSafeAPIError?) -> Void) { guard let apiHost = PlistHelper.getvalueFromInfoPlist(withKey: "API_Host", plistName: "CovidSafe-config") else { completion(nil, .RequestError) return @@ -23,8 +23,11 @@ class StatisticsAPI: CovidSafeAuthenticatedAPI { return } - CovidNetworking.shared.session.request("\(apiHost)/statistics", + let parameters = ["state" : "\(forState.rawValue)"] + + CovidNetworking.shared.session.request("\(apiHost)/v2/statistics", method: .get, + parameters: parameters, headers: headers ).validate().responseDecodable(of: StatisticsResponse.self) { (response) in switch response.result { @@ -66,6 +69,7 @@ class StatisticsAPI: CovidSafeAuthenticatedAPI { struct StatisticsResponse: Codable { let updatedDate: String? + let responseVersion: String? let national: StateTerritoryStatistics? let act: StateTerritoryStatistics? @@ -88,6 +92,14 @@ struct StatisticsResponse: Codable { case tas case vic case wa + case responseVersion = "version" + } + + func version() -> Int { + guard let versionStr = responseVersion else { + return 0 + } + return Int(versionStr) ?? 0 } } @@ -97,12 +109,32 @@ struct StateTerritoryStatistics: Codable { let newCases: Int? let recoveredCases: Int? let deaths: Int? + let newLocallyAcquired: Int? + let locallyAcquired: Int? + let newOverseasAcquired: Int? + let overseasAcquired: Int? + let historicalCases: [HistoricalCase]? enum CodingKeys: String, CodingKey { case totalCases = "total_cases" case activeCases = "active_cases" case newCases = "new_cases" case recoveredCases = "recovered_cases" + case newLocallyAcquired = "new_locally_acquired" + case locallyAcquired = "locally_acquired" + case newOverseasAcquired = "new_overseas_acquired" + case overseasAcquired = "overseas_acquired" + case historicalCases = "historical_cases" case deaths } } + +struct HistoricalCase: Codable { + let date: String + let newCases: Int + + enum CodingKeys: String, CodingKey { + case date + case newCases = "new_cases" + } +} diff --git a/CovidSafe/AppSettingsViewController.swift b/CovidSafe/AppSettingsViewController.swift index 064695a..f7ab908 100644 --- a/CovidSafe/AppSettingsViewController.swift +++ b/CovidSafe/AppSettingsViewController.swift @@ -21,7 +21,7 @@ class AppSettingsViewController: UIViewController { 4, 4 ) - topContentTextView.addLink("\(URLHelper.getHelpURL())#location-permission-android", enclosedIn: "*") + topContentTextView.addLink("\(URLHelper.geLocationPermissionsURL())", enclosedIn: "*") topContentTextView.addAllBold(enclosedIn: "#") } diff --git a/CovidSafe/Assets.xcassets/CovidSafe/activity.imageset/Contents.json b/CovidSafe/Assets.xcassets/CovidSafe/activity.imageset/Contents.json new file mode 100644 index 0000000..a012081 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/activity.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "activity 1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CovidSafe/Assets.xcassets/CovidSafe/activity.imageset/activity 1.pdf b/CovidSafe/Assets.xcassets/CovidSafe/activity.imageset/activity 1.pdf new file mode 100644 index 0000000..4891570 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/activity.imageset/activity 1.pdf @@ -0,0 +1,127 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.000000 1.000000 cm +0.000000 0.000000 0.000000 scn +20.000000 10.000000 m +20.552284 10.000000 21.000000 10.447715 21.000000 11.000000 c +21.000000 11.552285 20.552284 12.000000 20.000000 12.000000 c +20.000000 10.000000 l +h +16.000000 11.000000 m +16.000000 12.000000 l +15.569570 12.000000 15.187430 11.724570 15.051316 11.316228 c +16.000000 11.000000 l +h +13.000000 2.000000 m +12.051316 1.683773 l +12.187430 1.275431 12.569570 1.000000 13.000000 1.000000 c +13.430430 1.000000 13.812570 1.275431 13.948684 1.683773 c +13.000000 2.000000 l +h +7.000000 20.000000 m +7.948683 20.316227 l +7.812569 20.724569 7.430430 21.000000 7.000000 21.000000 c +6.569570 21.000000 6.187431 20.724569 6.051317 20.316227 c +7.000000 20.000000 l +h +4.000000 11.000000 m +4.000000 10.000000 l +4.430430 10.000000 4.812569 10.275430 4.948683 10.683772 c +4.000000 11.000000 l +h +0.000000 12.000000 m +-0.552285 12.000000 -1.000000 11.552285 -1.000000 11.000000 c +-1.000000 10.447715 -0.552285 10.000000 0.000000 10.000000 c +0.000000 12.000000 l +h +20.000000 12.000000 m +16.000000 12.000000 l +16.000000 10.000000 l +20.000000 10.000000 l +20.000000 12.000000 l +h +15.051316 11.316228 m +12.051316 2.316227 l +13.948684 1.683773 l +16.948683 10.683772 l +15.051316 11.316228 l +h +13.948684 2.316227 m +7.948683 20.316227 l +6.051317 19.683773 l +12.051316 1.683773 l +13.948684 2.316227 l +h +6.051317 20.316227 m +3.051317 11.316228 l +4.948683 10.683772 l +7.948683 19.683773 l +6.051317 20.316227 l +h +4.000000 12.000000 m +0.000000 12.000000 l +0.000000 10.000000 l +4.000000 10.000000 l +4.000000 12.000000 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1625 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Type /Catalog + /Pages 5 0 R + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001715 00000 n +0000001738 00000 n +0000001911 00000 n +0000001985 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2044 +%%EOF \ No newline at end of file diff --git a/CovidSafe/Assets.xcassets/CovidSafe/alert-triangle.imageset/Contents.json b/CovidSafe/Assets.xcassets/CovidSafe/alert-triangle.imageset/Contents.json new file mode 100644 index 0000000..2b5121d --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/alert-triangle.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "alert-triangle 1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CovidSafe/Assets.xcassets/CovidSafe/alert-triangle.imageset/alert-triangle 1.pdf b/CovidSafe/Assets.xcassets/CovidSafe/alert-triangle.imageset/alert-triangle 1.pdf new file mode 100644 index 0000000..b417e8d --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/alert-triangle.imageset/alert-triangle 1.pdf @@ -0,0 +1,228 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.551758 1.000000 cm +0.000000 0.000000 0.000000 scn +0.268019 5.000039 m +-0.589849 5.513910 l +-0.592593 5.509329 -0.595301 5.504725 -0.597972 5.500099 c +0.268019 5.000039 l +h +1.978019 2.000038 m +1.967028 1.000038 l +1.978019 1.000038 l +1.978019 2.000038 l +h +18.918018 2.000038 m +18.918018 0.999977 l +18.929008 1.000099 l +18.918018 2.000038 l +h +20.628019 5.000039 m +21.494009 5.500099 l +21.491339 5.504725 21.488632 5.509329 21.485888 5.513910 c +20.628019 5.000039 l +h +12.158019 19.140039 m +13.015900 19.653917 l +13.013019 19.658667 l +12.158019 19.140039 l +h +10.448019 20.102783 m +10.448019 21.102783 l +10.448019 20.102783 l +h +7.880152 19.653910 m +-0.589849 5.513910 l +1.125886 4.486168 l +9.595886 18.626167 l +7.880152 19.653910 l +h +-0.597972 5.500099 m +-0.859919 5.046466 -0.998522 4.532151 -0.999988 4.008320 c +1.000004 4.002720 l +1.000493 4.177329 1.046693 4.348766 1.134009 4.499979 c +-0.597972 5.500099 l +h +-0.999988 4.008320 m +-1.001455 3.484489 -0.865735 2.969404 -0.606332 2.514311 c +1.131223 3.504717 l +1.044755 3.656414 0.999515 3.828110 1.000004 4.002720 c +-0.999988 4.008320 l +h +-0.606332 2.514311 m +-0.346929 2.059217 0.027116 1.679977 0.478590 1.414322 c +1.492863 3.138054 l +1.342373 3.226604 1.217691 3.353018 1.131223 3.504717 c +-0.606332 2.514311 l +h +0.478590 1.414322 m +0.930060 1.148670 1.443224 1.005856 1.967028 1.000099 c +1.989009 2.999977 l +1.814413 3.001896 1.643358 3.049500 1.492863 3.138054 c +0.478590 1.414322 l +h +1.978019 1.000038 m +18.918018 1.000038 l +18.918018 3.000038 l +1.978019 3.000038 l +1.978019 1.000038 l +h +18.929008 1.000099 m +19.452814 1.005856 19.965977 1.148670 20.417448 1.414322 c +19.403173 3.138054 l +19.252680 3.049500 19.081625 3.001896 18.907028 2.999977 c +18.929008 1.000099 l +h +20.417448 1.414322 m +20.868921 1.679977 21.242966 2.059217 21.502371 2.514311 c +19.764814 3.504717 l +19.678347 3.353020 19.553665 3.226604 19.403173 3.138054 c +20.417448 1.414322 l +h +21.502371 2.514311 m +21.761774 2.969404 21.897493 3.484489 21.896027 4.008320 c +19.896034 4.002720 l +19.896523 3.828110 19.851284 3.656416 19.764814 3.504717 c +21.502371 2.514311 l +h +21.896027 4.008320 m +21.894560 4.532151 21.755957 5.046466 21.494009 5.500099 c +19.762030 4.499979 l +19.849344 4.348766 19.895546 4.177329 19.896034 4.002720 c +21.896027 4.008320 l +h +21.485888 5.513910 m +13.015886 19.653910 l +11.300152 18.626167 l +19.770151 4.486168 l +21.485888 5.513910 l +h +13.013019 19.658667 m +12.745613 20.099508 12.369102 20.463987 11.919812 20.716942 c +10.938617 18.974169 l +11.088380 18.889851 11.213883 18.768358 11.303020 18.621410 c +13.013019 19.658667 l +h +11.919812 20.716942 m +11.470523 20.969894 10.963622 21.102783 10.448019 21.102783 c +10.448019 19.102783 l +10.619886 19.102783 10.788854 19.058487 10.938617 18.974169 c +11.919812 20.716942 l +h +10.448019 21.102783 m +9.932416 21.102783 9.425515 20.969894 8.976226 20.716942 c +9.957421 18.974169 l +10.107184 19.058487 10.276152 19.102783 10.448019 19.102783 c +10.448019 21.102783 l +h +8.976226 20.716942 m +8.526937 20.463987 8.150425 20.099508 7.883019 19.658667 c +9.593019 18.621410 l +9.682155 18.768358 9.807658 18.889851 9.957421 18.974169 c +8.976226 20.716942 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 12.000000 9.000000 cm +0.000000 0.000000 0.000000 scn +1.000000 6.000000 m +1.000000 6.552285 0.552285 7.000000 0.000000 7.000000 c +-0.552285 7.000000 -1.000000 6.552285 -1.000000 6.000000 c +1.000000 6.000000 l +h +-1.000000 2.000000 m +-1.000000 1.447715 -0.552285 1.000000 0.000000 1.000000 c +0.552285 1.000000 1.000000 1.447715 1.000000 2.000000 c +-1.000000 2.000000 l +h +-1.000000 6.000000 m +-1.000000 2.000000 l +1.000000 2.000000 l +1.000000 6.000000 l +-1.000000 6.000000 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 12.000000 5.000000 cm +0.000000 0.000000 0.000000 scn +0.000000 3.000000 m +-0.552285 3.000000 -1.000000 2.552285 -1.000000 2.000000 c +-1.000000 1.447715 -0.552285 1.000000 0.000000 1.000000 c +0.000000 3.000000 l +h +0.010000 1.000000 m +0.562285 1.000000 1.010000 1.447715 1.010000 2.000000 c +1.010000 2.552285 0.562285 3.000000 0.010000 3.000000 c +0.010000 1.000000 l +h +0.000000 1.000000 m +0.010000 1.000000 l +0.010000 3.000000 l +0.000000 3.000000 l +0.000000 1.000000 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 4243 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Type /Catalog + /Pages 5 0 R + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000004333 00000 n +0000004356 00000 n +0000004529 00000 n +0000004603 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +4662 +%%EOF \ No newline at end of file diff --git a/CovidSafe/Assets.xcassets/CovidSafe/check-green.imageset/Contents.json b/CovidSafe/Assets.xcassets/CovidSafe/check-green.imageset/Contents.json new file mode 100644 index 0000000..04e8389 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/check-green.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "check 1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CovidSafe/Assets.xcassets/CovidSafe/check-green.imageset/check 1.pdf b/CovidSafe/Assets.xcassets/CovidSafe/check-green.imageset/check 1.pdf new file mode 100644 index 0000000..b351dc7 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/check-green.imageset/check 1.pdf @@ -0,0 +1,92 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 4.804688 cm +0.000000 0.400000 0.105882 scn +16.707108 12.488206 m +17.097631 12.878730 17.097631 13.511895 16.707108 13.902419 c +16.316582 14.292944 15.683417 14.292944 15.292893 13.902419 c +16.707108 12.488206 l +h +5.000000 2.195312 m +4.292893 1.488206 l +4.683417 1.097681 5.316583 1.097681 5.707107 1.488206 c +5.000000 2.195312 l +h +0.707107 7.902419 m +0.316583 8.292944 -0.316583 8.292944 -0.707107 7.902419 c +-1.097631 7.511895 -1.097631 6.878730 -0.707107 6.488206 c +0.707107 7.902419 l +h +15.292893 13.902419 m +4.292893 2.902419 l +5.707107 1.488206 l +16.707108 12.488206 l +15.292893 13.902419 l +h +5.707107 2.902419 m +0.707107 7.902419 l +-0.707107 6.488206 l +4.292893 1.488206 l +5.707107 2.902419 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 783 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Type /Catalog + /Pages 5 0 R + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000873 00000 n +0000000895 00000 n +0000001068 00000 n +0000001142 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1201 +%%EOF \ No newline at end of file diff --git a/CovidSafe/Assets.xcassets/CovidSafe/external-link.imageset/Contents.json b/CovidSafe/Assets.xcassets/CovidSafe/external-link.imageset/Contents.json new file mode 100644 index 0000000..32dd13d --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/external-link.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "external-link 1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CovidSafe/Assets.xcassets/CovidSafe/external-link.imageset/external-link 1.pdf b/CovidSafe/Assets.xcassets/CovidSafe/external-link.imageset/external-link 1.pdf new file mode 100644 index 0000000..d9906f2 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/external-link.imageset/external-link 1.pdf @@ -0,0 +1,198 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.000000 1.000000 cm +0.000000 0.000000 0.000000 scn +16.000000 10.000000 m +16.000000 10.552284 15.552285 11.000000 15.000000 11.000000 c +14.447715 11.000000 14.000000 10.552284 14.000000 10.000000 c +16.000000 10.000000 l +h +0.000000 4.000000 m +-1.000000 4.000000 l +0.000000 4.000000 l +h +2.000000 17.000000 m +2.000000 18.000000 l +2.000000 17.000000 l +h +8.000000 16.000000 m +8.552285 16.000000 9.000000 16.447716 9.000000 17.000000 c +9.000000 17.552284 8.552285 18.000000 8.000000 18.000000 c +8.000000 16.000000 l +h +14.000000 10.000000 m +14.000000 4.000000 l +16.000000 4.000000 l +16.000000 10.000000 l +14.000000 10.000000 l +h +14.000000 4.000000 m +14.000000 3.734784 13.894643 3.480431 13.707107 3.292893 c +15.121320 1.878680 l +15.683928 2.441289 16.000000 3.204350 16.000000 4.000000 c +14.000000 4.000000 l +h +13.707107 3.292893 m +13.519569 3.105357 13.265216 3.000000 13.000000 3.000000 c +13.000000 1.000000 l +13.795650 1.000000 14.558711 1.316072 15.121320 1.878680 c +13.707107 3.292893 l +h +13.000000 3.000000 m +2.000000 3.000000 l +2.000000 1.000000 l +13.000000 1.000000 l +13.000000 3.000000 l +h +2.000000 3.000000 m +1.734784 3.000000 1.480430 3.105357 1.292893 3.292893 c +-0.121320 1.878680 l +0.441288 1.316072 1.204350 1.000000 2.000000 1.000000 c +2.000000 3.000000 l +h +1.292893 3.292893 m +1.105357 3.480430 1.000000 3.734783 1.000000 4.000000 c +-1.000000 4.000000 l +-1.000000 3.204350 -0.683930 2.441289 -0.121320 1.878680 c +1.292893 3.292893 l +h +1.000000 4.000000 m +1.000000 15.000000 l +-1.000000 15.000000 l +-1.000000 4.000000 l +1.000000 4.000000 l +h +1.000000 15.000000 m +1.000000 15.265217 1.105357 15.519570 1.292893 15.707107 c +-0.121320 17.121321 l +-0.683930 16.558712 -1.000000 15.795650 -1.000000 15.000000 c +1.000000 15.000000 l +h +1.292893 15.707107 m +1.480429 15.894643 1.734783 16.000000 2.000000 16.000000 c +2.000000 18.000000 l +1.204351 18.000000 0.441289 17.683929 -0.121320 17.121321 c +1.292893 15.707107 l +h +2.000000 16.000000 m +8.000000 16.000000 l +8.000000 18.000000 l +2.000000 18.000000 l +2.000000 16.000000 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 15.000000 13.000000 cm +0.000000 0.000000 0.000000 scn +0.000000 9.000000 m +-0.552285 9.000000 -1.000000 8.552285 -1.000000 8.000000 c +-1.000000 7.447715 -0.552285 7.000000 0.000000 7.000000 c +0.000000 9.000000 l +h +6.000000 8.000000 m +7.000000 8.000000 l +7.000000 8.552285 6.552285 9.000000 6.000000 9.000000 c +6.000000 8.000000 l +h +5.000000 2.000000 m +5.000000 1.447715 5.447715 1.000000 6.000000 1.000000 c +6.552285 1.000000 7.000000 1.447715 7.000000 2.000000 c +5.000000 2.000000 l +h +0.000000 7.000000 m +6.000000 7.000000 l +6.000000 9.000000 l +0.000000 9.000000 l +0.000000 7.000000 l +h +5.000000 8.000000 m +5.000000 2.000000 l +7.000000 2.000000 l +7.000000 8.000000 l +5.000000 8.000000 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 10.000000 7.804688 cm +0.000000 0.000000 0.000000 scn +-0.707107 2.902419 m +-1.097631 2.511895 -1.097631 1.878730 -0.707107 1.488206 c +-0.316583 1.097681 0.316583 1.097681 0.707107 1.488206 c +-0.707107 2.902419 l +h +11.707107 12.488206 m +12.097631 12.878730 12.097631 13.511895 11.707107 13.902419 c +11.316583 14.292944 10.683417 14.292944 10.292893 13.902419 c +11.707107 12.488206 l +h +0.707107 1.488206 m +11.707107 12.488206 l +10.292893 13.902419 l +-0.707107 2.902419 l +0.707107 1.488206 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 3372 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Type /Catalog + /Pages 5 0 R + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000003462 00000 n +0000003485 00000 n +0000003658 00000 n +0000003732 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +3791 +%%EOF \ No newline at end of file diff --git a/CovidSafe/Assets.xcassets/CovidSafe/home.imageset/Contents.json b/CovidSafe/Assets.xcassets/CovidSafe/home.imageset/Contents.json new file mode 100644 index 0000000..9fa3006 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/home.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "home.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CovidSafe/Assets.xcassets/CovidSafe/home.imageset/home.pdf b/CovidSafe/Assets.xcassets/CovidSafe/home.imageset/home.pdf new file mode 100644 index 0000000..8e0b077 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/home.imageset/home.pdf @@ -0,0 +1,182 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.000000 -0.070190 cm +0.000000 0.000000 0.000000 scn +0.000000 15.070190 m +-0.613941 15.859543 l +-0.857527 15.670086 -1.000000 15.378780 -1.000000 15.070190 c +0.000000 15.070190 l +h +9.000000 22.070190 m +9.613940 22.859543 l +9.252831 23.140406 8.747169 23.140406 8.386060 22.859543 c +9.000000 22.070190 l +h +18.000000 15.070190 m +19.000000 15.070190 l +19.000000 15.378780 18.857527 15.670086 18.613941 15.859543 c +18.000000 15.070190 l +h +0.000000 4.070190 m +-1.000000 4.070190 l +0.000000 4.070190 l +h +0.613941 14.280838 m +9.613940 21.280838 l +8.386060 22.859543 l +-0.613941 15.859543 l +0.613941 14.280838 l +h +8.386060 21.280838 m +17.386059 14.280838 l +18.613941 15.859543 l +9.613940 22.859543 l +8.386060 21.280838 l +h +17.000000 15.070190 m +17.000000 4.070190 l +19.000000 4.070190 l +19.000000 15.070190 l +17.000000 15.070190 l +h +17.000000 4.070190 m +17.000000 3.804976 16.894644 3.550621 16.707106 3.363085 c +18.121321 1.948870 l +18.683929 2.511478 19.000000 3.274540 19.000000 4.070190 c +17.000000 4.070190 l +h +16.707106 3.363085 m +16.519569 3.175547 16.265215 3.070190 16.000000 3.070190 c +16.000000 1.070190 l +16.795650 1.070190 17.558712 1.386261 18.121321 1.948870 c +16.707106 3.363085 l +h +16.000000 3.070190 m +2.000000 3.070190 l +2.000000 1.070190 l +16.000000 1.070190 l +16.000000 3.070190 l +h +2.000000 3.070190 m +1.734784 3.070190 1.480430 3.175547 1.292893 3.363085 c +-0.121320 1.948870 l +0.441288 1.386261 1.204350 1.070190 2.000000 1.070190 c +2.000000 3.070190 l +h +1.292893 3.363085 m +1.105357 3.550621 1.000000 3.804974 1.000000 4.070190 c +-1.000000 4.070190 l +-1.000000 3.274540 -0.683930 2.511480 -0.121320 1.948870 c +1.292893 3.363085 l +h +1.000000 4.070190 m +1.000000 15.070190 l +-1.000000 15.070190 l +-1.000000 4.070190 l +1.000000 4.070190 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 9.000000 0.000000 cm +0.000000 0.000000 0.000000 scn +-1.000000 2.000000 m +-1.000000 1.447715 -0.552285 1.000000 0.000000 1.000000 c +0.552285 1.000000 1.000000 1.447715 1.000000 2.000000 c +-1.000000 2.000000 l +h +0.000000 12.000000 m +0.000000 13.000000 l +-0.552285 13.000000 -1.000000 12.552285 -1.000000 12.000000 c +0.000000 12.000000 l +h +6.000000 12.000000 m +7.000000 12.000000 l +7.000000 12.552285 6.552285 13.000000 6.000000 13.000000 c +6.000000 12.000000 l +h +5.000000 2.000000 m +5.000000 1.447715 5.447715 1.000000 6.000000 1.000000 c +6.552285 1.000000 7.000000 1.447715 7.000000 2.000000 c +5.000000 2.000000 l +h +1.000000 2.000000 m +1.000000 12.000000 l +-1.000000 12.000000 l +-1.000000 2.000000 l +1.000000 2.000000 l +h +0.000000 11.000000 m +6.000000 11.000000 l +6.000000 13.000000 l +0.000000 13.000000 l +0.000000 11.000000 l +h +5.000000 12.000000 m +5.000000 2.000000 l +7.000000 2.000000 l +7.000000 12.000000 l +5.000000 12.000000 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 2806 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Type /Catalog + /Pages 5 0 R + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002896 00000 n +0000002919 00000 n +0000003092 00000 n +0000003166 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +3225 +%%EOF \ No newline at end of file diff --git a/CovidSafe/Assets.xcassets/CovidSafe/map-pin.imageset/Contents.json b/CovidSafe/Assets.xcassets/CovidSafe/map-pin.imageset/Contents.json new file mode 100644 index 0000000..740d393 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/map-pin.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "map-pin 1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CovidSafe/Assets.xcassets/CovidSafe/map-pin.imageset/map-pin 1.pdf b/CovidSafe/Assets.xcassets/CovidSafe/map-pin.imageset/map-pin 1.pdf new file mode 100644 index 0000000..06bebd1 --- /dev/null +++ b/CovidSafe/Assets.xcassets/CovidSafe/map-pin.imageset/map-pin 1.pdf @@ -0,0 +1,251 @@ +%PDF-1.7 + +1 0 obj + << /BBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources << >> + /Subtype /Form + /Length 2 0 R + /Group << /Type /Group + /S /Transparency + >> + /Type /XObject + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.000000 -1.055908 cm +0.000000 0.400000 0.105882 scn +18.000000 15.055908 m +19.000000 15.055908 l +18.000000 15.055908 l +h +9.000000 2.055908 m +8.445300 1.223858 l +8.781199 0.999926 9.218801 0.999926 9.554700 1.223858 c +9.000000 2.055908 l +h +0.000000 15.055908 m +-1.000000 15.055908 l +0.000000 15.055908 l +h +9.000000 24.055908 m +9.000000 23.055908 l +9.000000 24.055908 l +h +17.000000 15.055908 m +17.000000 11.957850 14.984262 8.951658 12.774047 6.618652 c +11.689388 5.473736 10.601333 4.536442 9.783323 3.885063 c +9.375111 3.560005 9.036171 3.307753 8.801229 3.138071 c +8.683807 3.053268 8.592514 2.989199 8.531706 2.947083 c +8.501307 2.926027 8.478540 2.910471 8.463954 2.900564 c +8.456661 2.895611 8.451414 2.892071 8.448282 2.889963 c +8.446716 2.888908 8.445679 2.888214 8.445179 2.887878 c +8.444929 2.887711 8.444814 2.887634 8.444833 2.887648 c +8.444843 2.887653 8.444960 2.887732 8.444964 2.887735 c +8.445115 2.887835 8.445300 2.887959 9.000000 2.055908 c +9.554700 1.223858 9.554954 1.224028 9.555242 1.224218 c +9.555383 1.224314 9.555705 1.224529 9.555988 1.224718 c +9.556556 1.225098 9.557260 1.225567 9.558100 1.226130 c +9.559780 1.227255 9.562004 1.228748 9.564764 1.230604 c +9.570284 1.234318 9.577946 1.239491 9.587682 1.246103 c +9.607153 1.259329 9.634924 1.278318 9.670443 1.302917 c +9.741470 1.352110 9.843536 1.423782 9.972209 1.516714 c +10.229454 1.702501 10.593639 1.973686 11.029177 2.320503 c +11.898667 3.012875 13.060612 4.013081 14.225953 5.243164 c +16.515738 7.660158 19.000000 11.153967 19.000000 15.055908 c +17.000000 15.055908 l +h +9.000000 2.055908 m +9.554700 2.887959 9.554885 2.887835 9.555036 2.887735 c +9.555040 2.887732 9.555157 2.887653 9.555167 2.887648 c +9.555186 2.887634 9.555071 2.887711 9.554821 2.887878 c +9.554321 2.888214 9.553284 2.888908 9.551718 2.889963 c +9.548586 2.892071 9.543339 2.895611 9.536046 2.900564 c +9.521460 2.910471 9.498693 2.926027 9.468294 2.947083 c +9.407486 2.989199 9.316193 3.053268 9.198771 3.138071 c +8.963829 3.307753 8.624889 3.560005 8.216677 3.885063 c +7.398668 4.536442 6.310612 5.473736 5.225953 6.618652 c +3.015737 8.951658 1.000000 11.957850 1.000000 15.055908 c +-1.000000 15.055908 l +-1.000000 11.153967 1.484263 7.660158 3.774047 5.243164 c +4.939388 4.013081 6.101332 3.012875 6.970823 2.320503 c +7.406361 1.973686 7.770545 1.702501 8.027791 1.516714 c +8.156464 1.423782 8.258530 1.352110 8.329557 1.302917 c +8.365076 1.278318 8.392847 1.259329 8.412318 1.246103 c +8.422054 1.239491 8.429716 1.234318 8.435236 1.230604 c +8.437996 1.228748 8.440220 1.227255 8.441900 1.226130 c +8.442740 1.225567 8.443444 1.225098 8.444012 1.224718 c +8.444295 1.224529 8.444617 1.224314 8.444758 1.224218 c +8.445046 1.224028 8.445300 1.223858 9.000000 2.055908 c +h +1.000000 15.055908 m +1.000000 17.177639 1.842855 19.212471 3.343146 20.712763 c +1.928932 22.126976 l +0.053568 20.251612 -1.000000 17.708073 -1.000000 15.055908 c +1.000000 15.055908 l +h +3.343146 20.712763 m +4.843436 22.213053 6.878268 23.055908 9.000000 23.055908 c +9.000000 25.055908 l +6.347835 25.055908 3.804296 24.002340 1.928932 22.126976 c +3.343146 20.712763 l +h +9.000000 23.055908 m +11.121732 23.055908 13.156563 22.213053 14.656854 20.712763 c +16.071068 22.126976 l +14.195704 24.002340 11.652164 25.055908 9.000000 25.055908 c +9.000000 23.055908 l +h +14.656854 20.712763 m +16.157145 19.212471 17.000000 17.177639 17.000000 15.055908 c +19.000000 15.055908 l +19.000000 17.708073 17.946430 20.251614 16.071068 22.126976 c +14.656854 20.712763 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 9.000000 9.000000 cm +0.000000 0.400000 0.105882 scn +5.000000 5.000000 m +5.000000 3.895431 4.104569 3.000000 3.000000 3.000000 c +3.000000 1.000000 l +5.209139 1.000000 7.000000 2.790861 7.000000 5.000000 c +5.000000 5.000000 l +h +3.000000 3.000000 m +1.895430 3.000000 1.000000 3.895431 1.000000 5.000000 c +-1.000000 5.000000 l +-1.000000 2.790861 0.790861 1.000000 3.000000 1.000000 c +3.000000 3.000000 l +h +1.000000 5.000000 m +1.000000 6.104569 1.895430 7.000000 3.000000 7.000000 c +3.000000 9.000000 l +0.790861 9.000000 -1.000000 7.209139 -1.000000 5.000000 c +1.000000 5.000000 l +h +3.000000 7.000000 m +4.104569 7.000000 5.000000 6.104569 5.000000 5.000000 c +7.000000 5.000000 l +7.000000 7.209139 5.209139 9.000000 3.000000 9.000000 c +3.000000 7.000000 l +h +f +n +Q + +endstream +endobj + +2 0 obj + 4340 +endobj + +3 0 obj + << /BBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources << >> + /Subtype /Form + /Length 4 0 R + /Group << /Type /Group + /S /Transparency + >> + /Type /XObject + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +0.000000 0.000000 0.000000 scn +0.000000 24.000000 m +24.000000 24.000000 l +24.000000 0.000000 l +0.000000 0.000000 l +0.000000 24.000000 l +h +f +n +Q + +endstream +endobj + +4 0 obj + 232 +endobj + +5 0 obj + << /XObject << /X1 1 0 R >> + /ExtGState << /E1 << /SMask << /Type /Mask + /G 3 0 R + /S /Alpha + >> + /Type /ExtGState + >> >> + >> +endobj + +6 0 obj + << /Length 7 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +/E1 gs +/X1 Do +Q + +endstream +endobj + +7 0 obj + 46 +endobj + +8 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 5 0 R + /Contents 6 0 R + /Parent 9 0 R + >> +endobj + +9 0 obj + << /Kids [ 8 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +10 0 obj + << /Type /Catalog + /Pages 9 0 R + >> +endobj + +xref +0 11 +0000000000 65535 f +0000000010 00000 n +0000004598 00000 n +0000004621 00000 n +0000005101 00000 n +0000005123 00000 n +0000005421 00000 n +0000005523 00000 n +0000005544 00000 n +0000005717 00000 n +0000005791 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 10 0 R + /Size 11 +>> +startxref +5851 +%%EOF \ No newline at end of file diff --git a/CovidSafe/Base.lproj/Main.storyboard b/CovidSafe/Base.lproj/Main.storyboard index 8a493b9..3377d59 100644 --- a/CovidSafe/Base.lproj/Main.storyboard +++ b/CovidSafe/Base.lproj/Main.storyboard @@ -12,7 +12,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -96,12 +96,26 @@ + + + + + + + + + + + + + + @@ -111,7 +125,6 @@ - @@ -179,6 +192,7 @@ + @@ -192,7 +206,7 @@ - + @@ -2280,7 +2294,7 @@ See the COVIDSafe *privacy policy* for further details about your rights about y - + diff --git a/CovidSafe/Base.lproj/UploadData.storyboard b/CovidSafe/Base.lproj/UploadData.storyboard index cb16535..a39bfa3 100644 --- a/CovidSafe/Base.lproj/UploadData.storyboard +++ b/CovidSafe/Base.lproj/UploadData.storyboard @@ -1,10 +1,11 @@ - + - + + @@ -61,7 +62,7 @@ - + @@ -87,7 +88,7 @@ - + @@ -115,7 +116,7 @@ - - + - + - + + - + + + - + @@ -332,7 +349,8 @@ Please do not close the app. - + + @@ -343,8 +361,10 @@ Please do not close the app. - + + + @@ -399,11 +419,11 @@ Please do not close the app. - + Only if you test positive to COVID-19 will a state or territory health official contact you to assist with voluntary upload of your information. Once you press ‘Yes’ you’ll need to provide consent to upload your information. - + @@ -411,7 +431,7 @@ Once you press ‘Yes’ you’ll need to provide consent to upload your informa - + @@ -458,7 +478,7 @@ Once you press ‘Yes’ you’ll need to provide consent to upload your informa - - - + + @@ -515,7 +536,6 @@ Once you press ‘Yes’ you’ll need to provide consent to upload your informa - @@ -550,13 +570,13 @@ Once you press ‘Yes’ you’ll need to provide consent to upload your informa - + Unless you consent, your close contact information will not be uploaded. If you consent, your close contact information will be uploaded and shared with state or territory health officials for contact tracing purposes. Read the COVIDSafe *privacy policy* for further details. - + @@ -587,7 +607,7 @@ Read the COVIDSafe *privacy policy* for further details. - + @@ -613,7 +633,7 @@ Read the COVIDSafe *privacy policy* for further details. - - + + @@ -646,7 +667,6 @@ Read the COVIDSafe *privacy policy* for further details. - @@ -692,11 +712,11 @@ Read the COVIDSafe *privacy policy* for further details. - + You have successfully uploaded your information to the COVIDSafe highly secure storage system. State or territory health officials will notify other COVIDSafe users that have recorded instances of close contact with you. Your identity will remain anonymous to other users. - + @@ -704,7 +724,7 @@ State or territory health officials will notify other COVIDSafe users that have - + @@ -749,7 +769,7 @@ State or territory health officials will notify other COVIDSafe users that have - - + + @@ -779,7 +800,6 @@ State or territory health officials will notify other COVIDSafe users that have - @@ -792,11 +812,37 @@ State or territory health officials will notify other COVIDSafe users that have + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CovidSafe/CSGenericContentView.xib b/CovidSafe/CSGenericContentView.xib index 2b2d388..a7ee035 100644 --- a/CovidSafe/CSGenericContentView.xib +++ b/CovidSafe/CSGenericContentView.xib @@ -1,9 +1,9 @@ - + - + @@ -89,7 +89,7 @@ Praesent viverra pretium lobortis. In laoreet at leo non viverra. Nullam sagitti - + diff --git a/CovidSafe/ChangePostcodeViewController.swift b/CovidSafe/ChangePostcodeViewController.swift new file mode 100644 index 0000000..8dbb3d8 --- /dev/null +++ b/CovidSafe/ChangePostcodeViewController.swift @@ -0,0 +1,186 @@ +// +// ChangePostcodeViewController.swift +// CovidSafe +// +// Copyright © 2021 Australian Government. All rights reserved. +// + +import UIKit +import Lottie + +class ChangePostcodeViewController: UIViewController { + + @IBOutlet weak var continueButton: UIButton! + @IBOutlet weak var postcodeTextField: UITextField! + @IBOutlet weak var postcodeErrorLabel: UILabel! + @IBOutlet weak var changePostcodeTextView: UITextView! + + var nextBarButtonItem: UIBarButtonItem? + var initialTextFieldBorderColour: UIColor? + + override func viewDidLoad() { + super.viewDidLoad() + self.postcodeTextField.delegate = self + initialTextFieldBorderColour = postcodeTextField.borderColor + updateContinueButton() + + let toolBar = UIToolbar() + toolBar.sizeToFit() + nextBarButtonItem = UIBarButtonItem(title: "Done".localizedString(), + style: .plain, + target: self, + action: #selector(self.doneButtonTapped)) + let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) + toolBar.setItems([spacer, self.nextBarButtonItem!], animated: true) + toolBar.isUserInteractionEnabled = true + postcodeTextField.inputAccessoryView = toolBar + + changePostcodeTextView.addLink(URLHelper.getPrivacyPolicyURL(), enclosedIn: "*") + changePostcodeTextView.addLink(URLHelper.getCollectionNoticeURL(), enclosedIn: "*") + + } + + func updateContinueButton() { + + if (self.postcodeTextField.text != "" && + self.postcodeErrorLabel.isHidden) { + + self.continueButton.isEnabled = true + self.continueButton.backgroundColor = UIColor.covidSafeButtonDarkerColor + } else { + self.continueButton.backgroundColor = UIColor(0xDBDDDD) + self.continueButton.isEnabled = false + } + } + + fileprivate func changePostcodeSuccess() { + + guard let successVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "registrationSuccess") as? RegistrationSuccessViewController else { + return + } + // force view to load + _ = successVC.view + successVC.titleLabel.text = "postcode_success".localizedString() + navigationController?.pushViewController(successVC, animated: true) + } + + fileprivate func toggleLoadingView() { + if loadingAnimationView.isHidden { + continueButton.isHidden = true + loadingAnimationView.isHidden = false + startAnimation() + } else { + stopAnimation() + continueButton.isHidden = false + loadingAnimationView.isHidden = true + } + } + + fileprivate func setChangePostcodeFailed() { + postcodeErrorLabel.isHidden = false + postcodeErrorLabel.text = "postcode_api_error".localizedString() + postcodeTextField.borderColor = UIColor.covidSafeErrorColor + if UIAccessibility.isVoiceOverRunning { + UIAccessibility.post(notification: .layoutChanged, argument: postcodeErrorLabel) + } + } + + @objc + func doneButtonTapped() { + postcodeTextField.resignFirstResponder() + } + + @IBAction func continueButtonTapped(_ sender: Any) { + postcodeErrorLabel.isHidden = true + postcodeTextField.borderColor = initialTextFieldBorderColour + + guard let newPostcode = postcodeTextField.text else { + return + } + + toggleLoadingView() + + ChangePostcodeAPI.changePostcode(newPostcode: newPostcode) { (apiError) in + defer { + self.toggleLoadingView() + } + + if apiError != nil { + self.setChangePostcodeFailed() + return + } + + // if succeeds + self.changePostcodeSuccess() + } + + } + + @IBAction func backButtonTapped(_ sender: Any) { + navigationController?.popViewController(animated: true) + } + + // MARK: Loading animation + + @IBOutlet weak var loadingAnimationView: UIView! + + var lottieLoadingView: AnimationView? + + func startAnimation() { + if lottieLoadingView == nil { + let loadingAnimation = AnimationView(name: "Spinner_upload") + loadingAnimation.loopMode = .loop + loadingAnimation.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: loadingAnimationView.frame.size) + loadingAnimationView.addSubview(loadingAnimation) + lottieLoadingView = loadingAnimation + } + lottieLoadingView?.play() + } + + func stopAnimation() { + lottieLoadingView?.stop() + } +} + +extension ChangePostcodeViewController: UITextFieldDelegate { + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + + if (string == "") { + return true + } + + if (textField == postcodeTextField) { + let isNumeric = CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: string)) + if (!isNumeric) { + return false + } + } + if (textField == postcodeTextField && postcodeTextField.text != nil) { + guard let text = postcodeTextField.text else { + return false + } + let newLength = text.count + string.count - range.length + return newLength <= 4 + } + return true + } + + func textFieldDidEndEditing(_ textField: UITextField) { + if textField == postcodeTextField { + if textField.text?.count != 4 { + postcodeErrorLabel.isHidden = false + postcodeErrorLabel.text = "personal_details_post_code_error_prompt".localizedString() + postcodeTextField.borderColor = UIColor.covidSafeErrorColor + if UIAccessibility.isVoiceOverRunning { + UIAccessibility.post(notification: .layoutChanged, argument: postcodeErrorLabel) + } + } else { + postcodeErrorLabel.isHidden = true + postcodeTextField.borderColor = initialTextFieldBorderColour + } + } + updateContinueButton() + } + +} diff --git a/CovidSafe/ChangePostcodeViewController.xib b/CovidSafe/ChangePostcodeViewController.xib new file mode 100644 index 0000000..0ec7599 --- /dev/null +++ b/CovidSafe/ChangePostcodeViewController.xib @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Have you moved to a different postcode area since you registered to use COVIDSafe? Keeping your postcode up to date can assist health officials to undertake contact tracing. + +Read the COVIDSafe privacy policy for further details about how your information is stored and shared. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CovidSafe/CovidStatisticsViewController.swift b/CovidSafe/CovidStatisticsViewController.swift index 3c3f1cb..21a18f7 100644 --- a/CovidSafe/CovidStatisticsViewController.swift +++ b/CovidSafe/CovidStatisticsViewController.swift @@ -15,6 +15,7 @@ class CovidStatisticsViewController: UITableViewController { private let heartImage = UIImage(named: "heart") private let virusMoleculeImage = UIImage(named: "virus-molecule") private let trendUpImage = UIImage(named: "trending-up") + private let alertTriangleImage = UIImage(named: "alert-triangle") private var statisticsUpdatedDate: Date? private var showError: Bool = false @@ -30,10 +31,19 @@ class CovidStatisticsViewController: UITableViewController { UserDefaults.standard.set(showStatistics, forKey: showHideStatisticsKey) } } + private lazy var statisticForStateTerritory: StateTerritory = { + guard let value = UserDefaults.standard.string(forKey: statisticsStateTerritorySelectedKey) else { + return StateTerritory.AU + } + return StateTerritory(rawValue: value)! + }() + private var statisticsData: StatisticsResponse? private var statisticSections: [[StatisticRowModel]] = [] var statisticsDelegate: StatisticsDelegate? + var homeDelegate: HomeDelegate? + var contentSizeKVOToken: NSKeyValueObservation? var isLoading = false { didSet { @@ -45,21 +55,26 @@ class CovidStatisticsViewController: UITableViewController { super.viewDidLoad() tableView.isScrollEnabled = false + tableView.register(UINib(nibName: "ExternalLinkTableViewCell", bundle: nil), forCellReuseIdentifier: "ExternalLinkTableViewCell") tableView.register(UINib(nibName: "StatDetailedCell", bundle: nil), forCellReuseIdentifier: "StatDetailedCell") tableView.register(UINib(nibName: "MainStatisticsHeader", bundle: nil), forCellReuseIdentifier: "MainStatisticsHeader") tableView.register(UINib(nibName: "StatisticsTableHeader", bundle: nil), forCellReuseIdentifier: "StatisticsHeader") tableView.register(UINib(nibName: "LoadingViewCell", bundle: nil), forCellReuseIdentifier: "LoadingViewCell") + getStatistics() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil) + contentSizeKVOToken = tableView.observe(\.contentSize, options: .new) { (tableView, change) in + if let newsize = change.newValue { + self.statisticsDelegate?.setStatisticsContainerHeight(height: newsize.height) + } + } } override func viewWillDisappear(_ animated: Bool) { - tableView.removeObserver(self, forKeyPath: "contentSize") super.viewWillDisappear(true) + contentSizeKVOToken?.invalidate() } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?){ @@ -72,6 +87,30 @@ class CovidStatisticsViewController: UITableViewController { } } + // MARK: Retrieve Statistics from API + + func getStatistics() { + if showStatistics { + isLoading = true + StatisticsAPI.getStatistics(forState: statisticForStateTerritory) { (stats, error) in + let hasInternet = self.homeDelegate?.isInternetReachable() ?? false + + if error != nil { + switch error { + case .TokenExpiredError: + self.homeDelegate?.showTokenExpiredMessage() + default: + // do nothing special + break + } + } + + self.isLoading = false + self.setupData(statistics: stats, errorType: error, hasInternet: hasInternet) + } + } + } + // MARK: Process data for the table func setupData(statistics: StatisticsResponse?, errorType: CovidSafeAPIError?, hasInternet: Bool) { @@ -87,12 +126,12 @@ class CovidStatisticsViewController: UITableViewController { if !hasInternet { showInternetError = true } - - processData(statisticsData: statistics) + statisticsData = statistics + processData(statisticsData: statisticsData, forState: statisticForStateTerritory) reloadTable() } - fileprivate func processData(statisticsData: StatisticsResponse?) { + fileprivate func processData(statisticsData: StatisticsResponse?, forState: StateTerritory) { statisticSections = [] guard let statisticsData = statisticsData else { // this is the edge case of no data available. @@ -100,7 +139,6 @@ class CovidStatisticsViewController: UITableViewController { statisticSections.append([]) return } - let mainData = statisticsData.national // Set updated date if let updatedDate = statisticsData.updatedDate { @@ -111,55 +149,117 @@ class CovidStatisticsViewController: UITableViewController { } var mainSectionData: [StatisticRowModel] = [] + let nationalData = statisticsData.national - if let cases = mainData?.newCases { - mainSectionData.append(StatisticRowModel(number: cases, description: "new_cases".localizedString(), image: trendUpImage)) + if statisticsData.version() == 2 { + var stateData = statisticsData.national + switch forState { + case .ACT: + stateData = statisticsData.act + case .NSW: + stateData = statisticsData.nsw + case .NT: + stateData = statisticsData.nt + case .SA: + stateData = statisticsData.sa + case .TAS: + stateData = statisticsData.tas + case .VIC: + stateData = statisticsData.vic + case .WA: + stateData = statisticsData.wa + case .QLD: + stateData = statisticsData.qld + default: + stateData = statisticsData.national + } + + let descriptionFormat = "%@\r\r%@" + + // New cases section + let newCases = stateData?.newCases ?? 0 + let localCases = stateData?.newLocallyAcquired ?? 0 + let overseasCases = stateData?.newOverseasAcquired ?? 0 + var bottomDesc = "\(String.localizedStringWithFormat("locally_acquired".localizedString(), "\(localCases)"))\r\(String.localizedStringWithFormat( "overseas_acquired".localizedString(), "\(overseasCases)"))" + var description = String.localizedStringWithFormat(descriptionFormat, "new_cases".localizedString(), bottomDesc) + var attributedDesc = NSMutableAttributedString(string: description) + + attributedDesc.addAttribute(.font, + value: UIFont.preferredFont(for: .callout, weight: .semibold), + range: NSRange(description.range(of: "\(localCases)")!, in: description)) + attributedDesc.addAttribute(.font, + value: UIFont.preferredFont(for: .callout, weight: .semibold), + range: NSRange(description.range(of: "\(overseasCases)")!, in: description)) + + mainSectionData.append(StatisticRowModel(number: newCases, description: attributedDesc, image: trendUpImage)) + + // Active cases section + let activeCases = stateData?.activeCases ?? 0 + let totalDeaths = stateData?.deaths ?? 0 + + bottomDesc = String.localizedStringWithFormat("total_deaths".localizedString(), "\(totalDeaths)") + description = String.localizedStringWithFormat(descriptionFormat, "active_cases".localizedString(), bottomDesc) + attributedDesc = NSMutableAttributedString(string: description) + attributedDesc.addAttribute(.font, + value: UIFont.preferredFont(for: .callout, weight: .semibold), + range: NSRange(description.range(of: "\(totalDeaths)")!, in: description)) + + mainSectionData.append(StatisticRowModel(number: activeCases, description: attributedDesc, image: virusMoleculeImage)) + + statisticSections.append(mainSectionData) + + } else { + // we keep old design/data shown in case the response does not have state based data + if let cases = nationalData?.newCases { + mainSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "new_cases".localizedString()), image: trendUpImage)) + } + + if let cases = nationalData?.totalCases { + mainSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "total_confirmed_cases".localizedString()), image: virusMoleculeImage)) + } + + if let cases = nationalData?.recoveredCases { + mainSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "recovered".localizedString()), image: heartImage)) + } + + if let cases = nationalData?.deaths { + mainSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "deaths".localizedString()), image: virusMoleculeImage, imageBackgroundColor: UIColor.covidSafeLightGreyColor)) + } + + statisticSections.append(mainSectionData) + + var statesSectionData: [StatisticRowModel] = [] + + if let cases = statisticsData.act?.totalCases { + statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "australian_capital_territory".localizedString()))) + } + if let cases = statisticsData.nsw?.totalCases { + statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "new_south_wales".localizedString()))) + } + if let cases = statisticsData.nt?.totalCases { + statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "northern_territory".localizedString()))) + } + if let cases = statisticsData.qld?.totalCases { + statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "queensland".localizedString()))) + } + if let cases = statisticsData.sa?.totalCases { + statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "south_australia".localizedString()))) + } + if let cases = statisticsData.tas?.totalCases { + statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "tasmania".localizedString()))) + } + if let cases = statisticsData.vic?.totalCases { + statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "victoria".localizedString()))) + } + if let cases = statisticsData.wa?.totalCases { + statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "western_australia".localizedString()))) + } + + if statesSectionData.count > 0 { + statisticSections.append(statesSectionData) + } } - if let cases = mainData?.totalCases { - mainSectionData.append(StatisticRowModel(number: cases, description: "total_confirmed_cases".localizedString(), image: virusMoleculeImage)) - } - - if let cases = mainData?.recoveredCases { - mainSectionData.append(StatisticRowModel(number: cases, description: "recovered".localizedString(), image: heartImage)) - } - - if let cases = mainData?.deaths { - mainSectionData.append(StatisticRowModel(number: cases, description: "deaths".localizedString(), image: virusMoleculeImage, imageBackgroundColor: UIColor.covidSafeLightGreyColor)) - } - - statisticSections.append(mainSectionData) - - var statesSectionData: [StatisticRowModel] = [] - - if let cases = statisticsData.act?.totalCases { - statesSectionData.append(StatisticRowModel(number: cases, description: "australian_capital_territory".localizedString())) - } - if let cases = statisticsData.nsw?.totalCases { - statesSectionData.append(StatisticRowModel(number: cases, description: "new_south_wales".localizedString())) - } - if let cases = statisticsData.nt?.totalCases { - statesSectionData.append(StatisticRowModel(number: cases, description: "northern_territory".localizedString())) - } - if let cases = statisticsData.qld?.totalCases { - statesSectionData.append(StatisticRowModel(number: cases, description: "queensland".localizedString())) - } - if let cases = statisticsData.sa?.totalCases { - statesSectionData.append(StatisticRowModel(number: cases, description: "south_australia".localizedString())) - } - if let cases = statisticsData.tas?.totalCases { - statesSectionData.append(StatisticRowModel(number: cases, description: "tasmania".localizedString())) - } - if let cases = statisticsData.vic?.totalCases { - statesSectionData.append(StatisticRowModel(number: cases, description: "victoria".localizedString())) - } - if let cases = statisticsData.wa?.totalCases { - statesSectionData.append(StatisticRowModel(number: cases, description: "western_australia".localizedString())) - } - - if statesSectionData.count > 0 { - statisticSections.append(statesSectionData) - } } // MARK: Table view delegate @@ -175,13 +275,18 @@ class CovidStatisticsViewController: UITableViewController { if section == 0 { let headerView = tableView.dequeueReusableCell(withIdentifier: "MainStatisticsHeader") as! MainStatisticsHeaderViewCell - headerView.titleLabel.font = UIFont.preferredFont(for: .title3, weight: .semibold) headerView.statisticsDelegate = statisticsDelegate headerView.statisticsTableDelegate = self + let shouldDisplayStateSelection = (statisticsData?.version() ?? 0) >= 2 let hideShowLabel = showStatistics ? "hide".localizedString() : "show".localizedString() headerView.hideShowButton.setTitle(hideShowLabel, for: .normal) + headerView.selectStateTerritoryContainer.isHidden = !showStatistics || !shouldDisplayStateSelection + headerView.titleLabel.text = (statisticForStateTerritory == StateTerritory.AU || !shouldDisplayStateSelection) ? "national_numbers".localizedString() : String.localizedStringWithFormat( + "state_number_heading".localizedString(), + statisticForStateTerritory.rawValue + ) if let updateDate = statisticsUpdatedDate, showStatistics { let dateFormatter = DateFormatter() @@ -271,23 +376,33 @@ class CovidStatisticsViewController: UITableViewController { // detailed stat row if indexPath.section == 0 { - let cellView = tableView.dequeueReusableCell(withIdentifier: "StatDetailedCell", for: indexPath) as! StatDetailedViewCell let rowData = statisticSections[indexPath.section][indexPath.row] - - cellView.statImage?.image = rowData.image - cellView.statDescription.text = rowData.description - cellView.statNumberLabel.text = NumberFormatter.localizedString(from: NSNumber(value: rowData.number), number: .decimal) - if #available(iOS 11.0, *) { - cellView.statNumberLabel.font = UIFont.preferredFont(for: .largeTitle, weight: .semibold) + if rowData.cellType == .Link { + let cellView = tableView.dequeueReusableCell(withIdentifier: "ExternalLinkTableViewCell", for: indexPath) as! ExternalLinkTableViewCell + + cellView.cellImage.image = rowData.image + cellView.linkDescription.attributedText = rowData.description + cellView.externalLinkURL = rowData.urlLink + + return cellView } else { - // Fallback on earlier versions - cellView.statNumberLabel.font = UIFont.preferredFont(for: .title1, weight: .semibold) + let cellView = tableView.dequeueReusableCell(withIdentifier: "StatDetailedCell", for: indexPath) as! StatDetailedViewCell + + cellView.statImage?.image = rowData.image + cellView.statDescription.attributedText = rowData.description + cellView.statNumberLabel.text = NumberFormatter.localizedString(from: NSNumber(value: rowData.number), number: .decimal) + if #available(iOS 11.0, *) { + cellView.statNumberLabel.font = UIFont.preferredFont(for: .largeTitle, weight: .semibold) + } else { + // Fallback on earlier versions + cellView.statNumberLabel.font = UIFont.preferredFont(for: .title1, weight: .semibold) + } + if let bkgColor = rowData.imageBackgroundColor { + cellView.imageBackgroundColor = bkgColor + } + + return cellView } - if let bkgColor = rowData.imageBackgroundColor { - cellView.imageBackgroundColor = bkgColor - } - - return cellView } // Simple stat row @@ -302,7 +417,7 @@ class CovidStatisticsViewController: UITableViewController { let rowData = statisticSections[indexPath.section][indexPath.row] - cellView!.textLabel?.text = rowData.description + cellView!.textLabel?.attributedText = rowData.description cellView!.detailTextLabel?.text = NumberFormatter.localizedString(from: NSNumber(value: rowData.number), number: .decimal) return cellView! @@ -317,7 +432,7 @@ extension CovidStatisticsViewController: StatisticsTableDelegate { showStatistics = !showStatistics if showStatistics && statisticSections.count == 0 { - statisticsDelegate?.refreshStatistics() + refreshStatistics() } else { UIView.transition(with: tableView, duration: 0.3, @@ -325,6 +440,29 @@ extension CovidStatisticsViewController: StatisticsTableDelegate { animations: { self.reloadTable() }) } } + + func refreshStatistics() { + getStatistics() + } + + func changeStateTerritoryStatistics() { + let selectStateTerritoryViewController = SelectStateTerritoryViewController() + selectStateTerritoryViewController.delegate = self + let navController = UINavigationController(rootViewController: selectStateTerritoryViewController) + + present(navController, animated: true, completion: nil) + } +} + +// MARK: Selected state territory delegate + +extension CovidStatisticsViewController: StateTerritorySelectionDelegate { + + func didChangeStateTerritory(selectedState: StateTerritory) { + statisticForStateTerritory = selectedState + getStatistics() + } + } // MARK: Table view cells @@ -351,16 +489,34 @@ class MainStatisticsHeaderViewCell: UITableViewCell { @IBOutlet weak var refreshViewContainer: UIView! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var hideShowButton: UIButton! + @IBOutlet weak var selectStateLabel: UILabel! + @IBOutlet weak var selectStateTerritoryContainer: UIStackView! var statisticsDelegate: StatisticsDelegate? var statisticsTableDelegate: StatisticsTableDelegate? + override func awakeFromNib() { + super.awakeFromNib() + titleLabel.font = UIFont.preferredFont(for: .title3, weight: .semibold) + let selectStateTerritoryTapGesture = UITapGestureRecognizer(target: self, action: #selector(selectStateTerritoryTapped)) + selectStateLabel.addGestureRecognizer(selectStateTerritoryTapGesture) + let selectStateText = NSMutableAttributedString(string: "select_state_territory_button".localizedString(), + attributes: [.font: UIFont.preferredFont(forTextStyle: .callout), + .underlineStyle: NSUnderlineStyle.single.rawValue]) + selectStateLabel.attributedText = selectStateText + } + @IBAction func refreshButtonTapped(_ sender: Any) { - statisticsDelegate?.refreshStatistics() + statisticsTableDelegate?.refreshStatistics() } @IBAction func showHideButtonTapped(_ sender: Any) { statisticsTableDelegate?.toggleDisplayStatistics() + selectStateTerritoryContainer.isHidden = !selectStateTerritoryContainer.isHidden + } + + @IBAction func selectStateTerritoryTapped(_ sender: Any) { + statisticsTableDelegate?.changeStateTerritoryStatistics() } } @@ -390,18 +546,25 @@ class LoadingViewCell: UITableViewCell { protocol StatisticsTableDelegate { func toggleDisplayStatistics() + func changeStateTerritoryStatistics() + func refreshStatistics() } protocol StatisticsDelegate { - func refreshStatistics() func setStatisticsContainerHeight(height: CGFloat) } // MARK: Statistics row model +enum StatisticCellType { + case Link, Detail +} + struct StatisticRowModel { var number: Int - var description: String + var description: NSAttributedString var image: UIImage? var imageBackgroundColor: UIColor? + var urlLink: URL? + var cellType: StatisticCellType? } diff --git a/CovidSafe/Encounter+CoreDataProperties.swift b/CovidSafe/Encounter+CoreDataProperties.swift index 99c827f..f048bae 100644 --- a/CovidSafe/Encounter+CoreDataProperties.swift +++ b/CovidSafe/Encounter+CoreDataProperties.swift @@ -65,6 +65,23 @@ extension Encounter { return fetchRequest } + // Fetch encounters in the number of days given. + @nonobjc public class func fetchEncountersForYesterday() -> NSFetchRequest? { + let fetchRequest = NSFetchRequest(entityName: "Encounter") + + // Get the current calendar with local time zone + var calendar = Calendar.current + calendar.timeZone = NSTimeZone.local + // Get date x days ago + let today = calendar.startOfDay(for: Date()) + guard let dateTo = calendar.date(byAdding: .day, value: -1, to: today) else { + return nil + } + // Set predicate as date since x days ago + fetchRequest.predicate = NSPredicate(format: "timestamp >= %@ && timestamp <= %@", dateTo as NSDate, today as NSDate) + return fetchRequest + } + @NSManaged public var timestamp: Date? @NSManaged public var org: String? @NSManaged public var v: NSNumber? diff --git a/CovidSafe/EncounterMessageManager.swift b/CovidSafe/EncounterMessageManager.swift index c6e0887..8d20601 100644 --- a/CovidSafe/EncounterMessageManager.swift +++ b/CovidSafe/EncounterMessageManager.swift @@ -284,9 +284,10 @@ public extension PayloadData { let message = decodedPayload.msg return String(message.suffix(25)) } catch { - let startIndex = count >= 3 ? 3 : 0 - let endIndex = count >= 3 ? count-3 : 0 - return String(subdata(in: startIndex.. 0 else { + return "" + } + return String(self.base64EncodedString().prefix(6)) } } } diff --git a/CovidSafe/ExternalLinkTableViewCell.swift b/CovidSafe/ExternalLinkTableViewCell.swift new file mode 100644 index 0000000..2f58a5d --- /dev/null +++ b/CovidSafe/ExternalLinkTableViewCell.swift @@ -0,0 +1,26 @@ +// +// ExternalLinkTableViewCell.swift +// CovidSafe +// +// Copyright © 2020 Australian Government. All rights reserved. +// + +import UIKit +import SafariServices + +class ExternalLinkTableViewCell: UITableViewCell { + + @IBOutlet weak var cellImage: UIImageView! + @IBOutlet weak var linkDescription: UILabel! + var externalLinkURL: URL? + + @IBAction func openExternalLinkTapped(_ sender: Any) { + guard let linkToOpen = externalLinkURL else { + return + } + + let safariVC = SFSafariViewController(url: linkToOpen) + UIApplication.shared.keyWindow?.rootViewController?.present(safariVC, animated: true, completion: nil) + + } +} diff --git a/CovidSafe/ExternalLinkTableViewCell.xib b/CovidSafe/ExternalLinkTableViewCell.xib new file mode 100644 index 0000000..d4b08db --- /dev/null +++ b/CovidSafe/ExternalLinkTableViewCell.xib @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CovidSafe/Herald/Sensor/BLE/BLEDatabase.swift b/CovidSafe/Herald/Sensor/BLE/BLEDatabase.swift index fb65b4f..224df78 100644 --- a/CovidSafe/Herald/Sensor/BLE/BLEDatabase.swift +++ b/CovidSafe/Herald/Sensor/BLE/BLEDatabase.swift @@ -316,7 +316,7 @@ typealias BLE_RSSI = Int typealias BLE_TxPower = Int class BLEPseudoDeviceAddress { - let address: Int + let address: Int64 let data: Data var description: String { get { return "BLEPseudoDeviceAddress(address=\(address),data=\(data.base64EncodedString()))" @@ -338,6 +338,6 @@ class BLEPseudoDeviceAddress { guard let longValue = longValueData.int64(0) else { return nil } - address = Int(longValue) + address = Int64(longValue) } } diff --git a/CovidSafe/Herald/Sensor/BLE/BLEReceiver.swift b/CovidSafe/Herald/Sensor/BLE/BLEReceiver.swift index 301e557..01bf1aa 100644 --- a/CovidSafe/Herald/Sensor/BLE/BLEReceiver.swift +++ b/CovidSafe/Herald/Sensor/BLE/BLEReceiver.swift @@ -41,7 +41,7 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral /// Payload data supplier for parsing shared payloads private let payloadDataSupplier: PayloadDataSupplier /// Central manager for managing all connections, using a single manager for simplicity. - private var central: CBCentralManager! + private var central: CBCentralManager? /// Dummy data for writing to the transmitter to trigger state restoration or resume from suspend state to background state. private let emptyData = Data(repeating: 0, count: 0) /** @@ -93,26 +93,26 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral CBCentralManagerOptionShowPowerAlertKey : false]) } // Start scanning - if central.state == .poweredOn { + if central?.state == .poweredOn { scan("start") } } func stop() { logger.debug("stop") - guard central != nil else { + guard let central = central else { return } guard central.isScanning else { logger.fault("stop denied, already stopped") - central = nil + self.central = nil return } // Stop scanning scanTimer?.cancel() scanTimer = nil queue.async { - self.central.stopScan() + central.stopScan() self.central = nil } // Cancel all connections, the resulting didDisconnect and didFailToConnect @@ -129,7 +129,7 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral func scan(_ source: String) { statistics.add() logger.debug("scan (source=\(source),statistics={\(statistics.description)})") - guard central.state == .poweredOn else { + guard central?.state == .poweredOn else { logger.fault("scan failed, bluetooth is not powered on") return } @@ -226,7 +226,7 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral */ private func taskScanForPeripherals() { // Scan for peripherals -> didDiscover - central.scanForPeripherals( + central?.scanForPeripherals( withServices: [BLESensorConfiguration.serviceUUID], options: [CBCentralManagerScanOptionSolicitedServiceUUIDsKey: [BLESensorConfiguration.serviceUUID]]) } @@ -235,7 +235,7 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral Register all connected peripherals advertising the sensor service as a device. */ private func taskRegisterConnectedPeripherals() { - central.retrieveConnectedPeripherals(withServices: [BLESensorConfiguration.serviceUUID]).forEach() { peripheral in + central?.retrieveConnectedPeripherals(withServices: [BLESensorConfiguration.serviceUUID]).forEach() { peripheral in let targetIdentifier = TargetIdentifier(peripheral: peripheral) let device = database.device(targetIdentifier) if device.peripheral == nil || device.peripheral != peripheral { @@ -255,8 +255,8 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral guard let identifier = UUID(uuidString: device.identifier) else { return } - let peripherals = central.retrievePeripherals(withIdentifiers: [identifier]) - if let peripheral = peripherals.last { + + if let peripherals = central?.retrievePeripherals(withIdentifiers: [identifier]), let peripheral = peripherals.last { logger.debug("taskResolveDevicePeripherals (resolved=\(device))") _ = database.device(peripheral, delegate: self) } @@ -499,13 +499,16 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral private func connect(_ source: String, _ peripheral: CBPeripheral) { let device = database.device(peripheral, delegate: self) logger.debug("connect (source=\(source),device=\(device))") - guard central.state == .poweredOn else { + guard central?.state == .poweredOn else { logger.fault("connect denied, central not powered on (source=\(source),device=\(device))") return } queue.async { device.lastConnectRequestedAt = Date() - self.central.retrievePeripherals(withIdentifiers: [peripheral.identifier]).forEach { + guard let central = self.central else { + return + } + central.retrievePeripherals(withIdentifiers: [peripheral.identifier]).forEach { if $0.state != .connected { // Check to see if Herald has initiated a connection attempt before if let lastAttempt = device.lastConnectionInitiationAttempt { @@ -514,17 +517,17 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral // If timeout reached, force disconnect self.logger.fault("connect, timeout forcing disconnect (source=\(source),device=\(device),elapsed=\(-lastAttempt.timeIntervalSinceNow))") device.lastConnectionInitiationAttempt = nil - self.queue.async { self.central.cancelPeripheralConnection(peripheral) } + self.queue.async { central.cancelPeripheralConnection(peripheral) } } else { // If not timed out yet, keep trying self.logger.debug("connect, retrying (source=\(source),device=\(device),elapsed=\(-lastAttempt.timeIntervalSinceNow))") - self.central.connect($0) + central.connect($0) } } else { // If not, connect now self.logger.debug("connect, initiation (source=\(source),device=\(device))") device.lastConnectionInitiationAttempt = Date() - self.central.connect($0) + central.connect($0) } } else { self.taskInitiateNextAction("connect|" + source, peripheral: $0) @@ -547,7 +550,7 @@ class ConcreteBLEReceiver: NSObject, BLEReceiver, BLEDatabaseDelegate, CBCentral logger.fault("disconnect denied, peripheral not connected or connecting (source=\(source),peripheral=\(targetIdentifier))") return } - queue.async { self.central.cancelPeripheralConnection(peripheral) } + queue.async { self.central?.cancelPeripheralConnection(peripheral) } } /// Read RSSI diff --git a/CovidSafe/Herald/Sensor/BLE/BLETransmitter.swift b/CovidSafe/Herald/Sensor/BLE/BLETransmitter.swift index d0b8fe8..fbb6556 100644 --- a/CovidSafe/Herald/Sensor/BLE/BLETransmitter.swift +++ b/CovidSafe/Herald/Sensor/BLE/BLETransmitter.swift @@ -48,7 +48,7 @@ class ConcreteBLETransmitter : NSObject, BLETransmitter, CBPeripheralManagerDele /// Beacon code generator for creating cryptographically secure public codes that can be later used for on-device matching. private let payloadDataSupplier: PayloadDataSupplier /// Peripheral manager for managing all connections, using a single manager for simplicity. - private var peripheral: CBPeripheralManager! + private var peripheral: CBPeripheralManager? /// Beacon service and characteristics being broadcasted by the transmitter. private var signalCharacteristic: CBMutableCharacteristic? private var payloadCharacteristic: CBMutableCharacteristic? @@ -91,6 +91,9 @@ class ConcreteBLETransmitter : NSObject, BLETransmitter, CBPeripheralManagerDele CBPeripheralManagerOptionShowPowerAlertKey : true ]) } + guard let peripheral = peripheral else { + return + } guard peripheral.state == .poweredOn else { logger.fault("start denied, not powered on") @@ -102,8 +105,8 @@ class ConcreteBLETransmitter : NSObject, BLETransmitter, CBPeripheralManagerDele startAdvertising(withNewCharacteristics: false) } else { queue.async { - self.peripheral.stopAdvertising() - self.peripheral.startAdvertising([CBAdvertisementDataServiceUUIDsKey : [BLESensorConfiguration.serviceUUID]]) + peripheral.stopAdvertising() + peripheral.startAdvertising([CBAdvertisementDataServiceUUIDsKey : [BLESensorConfiguration.serviceUUID]]) } } logger.debug("start successful, for existing characteristics") @@ -123,7 +126,7 @@ class ConcreteBLETransmitter : NSObject, BLETransmitter, CBPeripheralManagerDele guard peripheral != nil else { return } - guard peripheral.isAdvertising else { + guard peripheral?.isAdvertising ?? false else { logger.fault("stop denied, already stopped (source=%s)") self.peripheral = nil return @@ -144,17 +147,17 @@ class ConcreteBLETransmitter : NSObject, BLETransmitter, CBPeripheralManagerDele legacyCovidPayloadCharacteristic?.value = nil service.characteristics = [signalCharacteristic!, payloadCharacteristic!, legacyCovidPayloadCharacteristic!] queue.async { - self.peripheral.stopAdvertising() - self.peripheral.removeAllServices() - self.peripheral.add(service) - self.peripheral.startAdvertising([CBAdvertisementDataServiceUUIDsKey : [BLESensorConfiguration.serviceUUID]]) + self.peripheral?.stopAdvertising() + self.peripheral?.removeAllServices() + self.peripheral?.add(service) + self.peripheral?.startAdvertising([CBAdvertisementDataServiceUUIDsKey : [BLESensorConfiguration.serviceUUID]]) } } private func stopAdvertising() { logger.debug("stopAdvertising()") queue.async { - self.peripheral.stopAdvertising() + self.peripheral?.stopAdvertising() self.peripheral = nil } notifyTimer?.cancel() @@ -168,17 +171,18 @@ class ConcreteBLETransmitter : NSObject, BLETransmitter, CBPeripheralManagerDele notifyTimer = DispatchSource.makeTimerSource(queue: notifyTimerQueue) notifyTimer?.schedule(deadline: DispatchTime.now() + BLESensorConfiguration.notificationDelay) notifyTimer?.setEventHandler { [weak self] in - guard let s = self, let logger = self?.logger, let signalCharacteristic = self?.signalCharacteristic else { + guard let s = self, let logger = self?.logger, let signalCharacteristic = self?.signalCharacteristic, + let peripheral = s.peripheral else { return } // Notify subscribers to keep them awake s.queue.async { logger.debug("notifySubscribers (source=\(source))") - s.peripheral.updateValue(s.emptyData, for: signalCharacteristic, onSubscribedCentrals: nil) + peripheral.updateValue(s.emptyData, for: signalCharacteristic, onSubscribedCentrals: nil) } // Restart advert if required let advertUpTime = Date().timeIntervalSince(s.advertisingStartedAt) - if s.peripheral.isAdvertising, advertUpTime > BLESensorConfiguration.advertRestartTimeInterval { + if peripheral.isAdvertising && advertUpTime > BLESensorConfiguration.advertRestartTimeInterval { logger.debug("advertRestart (upTime=\(advertUpTime))") s.startAdvertising(withNewCharacteristics: true) } diff --git a/CovidSafe/HomeView.xib b/CovidSafe/HomeView.xib index afb3745..b064453 100644 --- a/CovidSafe/HomeView.xib +++ b/CovidSafe/HomeView.xib @@ -105,7 +105,7 @@ - + @@ -171,13 +171,13 @@ - + - + - + @@ -517,10 +517,10 @@ - + - + @@ -594,10 +594,10 @@ - + - + @@ -654,7 +654,7 @@ - + @@ -787,7 +787,7 @@ - + @@ -920,7 +920,7 @@ - + @@ -1031,7 +1031,7 @@ - + @@ -1151,7 +1151,7 @@ - +