From 9ee3acaa0a8db47e4de4861a0526523a7cc1492c Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 17 Feb 2023 11:52:52 +0100 Subject: [PATCH 001/137] 14811: Determine if the CWA hibernation state shall be given. --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 4 +++ .../AppDelegate & Globals/Globals.swift | 26 +++++++++++++++++++ .../__tests__/GlobalsTests.swift | 21 +++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/GlobalsTests.swift diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index 20cf1222b6f..e5280942b45 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -1758,6 +1758,7 @@ DC7003092858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7003082858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift */; }; DC8795AC2923ED8D00F478D5 /* UIViewController+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */; }; DC8BC2BF2953266B003C8CB1 /* InternetConnectivityMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */; }; + DC9390A2299F931A00C2F8F4 /* GlobalsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A1299F931A00C2F8F4 /* GlobalsTests.swift */; }; DC95881428BCF9FE00F4D03E /* MaskStateTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */; }; DC95881628BE3D5500F4D03E /* MaskStateCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */; }; DC95881828BE5E2800F4D03E /* MaskStateCellModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881728BE5E2800F4D03E /* MaskStateCellModelTests.swift */; }; @@ -3657,6 +3658,7 @@ DC7003082858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogSubmissionProvidingMock.swift; sourceTree = ""; }; DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Helpers.swift"; sourceTree = ""; }; DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetConnectivityMonitor.swift; sourceTree = ""; }; + DC9390A1299F931A00C2F8F4 /* GlobalsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalsTests.swift; sourceTree = ""; }; DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateTableViewCell.swift; sourceTree = ""; }; DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModel.swift; sourceTree = ""; }; DC95881728BE5E2800F4D03E /* MaskStateCellModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModelTests.swift; sourceTree = ""; }; @@ -5633,6 +5635,7 @@ children = ( BA7F15A02629D3F200CA4783 /* RouteTests.swift */, 502AB79826E64E5B00536DD2 /* NotificationManagerTests.swift */, + DC9390A1299F931A00C2F8F4 /* GlobalsTests.swift */, ); path = __tests__; sourceTree = ""; @@ -12432,6 +12435,7 @@ A1BABD0924A57B88000ED515 /* TemporaryExposureKeyMock.swift in Sources */, BAF5E41E27B17720001DF172 /* Locator+TestResultTests.swift in Sources */, 940109F225DFB5EF0017355C /* DiaryDayNotesInfoViewModelTest.swift in Sources */, + DC9390A2299F931A00C2F8F4 /* GlobalsTests.swift in Sources */, BAA19D7326121ACC00CBBDDD /* EditCheckinDetailViewModelTests.swift in Sources */, A1E41949249548770016E52A /* HTTPClient+SubmitTests.swift in Sources */, A1E41941249410AF0016E52A /* SAPDownloadedPackage+Helpers.swift in Sources */, diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Globals.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Globals.swift index 1cbff329c37..8b93cbda240 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Globals.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Globals.swift @@ -19,6 +19,32 @@ var isScreenshotMode: Bool { #endif +/// Determines the CWA Hibernation State, beginning on 01.06.2023. +var isHibernationState: Bool { + #if RELEASE + + var hibernationStartDateComponents = DateComponents() + hibernationStartDateComponents.year = 2023 + hibernationStartDateComponents.month = 6 + hibernationStartDateComponents.day = 1 + hibernationStartDateComponents.hour = 0 + hibernationStartDateComponents.minute = 0 + hibernationStartDateComponents.second = 0 + hibernationStartDateComponents.timeZone = .utcTimeZone + + guard let hibernationStartDate = Calendar.current.date(from: hibernationStartDateComponents) else { + fatalError("The hibernation start date couldn't be created.") + } + + return Date() >= hibernationStartDate + + #else + + return true // to.do Dev Menu setting, see https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 + + #endif +} + /// Unconditionally logs, prints a given message and stops execution. /// /// This 'catches' fatal errors by logging them first as errors… and then failing gloriously. diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/GlobalsTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/GlobalsTests.swift new file mode 100644 index 00000000000..b47921818f8 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/GlobalsTests.swift @@ -0,0 +1,21 @@ +// +// 🦠 Corona-Warn-App +// + +import XCTest +@testable import ENA + +final class GlobalsTests: CWATestCase { + + func testIsHibernationState_DeveloperMenuSetting_true() throws { + // to.do Dev Setting true + // https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 + + XCTAssertTrue(isHibernationState) + } + + func testIsHibernationState_DeveloperMenuSetting_false() throws { + // to.do Dev Setting false + // https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 + } +} From edfd21865a275ef8e18d242756a9384eb4c84ba6 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 17 Feb 2023 15:03:58 +0100 Subject: [PATCH 002/137] 14812: Developer Menu new entry for CWA hibernation options. --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 16 ++ .../Developer Menu/DMViewController.swift | 2 + .../DMHibernationOptionsViewController.swift | 105 ++++++++++++++ .../DMHibernationOptionsViewModel.swift | 100 +++++++++++++ .../Developer Menu/Helper/DMMenuItem.swift | 3 + .../__tests__/Mocks/MockTestStore.swift | 1 + .../AccessibilityIdentifiers.swift | 3 + .../Source/Workers/Store/SecureStore.swift | 137 +++++++++--------- .../ENA/ENA/Source/Workers/Store/Store.swift | 2 + 9 files changed, 303 insertions(+), 66 deletions(-) create mode 100644 src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift create mode 100644 src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index e5280942b45..7ddf612feed 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -1759,6 +1759,8 @@ DC8795AC2923ED8D00F478D5 /* UIViewController+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */; }; DC8BC2BF2953266B003C8CB1 /* InternetConnectivityMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */; }; DC9390A2299F931A00C2F8F4 /* GlobalsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A1299F931A00C2F8F4 /* GlobalsTests.swift */; }; + DC9390A5299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A4299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift */; }; + DC9390A7299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A6299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift */; }; DC95881428BCF9FE00F4D03E /* MaskStateTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */; }; DC95881628BE3D5500F4D03E /* MaskStateCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */; }; DC95881828BE5E2800F4D03E /* MaskStateCellModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881728BE5E2800F4D03E /* MaskStateCellModelTests.swift */; }; @@ -3659,6 +3661,8 @@ DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Helpers.swift"; sourceTree = ""; }; DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetConnectivityMonitor.swift; sourceTree = ""; }; DC9390A1299F931A00C2F8F4 /* GlobalsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalsTests.swift; sourceTree = ""; }; + DC9390A4299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMHibernationOptionsViewController.swift; sourceTree = ""; }; + DC9390A6299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMHibernationOptionsViewModel.swift; sourceTree = ""; }; DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateTableViewCell.swift; sourceTree = ""; }; DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModel.swift; sourceTree = ""; }; DC95881728BE5E2800F4D03E /* MaskStateCellModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModelTests.swift; sourceTree = ""; }; @@ -8861,6 +8865,7 @@ B16457BC24DC3E0E002879EB /* Features */ = { isa = PBXGroup; children = ( + DC9390A3299FAB3900C2F8F4 /* DMHibernation */, 8F8B4A312934CCC7007ED94E /* DMSRSPrechecks */, 018105D428115BF500C40268 /* DMRevocationList */, 50DED23527CE31E70035267C /* DMHealthCertificateMigration */, @@ -10594,6 +10599,15 @@ name = Mocks; sourceTree = ""; }; + DC9390A3299FAB3900C2F8F4 /* DMHibernation */ = { + isa = PBXGroup; + children = ( + DC9390A4299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift */, + DC9390A6299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift */, + ); + path = DMHibernation; + sourceTree = ""; + }; DC95881228BCF6C100F4D03E /* MaskState */ = { isa = PBXGroup; children = ( @@ -11431,6 +11445,7 @@ 01DE60752744EF3F00E12FA4 /* TicketValidationInitializationData.swift in Sources */, 013C413D255463A400826C9F /* DMDebugRiskCalculationViewController.swift in Sources */, 01BB00D0274FDAD70065D1D1 /* TicketValidationConditions.swift in Sources */, + DC9390A7299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift in Sources */, BAB6C7EF25C4626100E042FB /* TimestampedToken.swift in Sources */, 2FC951FE24DC23B9008D39F4 /* DMConfigurationCell.swift in Sources */, 3529BC1925D6BA800097E492 /* CachingHTTPClientMock.swift in Sources */, @@ -12267,6 +12282,7 @@ EBCD2412250790F400E5574C /* ExposureSubmissionSymptomsViewController.swift in Sources */, AB7420B7251B69E2006666AC /* DeltaOnboardingCoordinator.swift in Sources */, ABE961E225F29A5000D0F699 /* EventStoreSchemaV1.swift in Sources */, + DC9390A5299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift in Sources */, ABE9616725F1208300D0F699 /* TraceLocation.swift in Sources */, 01A4DCFE25926A66007D5794 /* HomeImageItemViewModel.swift in Sources */, 0138F65525F1174200A9B075 /* TraceLocationsOverviewViewModel.swift in Sources */, diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift b/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift index 57ef68a0a94..88da82c6d88 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift @@ -183,6 +183,8 @@ final class DMViewController: UITableViewController, RequiresAppDependencies { vc = DMCrashAppViewController() case .srs: vc = DMSRSOptionsViewController(store: store) + case .hibernation2023: + vc = DMHibernationOptionsViewController(store: store) } if let vc = vc { diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift new file mode 100644 index 00000000000..85087d3c633 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift @@ -0,0 +1,105 @@ +// +// 🦠 Corona-Warn-App +// +#if !RELEASE + +import UIKit + +class DMHibernationOptionsViewController: UITableViewController { + + // MARK: - Init + + init(store: Store) { + viewModel = DMHibernationOptionsViewModel(store: store) + + if #available(iOS 13.0, *) { + super.init(style: .insetGrouped) + } else { + super.init(style: .grouped) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Overrides + + override func viewDidLoad() { + super.viewDidLoad() + + setupNavigationBar() + setupTableView() + } + + // MARK: - Table view data source + + override func numberOfSections(in tableView: UITableView) -> Int { + viewModel.numberOfSections + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + viewModel.numberOfRows(in: section) + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cellViewModel = viewModel.cellViewModel(for: indexPath) + + if let cellViewModel = cellViewModel as? DMDatePickerCellViewModel { + return configureHibernationComparingDatePickerCell(cellViewModel: cellViewModel, indexPath: indexPath) + + } else if let cellViewModel = cellViewModel as? DMButtonCellViewModel { + return configureHibernationComparingDateResetCell(cellViewModel: cellViewModel, indexPath: indexPath) + + } else { + return UITableViewCell() + } + } + + override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { + viewModel.titleForFooter(in: section) + } + + // MARK: - Private + + private let viewModel: DMHibernationOptionsViewModel + + private func setupNavigationBar() { + title = "Hibernation Options" + } + + private func setupTableView() { + tableView.estimatedRowHeight = 45 + tableView.rowHeight = UITableView.automaticDimension + + tableView.register(DMDatePickerTableViewCell.self, forCellReuseIdentifier: DMDatePickerTableViewCell.reuseIdentifier) + tableView.register(DMButtonTableViewCell.self, forCellReuseIdentifier: DMButtonTableViewCell.reuseIdentifier) + } + + private func configureHibernationComparingDatePickerCell( + cellViewModel: DMDatePickerCellViewModel, + indexPath: IndexPath + ) -> DMDatePickerTableViewCell { + let cell = tableView.dequeueReusableCell(cellType: DMDatePickerTableViewCell.self, for: indexPath) + cell.configure(cellViewModel: cellViewModel) + + cell.didSelectDate = { [weak self] hibernationComparingDate in + self?.viewModel.store(hibernationComparingDate: hibernationComparingDate) + } + + return cell + } + + private func configureHibernationComparingDateResetCell( + cellViewModel: DMButtonCellViewModel, + indexPath: IndexPath + ) -> DMButtonTableViewCell { + let cell = tableView.dequeueReusableCell(cellType: DMButtonTableViewCell.self, for: indexPath) + + cell.configure(cellViewModel: cellViewModel) + + return cell + } +} + +#endif diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift new file mode 100644 index 00000000000..1adb0df32c8 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -0,0 +1,100 @@ +// +// 🦠 Corona-Warn-App +// + +import Foundation + +class DMHibernationOptionsViewModel { + + // MARK: - Init + + init(store: Store) { + self.store = store + } + + // MARK: - Internal + + var numberOfSections: Int { Sections.allCases.count } + + func numberOfRows(in section: Int) -> Int { 1 } + + func titleForFooter(in section: Int) -> String { + guard let section = Sections(rawValue: section) else { + fatalError("Invalid tableView section") + } + + switch section { + case .hibernationComparingDate: + var title = "App will be shutdown after set a new date value in the date picker.\n\n" + + if let date = store.hibernationComparingDate { + title.append("Currently the hibernation threshold compares against the set date \(dateFormatter.string(from: date))") + } else { + title.append("Currently there was no fake date set, so threshold date compares to today (\(dateFormatter.string(from: Date())))") + } + + return title + case .reset: + return "App will be shutdown after reset." + } + } + + func cellViewModel(for indexPath: IndexPath) -> Any { + guard let section = Sections(rawValue: indexPath.section) else { + fatalError("Invalid tableView section") + } + + switch section { + case .hibernationComparingDate: + return DMDatePickerCellViewModel( + title: "Hibernation Comparing Date", + accessibilityIdentifier: AccessibilityIdentifiers.DeveloperMenu.Hibernation.datePicker, + datePickerMode: .date, + date: store.hibernationComparingDate ?? Date() + ) + case .reset: + return DMButtonCellViewModel( + text: "Reset Comparing Date", + textColor: .white, + backgroundColor: .enaColor(for: .buttonDestructive)) { + self.store(hibernationComparingDate: nil) + } + } + } + + func store(hibernationComparingDate: Date?) { + if let hibernationComparingDate = hibernationComparingDate { + Log.debug("[Debug-Menu] Set hibernation comparing date to \(dateFormatter.string(from: hibernationComparingDate)).") + } else { + Log.debug("[Debug-Menu] Reset hibernation comparing date.") + } + store.hibernationComparingDate = hibernationComparingDate + + exitApp() + } + + // MARK: - Private + + private let store: Store + + private let dateFormatter: DateFormatter = { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd" + return dateFormatter + }() + + private func exitApp() { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + exit(0) + } + } +} + +extension DMHibernationOptionsViewModel { + enum Sections :Int, CaseIterable { + /// The date, that will be used to compare it against the hibernation start date (01.06.2023) + case hibernationComparingDate + /// Reset the stored fake date, the hibernation threshold compares to + case reset + } +} diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Helper/DMMenuItem.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Helper/DMMenuItem.swift index 5806acf398f..69348871252 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Helper/DMMenuItem.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Helper/DMMenuItem.swift @@ -46,6 +46,7 @@ enum DMMenuItem: Int, CaseIterable { case boosterRules case crashApp case srs + case hibernation2023 } extension DMMenuItem { @@ -101,6 +102,7 @@ extension DMMenuItem { case .boosterRules: return "Download Booster rules" case .crashApp: return "Crash App" case .srs: return "SRS Options" + case .hibernation2023: return "CWA Hibernation 2023" } } var subtitle: String { @@ -144,6 +146,7 @@ extension DMMenuItem { case .boosterRules: return "Download Booster rules and trigger the notification" case .crashApp: return "Crash the App to test crash reporting." case .srs: return "Configure SRS Behavior" + case .hibernation2023: return "Change date and time to trigger hibernation." } } } diff --git a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift index 252417dde92..408de3ad70e 100644 --- a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift +++ b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift @@ -63,6 +63,7 @@ final class MockTestStore: Store, PPAnalyticsData { var forceAPITokenAuthorization = false var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? var isSrsPrechecksEnabled = false + var hibernationComparingDate: Date? #endif // MARK: - AppConfigCaching diff --git a/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift b/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift index 9df58db0fc5..39cb241482f 100644 --- a/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift +++ b/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift @@ -10,6 +10,9 @@ enum AccessibilityIdentifiers { enum InstallationDay { static let datePicker = "AppStrings.DeveloperMenu.InstallationDay.datePicker" } + enum Hibernation { + static let datePicker = "AppStrings.DeveloperMenu.Hibernation.datePicker" + } } enum ExposureNotificationSetting { diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift index 0ce9473ffa2..1ba4181a472 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift @@ -10,14 +10,14 @@ import OpenCombine /// It uses an SQLite Database that still needs to be encrypted // swiftlint:disable file_length final class SecureStore: SecureKeyValueStoring, Store { - + // MARK: - Init - + init(at directoryURL: URL, key: String) throws { self.directoryURL = directoryURL self.kvStore = try SQLiteKeyValueStore(with: directoryURL, key: key) } - + convenience init( at directoryURL: URL, key: String, @@ -25,9 +25,9 @@ final class SecureStore: SecureKeyValueStoring, Store { ) throws { try self.init(at: directoryURL, key: key) } - + // MARK: - Protocol Store - + /// Removes most key/value pairs. /// /// Keys whose values are not removed: @@ -43,7 +43,7 @@ final class SecureStore: SecureKeyValueStoring, Store { Log.error("kv store error", log: .localData, error: error) } } - + /// Database reset & re-initialization with a given key /// - Parameter key: the key for the new database; if no key is given, no new database will be created /// @@ -57,133 +57,133 @@ final class SecureStore: SecureKeyValueStoring, Store { Log.error("kv store error", log: .localData, error: error) } } - + var exposureActivationConsentAcceptTimestamp: Int64? { get { kvStore["exposureActivationConsentAcceptTimestamp"] as Int64? ?? 0 } set { kvStore["exposureActivationConsentAcceptTimestamp"] = newValue } } - + var exposureActivationConsentAccept: Bool { get { kvStore["exposureActivationConsentAccept"] as Bool? ?? false } set { kvStore["exposureActivationConsentAccept"] = newValue } } - + var isOnboarded: Bool { get { kvStore["isOnboarded"] as Bool? ?? false } set { kvStore["isOnboarded"] = newValue } } - + var cclVersion: String? { get { kvStore["cclVersion"] as String? } set { kvStore["cclVersion"] = newValue } } - + var finishedDeltaOnboardings: [String: [String]] { get { kvStore["finishedDeltaOnboardings"] as [String: [String]]? ?? [String: [String]]() } set { kvStore["finishedDeltaOnboardings"] = newValue } } - + var onboardingVersion: String { get { kvStore["onboardingVersion"] as String? ?? "1.4" } set { kvStore["onboardingVersion"] = newValue } } - + var dateOfAcceptedPrivacyNotice: Date? { get { kvStore["dateOfAcceptedPrivacyNotice"] as Date? ?? nil } set { kvStore["dateOfAcceptedPrivacyNotice"] = newValue } } - + var hasSeenBackgroundFetchAlert: Bool { get { kvStore["hasSeenBackgroundFetchAlert"] as Bool? ?? false } set { kvStore["hasSeenBackgroundFetchAlert"] = newValue } } - + var developerSubmissionBaseURLOverride: String? { get { kvStore["developerSubmissionBaseURLOverride"] as String? ?? nil } set { kvStore["developerSubmissionBaseURLOverride"] = newValue } } - + var developerDistributionBaseURLOverride: String? { get { kvStore["developerDistributionBaseURLOverride"] as String? ?? nil } set { kvStore["developerDistributionBaseURLOverride"] = newValue } } - + var developerVerificationBaseURLOverride: String? { get { kvStore["developerVerificationBaseURLOverride"] as String? ?? nil } set { kvStore["developerVerificationBaseURLOverride"] = newValue } } - + var appInstallationDate: Date? { get { kvStore["appInstallationDate"] as Date? } set { kvStore["appInstallationDate"] = newValue } } - + var referenceDateForRateLimitLogger: Date? { get { kvStore["referenceDateForRateLimitLogger"] as Date? } set { kvStore["referenceDateForRateLimitLogger"] = newValue } } - + var enfRiskCalculationResult: ENFRiskCalculationResult? { // Old named key matches not to property name to avoid migration. get { kvStore["riskCalculationResult"] as ENFRiskCalculationResult? ?? nil } set { kvStore["riskCalculationResult"] = newValue } } - + var checkinRiskCalculationResult: CheckinRiskCalculationResult? { get { kvStore["checkinRiskCalculationResult"] as CheckinRiskCalculationResult? ?? nil } set { kvStore["checkinRiskCalculationResult"] = newValue } } - + var mostRecentDateWithRiskLevel: Date? { get { kvStore["mostRecentDateWithRiskLevel"] as Date? } set { kvStore["mostRecentDateWithRiskLevel"] = newValue } } - + var showAnotherHighExposureAlert: Bool { get { kvStore["showAnotherHighExposureAlert"] as Bool? ?? false } set { kvStore["showAnotherHighExposureAlert"] = newValue } } - + var shouldShowRiskStatusLoweredAlert: Bool { get { kvStore["shouldShowRiskStatusLoweredAlert"] as Bool? ?? false } set { kvStore["shouldShowRiskStatusLoweredAlert"] = newValue } } - + var userNeedsToBeInformedAboutHowRiskDetectionWorks: Bool { get { kvStore["userNeedsToBeInformedAboutHowRiskDetectionWorks"] as Bool? ?? true } set { kvStore["userNeedsToBeInformedAboutHowRiskDetectionWorks"] = newValue } } - + var shouldShowQRScannerTooltip: Bool { get { kvStore["shouldShowQRScannerTooltip"] as Bool? ?? true } set { kvStore["shouldShowQRScannerTooltip"] = newValue } } - + var lastBackgroundFakeRequest: Date { get { kvStore["lastBackgroundFakeRequest"] as Date? ?? Date() } set { kvStore["lastBackgroundFakeRequest"] = newValue } } - + var firstPlaybookExecution: Date? { get { kvStore["firstPlaybookExecution"] as Date? } set { kvStore["firstPlaybookExecution"] = newValue } } - + var wasRecentDayKeyDownloadSuccessful: Bool { get { kvStore["wasRecentDayKeyDownloadSuccessful"] as Bool? ?? false } set { kvStore["wasRecentDayKeyDownloadSuccessful"] = newValue } } - + var wasRecentHourKeyDownloadSuccessful: Bool { get { kvStore["wasRecentHourKeyDownloadSuccessful"] as Bool? ?? false } set { kvStore["wasRecentHourKeyDownloadSuccessful"] = newValue } - } - + } + var lastKeyPackageDownloadDate: Date { get { kvStore["lastKeyPackageDownloadDate"] as Date? ?? .distantPast } set { kvStore["lastKeyPackageDownloadDate"] = newValue } } - + var submissionKeys: [SAP_External_Exposurenotification_TemporaryExposureKey]? { get { (kvStore["submissionKeys"] as [Data]?)?.compactMap { @@ -199,7 +199,7 @@ final class SecureStore: SecureKeyValueStoring, Store { get { kvStore["submissionCheckins"] as [Checkin]? ?? [] } set { kvStore["submissionCheckins"] = newValue } } - + var submissionCountries: [Country] { get { let countries = kvStore["submissionCountries"] as [Country]? ?? [.defaultCountry()] @@ -207,12 +207,12 @@ final class SecureStore: SecureKeyValueStoring, Store { } set { kvStore["submissionCountries"] = newValue } } - + var submissionSymptomsOnset: SymptomsOnset { get { kvStore["submissionSymptomsOnset"] as SymptomsOnset? ?? .noInformation } set { kvStore["submissionSymptomsOnset"] = newValue } } - + var journalWithExposureHistoryInfoScreenShown: Bool { get { kvStore["journalWithExposureHistoryInfoScreenShown"] as Bool? ?? false } set { kvStore["journalWithExposureHistoryInfoScreenShown"] = newValue } @@ -227,11 +227,11 @@ final class SecureStore: SecureKeyValueStoring, Store { get { kvStore["lastBoosterNotificationsExecutionDate"] as Date? } set { kvStore["lastBoosterNotificationsExecutionDate"] = newValue } } - - // MARK: - Protocol AntigenTestProfileStoring - + + // MARK: - Protocol AntigenTestProfileStoring + private(set) lazy var antigenTestProfilesSubject = CurrentValueSubject<[AntigenTestProfile], Never>(antigenTestProfiles) - + var antigenTestProfiles: [AntigenTestProfile] { get { var antigenTestProfiles = kvStore["antigenTestProfiles"] as [AntigenTestProfile]? ?? [] @@ -257,29 +257,29 @@ final class SecureStore: SecureKeyValueStoring, Store { get { kvStore["antigenTestProfileInfoScreenShown"] as Bool? ?? false } set { kvStore["antigenTestProfileInfoScreenShown"] = newValue } } - - // MARK: - Protocol HealthCertificateStoring - + + // MARK: - Protocol HealthCertificateStoring + var healthCertificateInfoScreenShown: Bool { get { kvStore["healthCertificateInfoScreenShown25"] as Bool? ?? false } set { kvStore["healthCertificateInfoScreenShown25"] = newValue } } - - var healthCertifiedPersons: [HealthCertifiedPerson] { - get { kvStore["healthCertifiedPersons"] as [HealthCertifiedPerson]? ?? [] } - set { kvStore["healthCertifiedPersons"] = newValue } - } - + + var healthCertifiedPersons: [HealthCertifiedPerson] { + get { kvStore["healthCertifiedPersons"] as [HealthCertifiedPerson]? ?? [] } + set { kvStore["healthCertifiedPersons"] = newValue } + } + var healthCertifiedPersonsVersion: Int? { get { kvStore["healthCertifiedPersonsVersion"] as Int? ?? nil } set { kvStore["healthCertifiedPersonsVersion"] = newValue } } - + var testCertificateRequests: [TestCertificateRequest] { get { kvStore["testCertificateRequests"] as [TestCertificateRequest]? ?? [] } set { kvStore["testCertificateRequests"] = newValue } } - + var lastSelectedValidationCountry: Country { get { let country = kvStore["lastSelectedValidationCountry"] as Country? ?? Country.defaultCountry() @@ -287,7 +287,7 @@ final class SecureStore: SecureKeyValueStoring, Store { } set { kvStore["lastSelectedValidationCountry"] = newValue } } - + var lastSelectedValidationDate: Date { get { kvStore["lastSelectedValidationDate"] as Date? ?? Date() } set { kvStore["lastSelectedValidationDate"] = newValue } @@ -302,12 +302,12 @@ final class SecureStore: SecureKeyValueStoring, Store { get { kvStore["dccAdmissionCheckScenarios"] as DCCAdmissionCheckScenarios? ?? nil } set { kvStore["dccAdmissionCheckScenarios"] = newValue } } - + var shouldShowRegroupingAlert: Bool { get { kvStore["shouldShowRegroupingAlert"] as Bool? ?? false } set { kvStore["shouldShowRegroupingAlert"] = newValue } } - + var expiringSoonAndExpiredNotificationsRemoved: Bool { get { kvStore["expiringSoonAndExpiredNotificationsRemoved"] as Bool? ?? false } set { kvStore["expiringSoonAndExpiredNotificationsRemoved"] = newValue } @@ -322,25 +322,25 @@ final class SecureStore: SecureKeyValueStoring, Store { get { kvStore["shouldShowExportCertificatesTooltip"] as Bool? ?? true } set { kvStore["shouldShowExportCertificatesTooltip"] = newValue } } - + // MARK: - Protocol RevokedCertificatesStoring - + var revokedCertificates: [String] { get { kvStore["revokedCertificates"] as [String]? ?? [] } set { kvStore["revokedCertificates"] = newValue } } - + // MARK: - Protocol VaccinationCaching - + var vaccinationCertificateValueDataSets: VaccinationValueDataSets? { get { kvStore["vaccinationCertificateValueDataSets"] as VaccinationValueDataSets? ?? nil } set { kvStore["vaccinationCertificateValueDataSets"] = newValue } } - + // MARK: - Protocol RecycleBinStoring - + private(set) lazy var recycleBinItemsSubject = CurrentValueSubject, Never>(recycleBinItems) - + var recycleBinItems: Set { get { kvStore["recycleBinItems"] as Set? ?? [] } set { @@ -348,26 +348,26 @@ final class SecureStore: SecureKeyValueStoring, Store { recycleBinItemsSubject.send(newValue) } } - + // MARK: - Non-Release Stuff - #if !RELEASE +#if !RELEASE // Settings from the debug menu. var fakeSQLiteError: Int32? { get { kvStore["fakeSQLiteError"] as Int32? } set { kvStore["fakeSQLiteError"] = newValue } } - + var mostRecentRiskCalculation: ENFRiskCalculation? { get { kvStore["mostRecentRiskCalculation"] as ENFRiskCalculation? } set { kvStore["mostRecentRiskCalculation"] = newValue } } - + var mostRecentRiskCalculationConfiguration: RiskCalculationConfiguration? { get { kvStore["mostRecentRiskCalculationConfiguration"] as RiskCalculationConfiguration? } set { kvStore["mostRecentRiskCalculationConfiguration"] = newValue } } - + var forceAPITokenAuthorization: Bool { get { kvStore["forceAPITokenAuthorization"] as Bool? ?? false } set { kvStore["forceAPITokenAuthorization"] = newValue } @@ -377,6 +377,11 @@ final class SecureStore: SecureKeyValueStoring, Store { get { kvStore["recentTraceLocationCheckedInto"] as DMRecentTraceLocationCheckedInto? ?? nil } set { kvStore["recentTraceLocationCheckedInto"] = newValue } } + + var hibernationComparingDate: Date? { + get { kvStore["hibernationComparingDate"] as Date? ?? Date() } + set { kvStore["hibernationComparingDate"] = newValue } + } #endif // MARK: - Internal diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift index bfb9bdae28a..e2703f6154a 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift @@ -86,6 +86,8 @@ protocol StoreProtocol: AnyObject { var forceAPITokenAuthorization: Bool { get set } var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? { get set } + + var hibernationComparingDate: Date? { get set } #endif From 44a9bb4d7d397013089bfcba08a7ae8f29841cc3 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 17 Feb 2023 15:16:47 +0100 Subject: [PATCH 003/137] 14811: Find a better OOP approach. --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 12 +++-- .../CWAHibernationProvider.swift | 44 +++++++++++++++++++ .../AppDelegate & Globals/Globals.swift | 26 ----------- ...wift => CWAHibernationProviderTests.swift} | 9 +++- 4 files changed, 59 insertions(+), 32 deletions(-) create mode 100644 src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift rename src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/{GlobalsTests.swift => CWAHibernationProviderTests.swift} (70%) diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index e5280942b45..ca32df050b9 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -1758,7 +1758,8 @@ DC7003092858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7003082858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift */; }; DC8795AC2923ED8D00F478D5 /* UIViewController+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */; }; DC8BC2BF2953266B003C8CB1 /* InternetConnectivityMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */; }; - DC9390A2299F931A00C2F8F4 /* GlobalsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A1299F931A00C2F8F4 /* GlobalsTests.swift */; }; + DC9390A2299F931A00C2F8F4 /* CWAHibernationProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */; }; + DC9390A9299FC0F300C2F8F4 /* CWAHibernationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A8299FC0F300C2F8F4 /* CWAHibernationProvider.swift */; }; DC95881428BCF9FE00F4D03E /* MaskStateTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */; }; DC95881628BE3D5500F4D03E /* MaskStateCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */; }; DC95881828BE5E2800F4D03E /* MaskStateCellModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881728BE5E2800F4D03E /* MaskStateCellModelTests.swift */; }; @@ -3658,7 +3659,8 @@ DC7003082858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogSubmissionProvidingMock.swift; sourceTree = ""; }; DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Helpers.swift"; sourceTree = ""; }; DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetConnectivityMonitor.swift; sourceTree = ""; }; - DC9390A1299F931A00C2F8F4 /* GlobalsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalsTests.swift; sourceTree = ""; }; + DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CWAHibernationProviderTests.swift; sourceTree = ""; }; + DC9390A8299FC0F300C2F8F4 /* CWAHibernationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CWAHibernationProvider.swift; sourceTree = ""; }; DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateTableViewCell.swift; sourceTree = ""; }; DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModel.swift; sourceTree = ""; }; DC95881728BE5E2800F4D03E /* MaskStateCellModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModelTests.swift; sourceTree = ""; }; @@ -5635,7 +5637,7 @@ children = ( BA7F15A02629D3F200CA4783 /* RouteTests.swift */, 502AB79826E64E5B00536DD2 /* NotificationManagerTests.swift */, - DC9390A1299F931A00C2F8F4 /* GlobalsTests.swift */, + DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */, ); path = __tests__; sourceTree = ""; @@ -5703,6 +5705,7 @@ 353412CB2525EE4A0086D15C /* Globals.swift */, 35B2FAB925B9D3F3009ABC8E /* ENATaskExecutionDelegate.swift */, 3518DD6425BA2D060090A26B /* NotificationManager.swift */, + DC9390A8299FC0F300C2F8F4 /* CWAHibernationProvider.swift */, ); path = "AppDelegate & Globals"; sourceTree = ""; @@ -11285,6 +11288,7 @@ 2FA9E39524D2F2B00030561C /* ExposureSubmission+DeviceRegistrationKey.swift in Sources */, BAE11F5528217E1E00CA2790 /* FetchDayResource.swift in Sources */, BAE11F5328217D5500CA2790 /* Locator+DiagnosisKeys.swift in Sources */, + DC9390A9299FC0F300C2F8F4 /* CWAHibernationProvider.swift in Sources */, EB08F17E2541CE3300D11FA9 /* app_version_config.pb.swift in Sources */, 0138F54B25ECD44300A9B075 /* semantic_version.pb.swift in Sources */, A3FF84EC247BFAF00053E947 /* ENAHasher.swift in Sources */, @@ -12435,7 +12439,7 @@ A1BABD0924A57B88000ED515 /* TemporaryExposureKeyMock.swift in Sources */, BAF5E41E27B17720001DF172 /* Locator+TestResultTests.swift in Sources */, 940109F225DFB5EF0017355C /* DiaryDayNotesInfoViewModelTest.swift in Sources */, - DC9390A2299F931A00C2F8F4 /* GlobalsTests.swift in Sources */, + DC9390A2299F931A00C2F8F4 /* CWAHibernationProviderTests.swift in Sources */, BAA19D7326121ACC00CBBDDD /* EditCheckinDetailViewModelTests.swift in Sources */, A1E41949249548770016E52A /* HTTPClient+SubmitTests.swift in Sources */, A1E41941249410AF0016E52A /* SAPDownloadedPackage+Helpers.swift in Sources */, diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift new file mode 100644 index 00000000000..9e5e39bdfb4 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -0,0 +1,44 @@ +// +// 🦠 Corona-Warn-App +// + +import Foundation + +class CWAHibernationProvider: RequiresAppDependencies { + + // MARK: - Init + + /// Use shared instance instead + private init() {} + + // MARK: Internal + + static let shared = CWAHibernationProvider() + + /// Determines if the CWA is in hibernation state. + var isHibernationState: Bool { + #if RELEASE + return Date() >= hibernationStartDate + #else + return true // to.do Dev Menu setting, see https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 + #endif + } + + /// CWA hibernation 2023 threshold date. + private let hibernationStartDate: Date = { + var hibernationStartDateComponents = DateComponents() + hibernationStartDateComponents.year = 2023 + hibernationStartDateComponents.month = 6 + hibernationStartDateComponents.day = 1 + hibernationStartDateComponents.hour = 0 + hibernationStartDateComponents.minute = 0 + hibernationStartDateComponents.second = 0 + hibernationStartDateComponents.timeZone = .utcTimeZone + + guard let hibernationStartDate = Calendar.current.date(from: hibernationStartDateComponents) else { + fatalError("The hibernation start date couldn't be created.") + } + + return hibernationStartDate + }() +} diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Globals.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Globals.swift index 8b93cbda240..1cbff329c37 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Globals.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Globals.swift @@ -19,32 +19,6 @@ var isScreenshotMode: Bool { #endif -/// Determines the CWA Hibernation State, beginning on 01.06.2023. -var isHibernationState: Bool { - #if RELEASE - - var hibernationStartDateComponents = DateComponents() - hibernationStartDateComponents.year = 2023 - hibernationStartDateComponents.month = 6 - hibernationStartDateComponents.day = 1 - hibernationStartDateComponents.hour = 0 - hibernationStartDateComponents.minute = 0 - hibernationStartDateComponents.second = 0 - hibernationStartDateComponents.timeZone = .utcTimeZone - - guard let hibernationStartDate = Calendar.current.date(from: hibernationStartDateComponents) else { - fatalError("The hibernation start date couldn't be created.") - } - - return Date() >= hibernationStartDate - - #else - - return true // to.do Dev Menu setting, see https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 - - #endif -} - /// Unconditionally logs, prints a given message and stops execution. /// /// This 'catches' fatal errors by logging them first as errors… and then failing gloriously. diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/GlobalsTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift similarity index 70% rename from src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/GlobalsTests.swift rename to src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index b47921818f8..1e7f7bd8ab3 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/GlobalsTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -5,13 +5,18 @@ import XCTest @testable import ENA -final class GlobalsTests: CWATestCase { +final class CWAHibernationProviderTests: CWATestCase { func testIsHibernationState_DeveloperMenuSetting_true() throws { + // GIVEN + let sut = CWAHibernationProvider.shared + + // WHEN // to.do Dev Setting true // https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 - XCTAssertTrue(isHibernationState) + // THEN + XCTAssertTrue(sut.isHibernationState) } func testIsHibernationState_DeveloperMenuSetting_false() throws { From 53fee4809c5f564da3ebe640bc2c21eb7fe5624b Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 17 Feb 2023 15:17:38 +0100 Subject: [PATCH 004/137] Update CWAHibernationProvider.swift --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 9e5e39bdfb4..da891da8b3a 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -11,7 +11,7 @@ class CWAHibernationProvider: RequiresAppDependencies { /// Use shared instance instead private init() {} - // MARK: Internal + // MARK: - Internal static let shared = CWAHibernationProvider() From 53102e3834b901ecf51eb101099a75599210e0d8 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 17 Feb 2023 16:03:33 +0100 Subject: [PATCH 005/137] 14812: Unit Tests --- .../CWAHibernationProvider.swift | 22 +++++++++- .../CWAHibernationProviderTests.swift | 43 +++++++++++++++---- .../DMHibernationOptionsViewModel.swift | 22 +++------- .../__tests__/Mocks/MockTestStore.swift | 2 +- .../Source/Workers/Store/SecureStore.swift | 2 +- .../ENA/ENA/Source/Workers/Store/Store.swift | 2 +- 6 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 9e5e39bdfb4..507e1c24803 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -11,6 +11,13 @@ class CWAHibernationProvider: RequiresAppDependencies { /// Use shared instance instead private init() {} + #if !RELEASE + /// For UI/Unit purposes only + init(customStore: Store) { + self.customStore = customStore + } + #endif + // MARK: Internal static let shared = CWAHibernationProvider() @@ -20,7 +27,7 @@ class CWAHibernationProvider: RequiresAppDependencies { #if RELEASE return Date() >= hibernationStartDate #else - return true // to.do Dev Menu setting, see https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 + return secureStore.hibernationComparingDate >= hibernationStartDate #endif } @@ -41,4 +48,17 @@ class CWAHibernationProvider: RequiresAppDependencies { return hibernationStartDate }() + + private var secureStore: Store { + #if RELEASE + return store + #else + return customStore ?? store + #endif + } + + #if !RELEASE + /// For UI/Unit Test purposes only + private var customStore: Store? = nil + #endif } diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index 1e7f7bd8ab3..bf3d8f2c020 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -6,21 +6,46 @@ import XCTest @testable import ENA final class CWAHibernationProviderTests: CWATestCase { + + func testIsHibernationState_Store_HibernationComparingDate_before_false() throws { + // GIVEN + let mockTestStore = MockTestStore() + let sut = CWAHibernationProvider(customStore: mockTestStore) + + // WHEN + var beforeHibernationStartDateComponents = DateComponents() + beforeHibernationStartDateComponents.year = 2023 + beforeHibernationStartDateComponents.month = 5 + beforeHibernationStartDateComponents.day = 31 + beforeHibernationStartDateComponents.hour = 23 + beforeHibernationStartDateComponents.minute = 59 + beforeHibernationStartDateComponents.second = 59 + beforeHibernationStartDateComponents.timeZone = .utcTimeZone + + mockTestStore.hibernationComparingDate = Calendar.current.date(from: beforeHibernationStartDateComponents)! + + // THEN + XCTAssertFalse(sut.isHibernationState) + } - func testIsHibernationState_DeveloperMenuSetting_true() throws { + func testIsHibernationState_Store_HibernationComparingDate_after_true() throws { // GIVEN - let sut = CWAHibernationProvider.shared + let mockTestStore = MockTestStore() + let sut = CWAHibernationProvider(customStore: mockTestStore) // WHEN - // to.do Dev Setting true - // https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 + var afterHibernationStartDateComponents = DateComponents() + afterHibernationStartDateComponents.year = 2023 + afterHibernationStartDateComponents.month = 6 + afterHibernationStartDateComponents.day = 1 + afterHibernationStartDateComponents.hour = 0 + afterHibernationStartDateComponents.minute = 0 + afterHibernationStartDateComponents.second = 0 + afterHibernationStartDateComponents.timeZone = .utcTimeZone + + mockTestStore.hibernationComparingDate = Calendar.current.date(from: afterHibernationStartDateComponents)! // THEN XCTAssertTrue(sut.isHibernationState) } - - func testIsHibernationState_DeveloperMenuSetting_false() throws { - // to.do Dev Setting false - // https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-14812 - } } diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index 1adb0df32c8..da5c7e115c8 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -25,17 +25,11 @@ class DMHibernationOptionsViewModel { switch section { case .hibernationComparingDate: - var title = "App will be shutdown after set a new date value in the date picker.\n\n" - - if let date = store.hibernationComparingDate { - title.append("Currently the hibernation threshold compares against the set date \(dateFormatter.string(from: date))") - } else { - title.append("Currently there was no fake date set, so threshold date compares to today (\(dateFormatter.string(from: Date())))") - } + var title = "App will be shutdown after set a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date \(dateFormatter.string(from: store.hibernationComparingDate))" return title case .reset: - return "App will be shutdown after reset." + return "App will be shutdown after reset to today date." } } @@ -50,24 +44,20 @@ class DMHibernationOptionsViewModel { title: "Hibernation Comparing Date", accessibilityIdentifier: AccessibilityIdentifiers.DeveloperMenu.Hibernation.datePicker, datePickerMode: .date, - date: store.hibernationComparingDate ?? Date() + date: store.hibernationComparingDate ) case .reset: return DMButtonCellViewModel( text: "Reset Comparing Date", textColor: .white, backgroundColor: .enaColor(for: .buttonDestructive)) { - self.store(hibernationComparingDate: nil) + self.store(hibernationComparingDate: Date()) } } } - func store(hibernationComparingDate: Date?) { - if let hibernationComparingDate = hibernationComparingDate { - Log.debug("[Debug-Menu] Set hibernation comparing date to \(dateFormatter.string(from: hibernationComparingDate)).") - } else { - Log.debug("[Debug-Menu] Reset hibernation comparing date.") - } + func store(hibernationComparingDate: Date) { + Log.debug("[Debug-Menu] Set hibernation comparing date to \(dateFormatter.string(from: hibernationComparingDate)).") store.hibernationComparingDate = hibernationComparingDate exitApp() diff --git a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift index 408de3ad70e..42dd26f6e2f 100644 --- a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift +++ b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift @@ -63,7 +63,7 @@ final class MockTestStore: Store, PPAnalyticsData { var forceAPITokenAuthorization = false var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? var isSrsPrechecksEnabled = false - var hibernationComparingDate: Date? + var hibernationComparingDate = Date() #endif // MARK: - AppConfigCaching diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift index 1ba4181a472..6a2b18d68c2 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift @@ -378,7 +378,7 @@ final class SecureStore: SecureKeyValueStoring, Store { set { kvStore["recentTraceLocationCheckedInto"] = newValue } } - var hibernationComparingDate: Date? { + var hibernationComparingDate: Date { get { kvStore["hibernationComparingDate"] as Date? ?? Date() } set { kvStore["hibernationComparingDate"] = newValue } } diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift index e2703f6154a..2396ff0bf0e 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift @@ -87,7 +87,7 @@ protocol StoreProtocol: AnyObject { var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? { get set } - var hibernationComparingDate: Date? { get set } + var hibernationComparingDate: Date { get set } #endif From 5a2a5a4f88491cea2c49d941491e03d68ec2b332 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 20 Feb 2023 17:16:46 +0100 Subject: [PATCH 006/137] changes to info view controller --- .../Onboarding/OnboardingInfoViewController.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Onboarding/OnboardingInfoViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Onboarding/OnboardingInfoViewController.swift index e4be1354939..019f58d0d4d 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Onboarding/OnboardingInfoViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Onboarding/OnboardingInfoViewController.swift @@ -102,8 +102,14 @@ final class OnboardingInfoViewController: UIViewController { nextButton.isUserInteractionEnabled = false runActionForPageType( completion: { [weak self] in - self?.gotoNextScreen() - self?.nextButton.isUserInteractionEnabled = true + guard let self = self else { return } + + if CWAHibernationProvider.shared.isHibernationState && self.pageType.isPrivacyPage() { + self.finishOnBoarding() + } + + self.gotoNextScreen() + self.nextButton.isUserInteractionEnabled = true } ) } From 5268fed4c4ce4547f58d04463e91ebc443f4e921 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 20 Feb 2023 17:17:34 +0100 Subject: [PATCH 007/137] adding a convenience function --- .../ENA/ENA/Source/Scenes/Onboarding/OnboardingPageType.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Onboarding/OnboardingPageType.swift b/src/xcode/ENA/ENA/Source/Scenes/Onboarding/OnboardingPageType.swift index 90dbf9568bb..271304eb4a4 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Onboarding/OnboardingPageType.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Onboarding/OnboardingPageType.swift @@ -17,4 +17,8 @@ enum OnboardingPageType: Int, CaseIterable { func isLast() -> Bool { (self == OnboardingPageType.allCases.last) } + + func isPrivacyPage() -> Bool { + (self == OnboardingPageType.privacyPage) + } } From ebf4d39af7543d8085ac9ce31e5c5665c8fa6411 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 21 Feb 2023 10:08:32 +0100 Subject: [PATCH 008/137] add new illustration --- .../Contents.json | 21 ++++++++++++++++++ .../EndOfLifeThankYouIllustration.pdf | Bin 0 -> 40032 bytes 2 files changed, 21 insertions(+) create mode 100644 src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/Contents.json create mode 100644 src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration.pdf diff --git a/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/Contents.json b/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/Contents.json new file mode 100644 index 00000000000..cff99bbf028 --- /dev/null +++ b/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "EndOfLifeThankYouIllustration.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration.pdf b/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f645d29cf742cfee90156f0dc33142fcad1cbf3f GIT binary patch literal 40032 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 Date: Tue, 21 Feb 2023 10:09:08 +0100 Subject: [PATCH 009/137] add cell --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 20 ++++ .../EndOfLifeThankYouCell.swift | 67 +++++++++++++ .../EndOfLifeThankYouCell.xib | 99 +++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift create mode 100644 src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index ca32df050b9..f58c3a18572 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -968,6 +968,9 @@ 8F3D71AA25A86AD300D52CCD /* HomeExposureLoggingCellModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F3D71A925A86AD300D52CCD /* HomeExposureLoggingCellModelTests.swift */; }; 8F43A3CB25D55A3E008FD630 /* ppa_data.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F43A3C925D55A3D008FD630 /* ppa_data.pb.swift */; }; 8F43A3CC25D55A3E008FD630 /* ppa_data_request_ios.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F43A3CA25D55A3E008FD630 /* ppa_data_request_ios.pb.swift */; }; + 8F43E69029A32A890047C21F /* EndOfLifeThankYouCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F43E68E29A32A890047C21F /* EndOfLifeThankYouCell.swift */; }; + 8F43E69129A32A890047C21F /* EndOfLifeThankYouCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8F43E68F29A32A890047C21F /* EndOfLifeThankYouCell.xib */; }; + 8F43E69329A332280047C21F /* EndOfLifeThankYouCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F43E69229A332280047C21F /* EndOfLifeThankYouCellViewModel.swift */; }; 8F47CB67293E35C5008D91E5 /* ContactDiaryStoreSchemaV6.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F47CB66293E35C5008D91E5 /* ContactDiaryStoreSchemaV6.swift */; }; 8F47CB69293E376A008D91E5 /* ContactDiaryMigration5To6.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F47CB68293E376A008D91E5 /* ContactDiaryMigration5To6.swift */; }; 8F47CB6B293E4170008D91E5 /* DiaryDaySubmission.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F47CB6A293E4170008D91E5 /* DiaryDaySubmission.swift */; }; @@ -2868,6 +2871,9 @@ 8F3D71A925A86AD300D52CCD /* HomeExposureLoggingCellModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeExposureLoggingCellModelTests.swift; sourceTree = ""; }; 8F43A3C925D55A3D008FD630 /* ppa_data.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ppa_data.pb.swift; sourceTree = ""; }; 8F43A3CA25D55A3E008FD630 /* ppa_data_request_ios.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ppa_data_request_ios.pb.swift; sourceTree = ""; }; + 8F43E68E29A32A890047C21F /* EndOfLifeThankYouCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndOfLifeThankYouCell.swift; sourceTree = ""; }; + 8F43E68F29A32A890047C21F /* EndOfLifeThankYouCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EndOfLifeThankYouCell.xib; sourceTree = ""; }; + 8F43E69229A332280047C21F /* EndOfLifeThankYouCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndOfLifeThankYouCellViewModel.swift; sourceTree = ""; }; 8F47CB66293E35C5008D91E5 /* ContactDiaryStoreSchemaV6.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDiaryStoreSchemaV6.swift; sourceTree = ""; }; 8F47CB68293E376A008D91E5 /* ContactDiaryMigration5To6.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDiaryMigration5To6.swift; sourceTree = ""; }; 8F47CB6A293E4170008D91E5 /* DiaryDaySubmission.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryDaySubmission.swift; sourceTree = ""; }; @@ -5010,6 +5016,7 @@ 01EA176E2590F02F00E98E02 /* Cells */ = { isa = PBXGroup; children = ( + 8F43E68D29A32A360047C21F /* EndOfLifeThankYou */, 34D873C1297971140065E839 /* AppClosureNotice */, 01EA17BF2591346300E98E02 /* ExposureLogging */, BA91611B27ECD2D10076BC6B /* Family */, @@ -7369,6 +7376,16 @@ path = __tests__; sourceTree = ""; }; + 8F43E68D29A32A360047C21F /* EndOfLifeThankYou */ = { + isa = PBXGroup; + children = ( + 8F43E68E29A32A890047C21F /* EndOfLifeThankYouCell.swift */, + 8F43E69229A332280047C21F /* EndOfLifeThankYouCellViewModel.swift */, + 8F43E68F29A32A890047C21F /* EndOfLifeThankYouCell.xib */, + ); + path = EndOfLifeThankYou; + sourceTree = ""; + }; 8F47CB65293E35A2008D91E5 /* StoreV6 */ = { isa = PBXGroup; children = ( @@ -11062,6 +11079,7 @@ 01D02733258BD36800B6389A /* MainSettingsCell.xib in Resources */, BA6D163B255AD35900ED3492 /* DMSwitchTableViewCell.xib in Resources */, 013069512705D4A900D945E3 /* QRScannerTooltipViewController.xib in Resources */, + 8F43E69129A32A890047C21F /* EndOfLifeThankYouCell.xib in Resources */, 85D7594B24570491008175F0 /* Assets.xcassets in Resources */, DC03798228EDA34E00E1EE20 /* HomeLinkCardView.xib in Resources */, 34D873C72979773D0065E839 /* HomeAppClosureNoticeTableViewCell.xib in Resources */, @@ -11505,6 +11523,7 @@ 8F613538287B257700FD2DD8 /* PPASubmitResource.swift in Sources */, 01BA0755262094D700237DD8 /* AerosoleDecayFunctionLinear.swift in Sources */, ABE17DE727B14A4200E9EA2D /* Set+Utils.swift in Sources */, + 8F43E69029A32A890047C21F /* EndOfLifeThankYouCell.swift in Sources */, AB61206A27B3FDE900CC8C08 /* Array+Utils.swift in Sources */, 019E2EFC269C8EF0000EC4AD /* SAP_Internal_Dgc_ValueSet+DisplayText.swift in Sources */, BA6C8A9E254D634E008344F5 /* RiskCalculationConfiguration.swift in Sources */, @@ -11707,6 +11726,7 @@ BA6C8AB9254D64D3008344F5 /* MinutesAtAttenuationWeight.swift in Sources */, 7154EB4C247E862100A467FF /* ExposureDetectionLoadingCell.swift in Sources */, 4B54B35226D52B8F00A49EB9 /* MockENManager.swift in Sources */, + 8F43E69329A332280047C21F /* EndOfLifeThankYouCellViewModel.swift in Sources */, 94EAF87925B6CAA300BE1F40 /* DeltaOnboardingNewVersionFeaturesViewModel.swift in Sources */, ABB078F0273034AC0037B30F /* SecureCache.swift in Sources */, 01A4DD4325935D1F007D5794 /* HomeRiskCellModel.swift in Sources */, diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift new file mode 100644 index 00000000000..3a12b59aaa4 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -0,0 +1,67 @@ +// +// 🦠 Corona-Warn-App +// + +import UIKit + +final class EndOfLifeThankYouCell: UITableViewCell { + + // MARK: - Overrides + + override func prepareForInterfaceBuilder() { + super.prepareForInterfaceBuilder() + + setup() + } + + override func awakeFromNib() { + super.awakeFromNib() + + setup() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + updateIllustration(for: traitCollection) + } + + + // MARK: - Internal + + func configure(with cellModel: EndOfLifeThankYouCellViewModel) { + titleLabel.text = cellModel.title + titleLabel.accessibilityIdentifier = cellModel.titleAccessibilityIdentifier + descriptionLabel.text = cellModel.description + descriptionLabel.accessibilityIdentifier = cellModel.descriptionAccessibilityIdentifier + illustrationImageView.image = cellModel.image + } + + // MARK: - Private + + private func setup() { + updateIllustration(for: traitCollection) + clipsToBounds = false + + setupAccessibility() + } + + private func updateIllustration(for traitCollection: UITraitCollection) { + if traitCollection.preferredContentSizeCategory >= .accessibilityLarge { + illustrationImageView.isHidden = true + } else { + illustrationImageView.isHidden = false + } + } + + private func setupAccessibility() { + cardView.accessibilityElements = [titleLabel as Any, descriptionLabel as Any] + + titleLabel.accessibilityTraits = [.header, .button] + } + + @IBOutlet private weak var cardView: HomeCardView! + @IBOutlet private weak var illustrationImageView: UIImageView! + @IBOutlet private weak var descriptionLabel: ENALabel! + @IBOutlet private weak var titleLabel: ENALabel! +} diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib new file mode 100644 index 00000000000..ab81bdb15f3 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 95e31d3309026fd3906e6efd0330b9b8608837a5 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 21 Feb 2023 10:09:59 +0100 Subject: [PATCH 010/137] add new strings and identifiers --- .../ENA/Resources/Localization/de.lproj/Localizable.strings | 6 ++++++ .../ENA/Source/View Helpers/AccessibilityIdentifiers.swift | 5 +++++ src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings index 093bc4cc239..d91408c4d71 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings @@ -1521,6 +1521,12 @@ Bei ausgeschalteter Hintergrundaktualisierung müssen Sie die App täglich aufru "Home_Finding_Positive_Card_Button_Remove_Test" = "Test löschen"; +/* Home End of Life Thank you Card */ + +"Home_EndOfLifeThankYouTile_Title" = "Vielen Dank!"; + +"Home_EndOfLifeThankYouTile_description" = "Der Betrieb der Corona-Warn-App wurde eingestellt. Vielen Dank für Ihre Nutzung. Mit Ihrer Unterstützung konnten während der Pandemie mehr als %i Millionen Warnungen verschickt werden. Sie können weiterhin auf Ihre bereits vorhandenen Zertifikate und das Kontakt-Tagebuch zugreifen. Alle anderen Funktionen stehen nicht mehr zur Verfügung. In den Geräteeinstellungen Ihres Smartphones können Sie jetzt die Benachrichtigungen für die App deaktivieren."; + /* Home Test Registration Card */ "Home_TestRegistration_Title" = "Tests erfassen und andere warnen"; diff --git a/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift b/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift index 9df58db0fc5..8722c31b196 100644 --- a/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift +++ b/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift @@ -154,6 +154,11 @@ enum AccessibilityIdentifiers { static let shareLabel = "AppStrings.Home.shareActionView" } + enum EndOfLifeThankYouCell { + static let titleLabel = "AppStrings.Home.EndOfLifeThankYouCell.titleLabel" + static let descriptionLabel = "AppStrings.Home.EndOfLifeThankYouCell.descriptionLabel" + } + enum TestRegistrationCell { static let titleLabel = "AppStrings.Home.TestRegistrationCell.titleLabel" static let descriptionLabel = "AppStrings.Home.TestRegistrationCell.descriptionLabel" diff --git a/src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift b/src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift index b30c4389b58..2089b5fcb2e 100644 --- a/src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift +++ b/src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift @@ -1100,6 +1100,11 @@ enum AppStrings { } } + enum EndOfLifeThankYouTile { + static let title = NSLocalizedString("Home_EndOfLifeThankYouTile_Title", comment: "") + static let description = NSLocalizedString("Home_EndOfLifeThankYouTile_description", comment: "") + } + enum TestRegistration { static let title = NSLocalizedString("Home_TestRegistration_Title", comment: "") static let subtitle = NSLocalizedString("Home_TestRegistration_Subtitle", comment: "") From 0ee754c14cb2c81684a29aeadf554e50b13bb780 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 21 Feb 2023 10:10:24 +0100 Subject: [PATCH 011/137] add EndOfLifeThankYouCellViewModel --- .../EndOfLifeThankYouCellViewModel.swift | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift new file mode 100644 index 00000000000..3a3cafd4d30 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -0,0 +1,22 @@ +// +// 🦠 Corona-Warn-App +// + +import UIKit + +class EndOfLifeThankYouCellViewModel { + + // MARK: - Internal + + var title = AppStrings.Home.EndOfLifeThankYouTile.title + // TODO get the xx value in figma + var description = String( + format: AppStrings.Home.EndOfLifeThankYouTile.description, + 4 + ) + var image = UIImage(named: "EndOfLifeThankYouIllustration") + var tintColor: UIColor = .enaColor(for: .textPrimary1) + + var titleAccessibilityIdentifier = AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.titleLabel + var descriptionAccessibilityIdentifier = AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel +} From 4d34285ff34b2e102b652640da62a2fcf3f10053 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 21 Feb 2023 10:11:00 +0100 Subject: [PATCH 012/137] update HomeTableViewController --- .../Scenes/Home/HomeTableViewController.swift | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 03802bfc4fd..a86a536ff52 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -106,8 +106,16 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega viewModel.cclService.shouldShowNoticeTile .receive(on: DispatchQueue.OCombine(.main)) .sink { [weak self] shouldShowNoticeTile in + let isHibernationState = CWAHibernationProvider.shared.isHibernationState + self?.viewModel.isHibernationState = isHibernationState self?.viewModel.shouldShowAppClosureNotice = shouldShowNoticeTile - self?.tableView.reloadSections([HomeTableViewModel.Section.appClosureNotice.rawValue], with: .none) + self?.tableView.reloadSections( + [ + HomeTableViewModel.Section.appClosureNotice.rawValue, + HomeTableViewModel.Section.endOfLifeThankYou.rawValue + ], + with: .none + ) } .store(in: &subscriptions) } @@ -181,6 +189,8 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega // swiftlint:disable:next cyclomatic_complexity override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { switch HomeTableViewModel.Section(rawValue: indexPath.section) { + case .endOfLifeThankYou: + return endOfLifeThankYouCell(forRowAt: indexPath) case .appClosureNotice: return appClosureNoticeCell(forRowAt: indexPath, statusTabNotice: viewModel.statusTabNotice) case .exposureLogging: @@ -397,6 +407,10 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega UINib(nibName: String(describing: HomeShownPositiveTestResultTableViewCell.self), bundle: nil), forCellReuseIdentifier: String(describing: HomeShownPositiveTestResultTableViewCell.self) ) + tableView.register( + UINib(nibName: String(describing: EndOfLifeThankYouCell.self), bundle: nil), + forCellReuseIdentifier: String(describing: EndOfLifeThankYouCell.self) + ) tableView.register( UINib(nibName: String(describing: HomeTestRegistrationTableViewCell.self), bundle: nil), forCellReuseIdentifier: String(describing: HomeTestRegistrationTableViewCell.self) @@ -621,6 +635,15 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega return cell } + + private func endOfLifeThankYouCell(forRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: EndOfLifeThankYouCell.self), for: indexPath) as? EndOfLifeThankYouCell else { + fatalError("Could not dequeue EndOfLifeThankYouCell") + } + cell.configure(with: EndOfLifeThankYouCellViewModel()) + + return cell + } private func testRegistrationCell(forRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: HomeTestRegistrationTableViewCell.self), for: indexPath) as? HomeTestRegistrationTableViewCell else { From c2e7c77815a341f92efc5dcd91a019016f095753 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 21 Feb 2023 10:11:21 +0100 Subject: [PATCH 013/137] update homeTableviewModel --- src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift index 6f8c2fc58c1..d8449cc6233 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift @@ -66,6 +66,7 @@ class HomeTableViewModel { // MARK: - Internal enum Section: Int, CaseIterable { + case endOfLifeThankYou case appClosureNotice case exposureLogging case riskAndTestResults @@ -94,6 +95,7 @@ class HomeTableViewModel { let cclService: CCLServable var isUpdating: Bool = false var shouldShowAppClosureNotice: Bool = false + var isHibernationState: Bool = false @OpenCombine.Published var testResultLoadingError: Error? @OpenCombine.Published var riskAndTestResultsRows: [RiskAndTestResultsRow] = [] @@ -119,6 +121,8 @@ class HomeTableViewModel { func numberOfRows(in section: Int) -> Int { switch Section(rawValue: section) { + case .endOfLifeThankYou: + return isHibernationState ? 1 : 0 case .appClosureNotice: #if DEBUG if isUITesting, LaunchArguments.appClosureNotice.showAppClosureNoticeTile.boolValue { From 23c31795719d538c5e469cd5154d417d8c7261fc Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 21 Feb 2023 10:11:44 +0100 Subject: [PATCH 014/137] update unit tests --- .../Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift index 8a679c0c36d..12c26fa1ee9 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift @@ -38,7 +38,7 @@ class HomeTableViewModelTests: CWATestCase { ) // Number of Sections - XCTAssertEqual(viewModel.numberOfSections, 7) + XCTAssertEqual(viewModel.numberOfSections, 8) // Number of Rows per Section XCTAssertEqual(viewModel.numberOfRows(in: 0), 0) From baa2d1138e6b9ef2dc7daf914ad317c44c648e7a Mon Sep 17 00:00:00 2001 From: Puneet Mahali Date: Tue, 21 Feb 2023 11:43:44 +0100 Subject: [PATCH 015/137] ramp down changes to certificates --- .../FooterViewController/FooterViewModel.swift | 1 + .../HealthCertificateViewController.swift | 2 +- .../HealthCertificateViewModel.swift | 2 +- .../HealthCertificate/HealthCertificateCell.swift | 8 ++++++-- .../HealthCertifiedPersonViewModel.swift | 15 ++++++++++++--- .../Services/CCLService/DCCWalletInfo.swift | 14 +++++++------- 6 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/FooterViewController/FooterViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/FooterViewController/FooterViewModel.swift index 829737eb330..01d39c9bc7d 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/FooterViewController/FooterViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/FooterViewController/FooterViewModel.swift @@ -120,6 +120,7 @@ final class FooterViewModel { switch button { case .primary: isPrimaryButtonEnabled = isEnabled + isPrimaryButtonHidden = CWAHibernationProvider.shared.isHibernationState case .secondary: isSecondaryButtonEnabled = isEnabled } diff --git a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertificate/HealthCertificateViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertificate/HealthCertificateViewController.swift index c5f2bd5c9c0..7c8fd0393da 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertificate/HealthCertificateViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertificate/HealthCertificateViewController.swift @@ -151,7 +151,7 @@ class HealthCertificateViewController: UIViewController, UITableViewDataSource, func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // we are only interested in detail cell with person name once if the traitCollectionDidChange - to update gradientHeightConstraint guard didCalculateGradientHeight == false, - HealthCertificateViewModel.TableViewSection.map(indexPath.section) == .qrCode, + HealthCertificateViewModel.TableViewSection.map(indexPath.section) == .qrCode, indexPath.row == 0 else { return diff --git a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertificate/HealthCertificateViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertificate/HealthCertificateViewModel.swift index 924b3bd31d5..d9e26db91ef 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertificate/HealthCertificateViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertificate/HealthCertificateViewModel.swift @@ -115,7 +115,7 @@ final class HealthCertificateViewModel { let formattedDate = DateFormatter.localizedString(from: healthCertificate.expirationDate, dateStyle: .medium, timeStyle: .short) return HealthCertificateExpirationDateCellViewModel( headline: AppStrings.HealthCertificate.Details.expirationDateTitle, - expirationDate: String(format: AppStrings.HealthCertificate.Details.expirationDatePlaceholder, formattedDate) , + expirationDate: String(format: AppStrings.HealthCertificate.Details.expirationDatePlaceholder, formattedDate), content: nil ) } diff --git a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertifiedPerson/Cells/HealthCertificate/HealthCertificateCell.swift b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertifiedPerson/Cells/HealthCertificate/HealthCertificateCell.swift index 137b45a5c20..6d200e68fb1 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertifiedPerson/Cells/HealthCertificate/HealthCertificateCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertifiedPerson/Cells/HealthCertificate/HealthCertificateCell.swift @@ -56,8 +56,12 @@ class HealthCertificateCell: UITableViewCell, ReuseIdentifierProviding { currentlyUsedStackView.isHidden = !cellViewModel.isCurrentlyUsedCertificateHintVisible currentlyUsedImageView.image = cellViewModel.currentlyUsedImage - validationButton.isEnabled = cellViewModel.isValidationButtonEnabled - validationButton.isHidden = !cellViewModel.isValidationButtonVisible + if CWAHibernationProvider.shared.isHibernationState { + validationButton.isHidden = true + } else { + validationButton.isEnabled = cellViewModel.isValidationButtonEnabled + validationButton.isHidden = !cellViewModel.isValidationButtonVisible + } unseenNewsIndicator.isHidden = !cellViewModel.isUnseenNewsIndicatorVisible diff --git a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertifiedPerson/HealthCertifiedPersonViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertifiedPerson/HealthCertifiedPersonViewModel.swift index 0346823e4a1..5d424ae776a 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertifiedPerson/HealthCertifiedPersonViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/HealthCertifiedPerson/HealthCertifiedPersonViewModel.swift @@ -142,7 +142,10 @@ final class HealthCertifiedPersonViewModel { } var certificateReissuanceIsVisible: Bool { - healthCertifiedPerson.dccWalletInfo?.certificateReissuance?.reissuanceDivision.visible ?? false + if CWAHibernationProvider.shared.isHibernationState { + healthCertifiedPerson.dccWalletInfo?.certificateReissuance?.reissuanceDivision.visible = false + } + return healthCertifiedPerson.dccWalletInfo?.certificateReissuance?.reissuanceDivision.visible ?? false } var boosterNotificationIsVisible: Bool { @@ -150,11 +153,17 @@ final class HealthCertifiedPersonViewModel { } var vaccinationStateIsVisible: Bool { - healthCertifiedPerson.dccWalletInfo?.vaccinationState.visible ?? false + if CWAHibernationProvider.shared.isHibernationState { + healthCertifiedPerson.dccWalletInfo?.vaccinationState.visible = false + } + return healthCertifiedPerson.dccWalletInfo?.vaccinationState.visible ?? false } var admissionStateIsVisible: Bool { - healthCertifiedPerson.dccWalletInfo?.admissionState.visible ?? false + if CWAHibernationProvider.shared.isHibernationState { + healthCertifiedPerson.dccWalletInfo?.admissionState.visible = false + } + return healthCertifiedPerson.dccWalletInfo?.admissionState.visible ?? false } var maskStateIsVisible: Bool { diff --git a/src/xcode/ENA/ENA/Source/Services/CCLService/DCCWalletInfo.swift b/src/xcode/ENA/ENA/Source/Services/CCLService/DCCWalletInfo.swift index 7933a103887..ab07f498c30 100644 --- a/src/xcode/ENA/ENA/Source/Services/CCLService/DCCWalletInfo.swift +++ b/src/xcode/ENA/ENA/Source/Services/CCLService/DCCWalletInfo.swift @@ -25,14 +25,14 @@ struct StatusTabNotice: Codable, Equatable { struct DCCWalletInfo: Codable, Equatable { - let admissionState: DCCAdmissionState - let vaccinationState: DCCVaccinationState + var admissionState: DCCAdmissionState + var vaccinationState: DCCVaccinationState let maskState: DCCMaskState? let boosterNotification: DCCBoosterNotification let mostRelevantCertificate: DCCCertificateContainer let verification: DCCVerification let validUntil: Date? - let certificateReissuance: DCCCertificateReissuance? + var certificateReissuance: DCCCertificateReissuance? let certificatesRevokedByInvalidationRules: [DCCCertificateContainer]? } @@ -63,7 +63,7 @@ struct DCCScenarioSelectionItem: Codable, Equatable { struct DCCAdmissionState: Codable, Equatable { let identifier: String? - let visible: Bool + var visible: Bool let badgeText: DCCUIText? let titleText: DCCUIText? let subtitleText: DCCUIText? @@ -76,7 +76,7 @@ struct DCCAdmissionState: Codable, Equatable { struct DCCVaccinationState: Codable, Equatable { - let visible: Bool + var visible: Bool let titleText: DCCUIText? let subtitleText: DCCUIText? let longText: DCCUIText? @@ -142,7 +142,7 @@ struct DCCCertificateReference: Codable, Equatable { struct DCCCertificateReissuance: Codable, Equatable { - let reissuanceDivision: DCCCertificateReissuanceDivision + var reissuanceDivision: DCCCertificateReissuanceDivision // legacy from CCL config-v2 - needed for backward compatibility let certificateToReissue: DCCCertificateContainer? // legacy from CCL config-v2 - needed for backward compatibility @@ -153,7 +153,7 @@ struct DCCCertificateReissuance: Codable, Equatable { struct DCCCertificateReissuanceDivision: Codable, Equatable { - let visible: Bool + var visible: Bool let titleText: DCCUIText? let subtitleText: DCCUIText? let longText: DCCUIText? From b8ea74cbf5947ec50bf56888eb57cf8d5aa9b2d8 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 21 Feb 2023 12:23:19 +0100 Subject: [PATCH 016/137] 14812: Swiftlint. --- .../AppDelegate & Globals/CWAHibernationProvider.swift | 2 +- .../__tests__/CWAHibernationProviderTests.swift | 10 ++++++++-- .../ENA/Source/Developer Menu/DMViewController.swift | 6 +----- .../DMHibernation/DMHibernationOptionsViewModel.swift | 9 +++++---- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 507e1c24803..d353b6f24b0 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -59,6 +59,6 @@ class CWAHibernationProvider: RequiresAppDependencies { #if !RELEASE /// For UI/Unit Test purposes only - private var customStore: Store? = nil + private var customStore: Store? #endif } diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index bf3d8f2c020..4bed4b56271 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -22,7 +22,10 @@ final class CWAHibernationProviderTests: CWATestCase { beforeHibernationStartDateComponents.second = 59 beforeHibernationStartDateComponents.timeZone = .utcTimeZone - mockTestStore.hibernationComparingDate = Calendar.current.date(from: beforeHibernationStartDateComponents)! + guard let hibernationComparingDate = Calendar.current.date(from: beforeHibernationStartDateComponents) else { + return XCTFail("Expect the hibernation comparing date from the corresponding date components.") + } + mockTestStore.hibernationComparingDate = hibernationComparingDate // THEN XCTAssertFalse(sut.isHibernationState) @@ -43,7 +46,10 @@ final class CWAHibernationProviderTests: CWATestCase { afterHibernationStartDateComponents.second = 0 afterHibernationStartDateComponents.timeZone = .utcTimeZone - mockTestStore.hibernationComparingDate = Calendar.current.date(from: afterHibernationStartDateComponents)! + guard let hibernationComparingDate = Calendar.current.date(from: afterHibernationStartDateComponents) else { + return XCTFail("Expect the hibernation comparing date from the corresponding date components.") + } + mockTestStore.hibernationComparingDate = hibernationComparingDate // THEN XCTAssertTrue(sut.isHibernationState) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift b/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift index 88da82c6d88..ba8a1468c16 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift @@ -87,11 +87,7 @@ final class DMViewController: UITableViewController, RequiresAppDependencies { case .healthCertificateMigration: vc = DMHealthCertificateMigrationViewController(store: store) case .cclConfig: - vc = DMCCLConfigurationViewController( - viewModel: DMCCLConfigurationViewModel( - restService: restServiceProvider - ) - ) + vc = DMCCLConfigurationViewController(viewModel: DMCCLConfigurationViewModel(restService: restServiceProvider)) case .revocationList: vc = DMRevocationListViewController() case .newHttp: diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index da5c7e115c8..f6ffa0541f3 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -50,9 +50,10 @@ class DMHibernationOptionsViewModel { return DMButtonCellViewModel( text: "Reset Comparing Date", textColor: .white, - backgroundColor: .enaColor(for: .buttonDestructive)) { - self.store(hibernationComparingDate: Date()) - } + backgroundColor: .enaColor(for: .buttonDestructive) + ) { [weak self] in + self?.store(hibernationComparingDate: Date()) + } } } @@ -81,7 +82,7 @@ class DMHibernationOptionsViewModel { } extension DMHibernationOptionsViewModel { - enum Sections :Int, CaseIterable { + enum Sections: Int, CaseIterable { /// The date, that will be used to compare it against the hibernation start date (01.06.2023) case hibernationComparingDate /// Reset the stored fake date, the hibernation threshold compares to From 05956d6f57b6f5a3e7fbe5def10d225a41c13762 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 21 Feb 2023 15:03:40 +0100 Subject: [PATCH 017/137] 14812: PR remarks. --- .../CWAHibernationProvider.swift | 6 ++--- .../CWAHibernationProviderTests.swift | 4 ++-- .../Developer Menu/DMViewController.swift | 2 +- .../DMHibernationOptionsViewController.swift | 4 ++-- .../DMHibernationOptionsViewModel.swift | 22 +++++++++++-------- .../Developer Menu/Helper/DMMenuItem.swift | 6 ++--- .../__tests__/Mocks/MockTestStore.swift | 2 +- .../Source/Workers/Store/SecureStore.swift | 6 ++--- .../ENA/ENA/Source/Workers/Store/Store.swift | 2 +- 9 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index d353b6f24b0..ae4e7539e29 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -11,7 +11,7 @@ class CWAHibernationProvider: RequiresAppDependencies { /// Use shared instance instead private init() {} - #if !RELEASE + #if DEBUG /// For UI/Unit purposes only init(customStore: Store) { self.customStore = customStore @@ -27,7 +27,7 @@ class CWAHibernationProvider: RequiresAppDependencies { #if RELEASE return Date() >= hibernationStartDate #else - return secureStore.hibernationComparingDate >= hibernationStartDate + return secureStore.hibernationComparisonDate >= hibernationStartDate #endif } @@ -57,7 +57,7 @@ class CWAHibernationProvider: RequiresAppDependencies { #endif } - #if !RELEASE + #if DEBUG /// For UI/Unit Test purposes only private var customStore: Store? #endif diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index 4bed4b56271..4e6d741bd78 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -25,7 +25,7 @@ final class CWAHibernationProviderTests: CWATestCase { guard let hibernationComparingDate = Calendar.current.date(from: beforeHibernationStartDateComponents) else { return XCTFail("Expect the hibernation comparing date from the corresponding date components.") } - mockTestStore.hibernationComparingDate = hibernationComparingDate + mockTestStore.hibernationComparisonDate = hibernationComparingDate // THEN XCTAssertFalse(sut.isHibernationState) @@ -49,7 +49,7 @@ final class CWAHibernationProviderTests: CWATestCase { guard let hibernationComparingDate = Calendar.current.date(from: afterHibernationStartDateComponents) else { return XCTFail("Expect the hibernation comparing date from the corresponding date components.") } - mockTestStore.hibernationComparingDate = hibernationComparingDate + mockTestStore.hibernationComparisonDate = hibernationComparingDate // THEN XCTAssertTrue(sut.isHibernationState) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift b/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift index ba8a1468c16..cc89b318257 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/DMViewController.swift @@ -179,7 +179,7 @@ final class DMViewController: UITableViewController, RequiresAppDependencies { vc = DMCrashAppViewController() case .srs: vc = DMSRSOptionsViewController(store: store) - case .hibernation2023: + case .hibernation: vc = DMHibernationOptionsViewController(store: store) } diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift index 85087d3c633..f74ffcda9d7 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift @@ -83,8 +83,8 @@ class DMHibernationOptionsViewController: UITableViewController { let cell = tableView.dequeueReusableCell(cellType: DMDatePickerTableViewCell.self, for: indexPath) cell.configure(cellViewModel: cellViewModel) - cell.didSelectDate = { [weak self] hibernationComparingDate in - self?.viewModel.store(hibernationComparingDate: hibernationComparingDate) + cell.didSelectDate = { [weak self] hibernationComparisonDate in + self?.viewModel.store(hibernationComparisonDate: hibernationComparisonDate) } return cell diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index f6ffa0541f3..4ece74b3434 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -4,6 +4,8 @@ import Foundation +#if !RELEASE + class DMHibernationOptionsViewModel { // MARK: - Init @@ -25,11 +27,11 @@ class DMHibernationOptionsViewModel { switch section { case .hibernationComparingDate: - var title = "App will be shutdown after set a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date \(dateFormatter.string(from: store.hibernationComparingDate))" + var title = "App will shutdown after selecting a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationComparisonDate))" return title case .reset: - return "App will be shutdown after reset to today date." + return "App will shutdown after reseting to today's date." } } @@ -41,25 +43,25 @@ class DMHibernationOptionsViewModel { switch section { case .hibernationComparingDate: return DMDatePickerCellViewModel( - title: "Hibernation Comparing Date", + title: "Hibernation Comparison Date", accessibilityIdentifier: AccessibilityIdentifiers.DeveloperMenu.Hibernation.datePicker, datePickerMode: .date, - date: store.hibernationComparingDate + date: store.hibernationComparisonDate ) case .reset: return DMButtonCellViewModel( - text: "Reset Comparing Date", + text: "Reset Comparison Date", textColor: .white, backgroundColor: .enaColor(for: .buttonDestructive) ) { [weak self] in - self?.store(hibernationComparingDate: Date()) + self?.store(hibernationComparisonDate: Date()) } } } - func store(hibernationComparingDate: Date) { - Log.debug("[Debug-Menu] Set hibernation comparing date to \(dateFormatter.string(from: hibernationComparingDate)).") - store.hibernationComparingDate = hibernationComparingDate + func store(hibernationComparisonDate: Date) { + Log.debug("[Debug-Menu] Set hibernation comparison date to: \(dateFormatter.string(from: hibernationComparisonDate)).") + store.hibernationComparisonDate = hibernationComparisonDate exitApp() } @@ -89,3 +91,5 @@ extension DMHibernationOptionsViewModel { case reset } } + +#endif diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Helper/DMMenuItem.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Helper/DMMenuItem.swift index 69348871252..3a3ad8b0350 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Helper/DMMenuItem.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Helper/DMMenuItem.swift @@ -46,7 +46,7 @@ enum DMMenuItem: Int, CaseIterable { case boosterRules case crashApp case srs - case hibernation2023 + case hibernation } extension DMMenuItem { @@ -102,7 +102,7 @@ extension DMMenuItem { case .boosterRules: return "Download Booster rules" case .crashApp: return "Crash App" case .srs: return "SRS Options" - case .hibernation2023: return "CWA Hibernation 2023" + case .hibernation: return "CWA Hibernation" } } var subtitle: String { @@ -146,7 +146,7 @@ extension DMMenuItem { case .boosterRules: return "Download Booster rules and trigger the notification" case .crashApp: return "Crash the App to test crash reporting." case .srs: return "Configure SRS Behavior" - case .hibernation2023: return "Change date and time to trigger hibernation." + case .hibernation: return "Change date and time to trigger hibernation." } } } diff --git a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift index 42dd26f6e2f..8b7dcea598b 100644 --- a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift +++ b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift @@ -63,7 +63,7 @@ final class MockTestStore: Store, PPAnalyticsData { var forceAPITokenAuthorization = false var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? var isSrsPrechecksEnabled = false - var hibernationComparingDate = Date() + var hibernationComparisonDate = Date() #endif // MARK: - AppConfigCaching diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift index 6a2b18d68c2..efdb0073791 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift @@ -378,9 +378,9 @@ final class SecureStore: SecureKeyValueStoring, Store { set { kvStore["recentTraceLocationCheckedInto"] = newValue } } - var hibernationComparingDate: Date { - get { kvStore["hibernationComparingDate"] as Date? ?? Date() } - set { kvStore["hibernationComparingDate"] = newValue } + var hibernationComparisonDate: Date { + get { kvStore["hibernationComparisonDate"] as Date? ?? Date() } + set { kvStore["hibernationComparisonDate"] = newValue } } #endif diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift index 2396ff0bf0e..275c0376d81 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift @@ -87,7 +87,7 @@ protocol StoreProtocol: AnyObject { var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? { get set } - var hibernationComparingDate: Date { get set } + var hibernationComparisonDate: Date { get set } #endif From 0f35a41c65397409d83511e94f0a096b972fdfd8 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 21 Feb 2023 15:21:34 +0100 Subject: [PATCH 018/137] Update src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift Co-authored-by: Felix Schmidt --- .../EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index 3a3cafd4d30..7234f5bdc33 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -9,7 +9,7 @@ class EndOfLifeThankYouCellViewModel { // MARK: - Internal var title = AppStrings.Home.EndOfLifeThankYouTile.title - // TODO get the xx value in figma + // to.do get the xx value in figma var description = String( format: AppStrings.Home.EndOfLifeThankYouTile.description, 4 From 760501b7f10dd61b3424d4084bb03b0914f129a5 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 21 Feb 2023 15:22:05 +0100 Subject: [PATCH 019/137] Update src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift Co-authored-by: Felix Schmidt --- .../Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift index 3a12b59aaa4..7121aa3b2f4 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -47,11 +47,7 @@ final class EndOfLifeThankYouCell: UITableViewCell { } private func updateIllustration(for traitCollection: UITraitCollection) { - if traitCollection.preferredContentSizeCategory >= .accessibilityLarge { - illustrationImageView.isHidden = true - } else { - illustrationImageView.isHidden = false - } +illustrationImageView.isHidden = traitCollection.preferredContentSizeCategory >= .accessibilityLarge } private func setupAccessibility() { From c074689de7d7aad3fa97f29ef08f6ac19225c284 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 21 Feb 2023 15:22:16 +0100 Subject: [PATCH 020/137] 14812: Minor naming changes. --- .../__tests__/CWAHibernationProviderTests.swift | 16 ++++++++-------- .../DMHibernationOptionsViewController.swift | 8 ++++---- .../DMHibernationOptionsViewModel.swift | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index 4e6d741bd78..94113d94a07 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -7,7 +7,7 @@ import XCTest final class CWAHibernationProviderTests: CWATestCase { - func testIsHibernationState_Store_HibernationComparingDate_before_false() throws { + func testIsHibernationState_Store_HibernationComparisonDate_before_false() throws { // GIVEN let mockTestStore = MockTestStore() let sut = CWAHibernationProvider(customStore: mockTestStore) @@ -22,16 +22,16 @@ final class CWAHibernationProviderTests: CWATestCase { beforeHibernationStartDateComponents.second = 59 beforeHibernationStartDateComponents.timeZone = .utcTimeZone - guard let hibernationComparingDate = Calendar.current.date(from: beforeHibernationStartDateComponents) else { - return XCTFail("Expect the hibernation comparing date from the corresponding date components.") + guard let hibernationComparisonDate = Calendar.current.date(from: beforeHibernationStartDateComponents) else { + return XCTFail("Expect the hibernation comparison date from the corresponding date components.") } - mockTestStore.hibernationComparisonDate = hibernationComparingDate + mockTestStore.hibernationComparisonDate = hibernationComparisonDate // THEN XCTAssertFalse(sut.isHibernationState) } - func testIsHibernationState_Store_HibernationComparingDate_after_true() throws { + func testIsHibernationState_Store_HibernationComparisonDate_after_true() throws { // GIVEN let mockTestStore = MockTestStore() let sut = CWAHibernationProvider(customStore: mockTestStore) @@ -46,10 +46,10 @@ final class CWAHibernationProviderTests: CWATestCase { afterHibernationStartDateComponents.second = 0 afterHibernationStartDateComponents.timeZone = .utcTimeZone - guard let hibernationComparingDate = Calendar.current.date(from: afterHibernationStartDateComponents) else { - return XCTFail("Expect the hibernation comparing date from the corresponding date components.") + guard let hibernationComparisonDate = Calendar.current.date(from: afterHibernationStartDateComponents) else { + return XCTFail("Expect the hibernation comparison date from the corresponding date components.") } - mockTestStore.hibernationComparisonDate = hibernationComparingDate + mockTestStore.hibernationComparisonDate = hibernationComparisonDate // THEN XCTAssertTrue(sut.isHibernationState) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift index f74ffcda9d7..6adc94c0fdb 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift @@ -46,10 +46,10 @@ class DMHibernationOptionsViewController: UITableViewController { let cellViewModel = viewModel.cellViewModel(for: indexPath) if let cellViewModel = cellViewModel as? DMDatePickerCellViewModel { - return configureHibernationComparingDatePickerCell(cellViewModel: cellViewModel, indexPath: indexPath) + return configureHibernationComparisonDatePickerCell(cellViewModel: cellViewModel, indexPath: indexPath) } else if let cellViewModel = cellViewModel as? DMButtonCellViewModel { - return configureHibernationComparingDateResetCell(cellViewModel: cellViewModel, indexPath: indexPath) + return configureHibernationComparisonDateResetCell(cellViewModel: cellViewModel, indexPath: indexPath) } else { return UITableViewCell() @@ -76,7 +76,7 @@ class DMHibernationOptionsViewController: UITableViewController { tableView.register(DMButtonTableViewCell.self, forCellReuseIdentifier: DMButtonTableViewCell.reuseIdentifier) } - private func configureHibernationComparingDatePickerCell( + private func configureHibernationComparisonDatePickerCell( cellViewModel: DMDatePickerCellViewModel, indexPath: IndexPath ) -> DMDatePickerTableViewCell { @@ -90,7 +90,7 @@ class DMHibernationOptionsViewController: UITableViewController { return cell } - private func configureHibernationComparingDateResetCell( + private func configureHibernationComparisonDateResetCell( cellViewModel: DMButtonCellViewModel, indexPath: IndexPath ) -> DMButtonTableViewCell { diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index 4ece74b3434..1c32b38607a 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -26,7 +26,7 @@ class DMHibernationOptionsViewModel { } switch section { - case .hibernationComparingDate: + case .hibernationComparisonDate: var title = "App will shutdown after selecting a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationComparisonDate))" return title @@ -41,7 +41,7 @@ class DMHibernationOptionsViewModel { } switch section { - case .hibernationComparingDate: + case .hibernationComparisonDate: return DMDatePickerCellViewModel( title: "Hibernation Comparison Date", accessibilityIdentifier: AccessibilityIdentifiers.DeveloperMenu.Hibernation.datePicker, @@ -86,7 +86,7 @@ class DMHibernationOptionsViewModel { extension DMHibernationOptionsViewModel { enum Sections: Int, CaseIterable { /// The date, that will be used to compare it against the hibernation start date (01.06.2023) - case hibernationComparingDate + case hibernationComparisonDate /// Reset the stored fake date, the hibernation threshold compares to case reset } From 0cd7779b44e8bab8e5a80498da8736f131e07ab2 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 21 Feb 2023 16:14:34 +0100 Subject: [PATCH 021/137] 14812: Remove 2023 word. --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index ae4e7539e29..afc3b9ac983 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -31,7 +31,7 @@ class CWAHibernationProvider: RequiresAppDependencies { #endif } - /// CWA hibernation 2023 threshold date. + /// CWA hibernation threshold date. private let hibernationStartDate: Date = { var hibernationStartDateComponents = DateComponents() hibernationStartDateComponents.year = 2023 From 1a9dae13cbe9936597f2afcc8956b394745ffb4a Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 21 Feb 2023 16:17:11 +0100 Subject: [PATCH 022/137] 14815: Hide QR Scanner and Check-In in TabBar when Hibernation. --- .../ENA/ENA/Source/RootCoordinator.swift | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/RootCoordinator.swift b/src/xcode/ENA/ENA/Source/RootCoordinator.swift index 4ccc3029487..8af086d0683 100644 --- a/src/xcode/ENA/ENA/Source/RootCoordinator.swift +++ b/src/xcode/ENA/ENA/Source/RootCoordinator.swift @@ -45,7 +45,8 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele recycleBin: RecycleBin, restServiceProvider: RestServiceProviding, badgeWrapper: HomeBadgeWrapper, - cache: KeyValueCaching + cache: KeyValueCaching, + cwaHibernationProvider: CWAHibernationProvider = CWAHibernationProvider.shared ) { self.delegate = delegate self.coronaTestService = coronaTestService @@ -67,6 +68,7 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele self.restServiceProvider = restServiceProvider self.badgeWrapper = badgeWrapper self.cache = cache + self.cwaHibernationProvider = cwaHibernationProvider } deinit { @@ -256,22 +258,25 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele certificatesTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.certificates healthCertificatesTabCoordinator.viewController.tabBarItem = certificatesTabBarItem - let universalScannerTabBarItem = UITabBarItem( - title: nil, - image: UIImage(named: "Icons_Tabbar_UniversalScanner"), - selectedImage: nil - ) - universalScannerTabBarItem.accessibilityLabel = AppStrings.Tabbar.scannerTitle - universalScannerTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.scanner - universalScannerDummyViewController.tabBarItem = universalScannerTabBarItem - - let eventsTabBarItem = UITabBarItem( - title: AppStrings.Tabbar.checkInTitle, - image: UIImage(named: "Icons_Tabbar_Checkin"), - selectedImage: UIImage(named: "Icons_Tabbar_Checkin_Selected") - ) - eventsTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.checkin - checkinTabCoordinator.viewController.tabBarItem = eventsTabBarItem + // CWA Hibernation hides scanner and check-in tab + if !cwaHibernationProvider.isHibernationState { + let universalScannerTabBarItem = UITabBarItem( + title: nil, + image: UIImage(named: "Icons_Tabbar_UniversalScanner"), + selectedImage: nil + ) + universalScannerTabBarItem.accessibilityLabel = AppStrings.Tabbar.scannerTitle + universalScannerTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.scanner + universalScannerDummyViewController.tabBarItem = universalScannerTabBarItem + + let eventsTabBarItem = UITabBarItem( + title: AppStrings.Tabbar.checkInTitle, + image: UIImage(named: "Icons_Tabbar_Checkin"), + selectedImage: UIImage(named: "Icons_Tabbar_Checkin_Selected") + ) + eventsTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.checkin + checkinTabCoordinator.viewController.tabBarItem = eventsTabBarItem + } let diaryTabBarItem = UITabBarItem( title: AppStrings.Tabbar.diaryTitle, @@ -284,7 +289,15 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele tabBarController.tabBar.tintColor = .enaColor(for: .tint) tabBarController.tabBar.unselectedItemTintColor = .enaColor(for: .textPrimary2) tabBarController.delegate = self - tabBarController.setViewControllers([homeCoordinator.rootViewController, healthCertificatesTabCoordinator.viewController, universalScannerDummyViewController, checkinTabCoordinator.viewController, diaryCoordinator.viewController], animated: false) + + let tabBarViewControllers = [ + homeCoordinator.rootViewController, + healthCertificatesTabCoordinator.viewController, + cwaHibernationProvider.isHibernationState ? nil : universalScannerDummyViewController, + cwaHibernationProvider.isHibernationState ? nil : checkinTabCoordinator.viewController, + diaryCoordinator.viewController + ].compactMap { $0 } + tabBarController.setViewControllers(tabBarViewControllers, animated: false) viewController.clearChildViewController() viewController.embedViewController(childViewController: tabBarController) @@ -417,6 +430,7 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele private let badgeWrapper: HomeBadgeWrapper private let cache: KeyValueCaching private let tabBarController = UITabBarController() + private let cwaHibernationProvider: CWAHibernationProvider private var homeCoordinator: HomeCoordinator? private var homeState: HomeState? From 1df5df9c6f6db27132cf72db2bb69f07cc165af8 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 21 Feb 2023 16:25:51 +0100 Subject: [PATCH 023/137] 14812: Adapt a comment. --- .../DMHibernation/DMHibernationOptionsViewModel.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index 1c32b38607a..3bd8be04801 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -85,9 +85,9 @@ class DMHibernationOptionsViewModel { extension DMHibernationOptionsViewModel { enum Sections: Int, CaseIterable { - /// The date, that will be used to compare it against the hibernation start date (01.06.2023) + /// The date, that will be used to compare it against the hibernation start date. case hibernationComparisonDate - /// Reset the stored fake date, the hibernation threshold compares to + /// Reset the stored fake date, the hibernation threshold compares to. case reset } } From 3a3020836d0abbc74dc4ba225c7fbd4bce7a1480 Mon Sep 17 00:00:00 2001 From: Puneet Mahali Date: Tue, 21 Feb 2023 18:09:51 +0100 Subject: [PATCH 024/137] Add if condition --- .../Source/Scenes/FooterViewController/FooterViewModel.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/FooterViewController/FooterViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/FooterViewController/FooterViewModel.swift index 01d39c9bc7d..1e3f5152853 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/FooterViewController/FooterViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/FooterViewController/FooterViewModel.swift @@ -120,7 +120,9 @@ final class FooterViewModel { switch button { case .primary: isPrimaryButtonEnabled = isEnabled - isPrimaryButtonHidden = CWAHibernationProvider.shared.isHibernationState + if CWAHibernationProvider.shared.isHibernationState { + isPrimaryButtonHidden = true + } case .secondary: isSecondaryButtonEnabled = isEnabled } From 5c1385e327c7cffa61ef68353fe048cb56aece2b Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 22 Feb 2023 06:50:04 +0100 Subject: [PATCH 025/137] add launch argument for uitests --- .../AppDelegate & Globals/CWAHibernationProvider.swift | 9 ++++++--- src/xcode/ENA/ENAUITests/Utils/LaunchArguments.swift | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index afc3b9ac983..026e0050b04 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -24,10 +24,13 @@ class CWAHibernationProvider: RequiresAppDependencies { /// Determines if the CWA is in hibernation state. var isHibernationState: Bool { - #if RELEASE - return Date() >= hibernationStartDate - #else + #if DEBUG + if isUITesting { + return LaunchArguments.endOfLife.isHibernationStateEnabled.boolValue + } return secureStore.hibernationComparisonDate >= hibernationStartDate + #else + return Date() >= hibernationStartDate #endif } diff --git a/src/xcode/ENA/ENAUITests/Utils/LaunchArguments.swift b/src/xcode/ENA/ENAUITests/Utils/LaunchArguments.swift index ea67d83a3ac..6d101890462 100644 --- a/src/xcode/ENA/ENAUITests/Utils/LaunchArguments.swift +++ b/src/xcode/ENA/ENAUITests/Utils/LaunchArguments.swift @@ -191,6 +191,11 @@ enum LaunchArguments { static let shouldShowExportCertificatesTooltip = LaunchArgument(name: "shouldShowExportCertificatesTooltip") } + enum endOfLife { + /// set this to true if you want to force CWAHibernationProvider.isHibernationState to return true + static let isHibernationStateEnabled = LaunchArgument(name: "isHibernationStateEnabled") + } + enum notifications { /// Turn notifications for the settings screen on or off - does NOT sync or reflect the system setting. But needed to test the different screens. static let isNotificationsEnabled = LaunchArgument(name: "isNotificationsEnabled") From efa98476ea68faaf9d313bceee23f71de38614b6 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 22 Feb 2023 06:50:27 +0100 Subject: [PATCH 026/137] add unit test for the thank you tile --- .../__tests__/HomeTableViewModelTests.swift | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift index 12c26fa1ee9..2085b747da6 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift @@ -41,13 +41,18 @@ class HomeTableViewModelTests: CWATestCase { XCTAssertEqual(viewModel.numberOfSections, 8) // Number of Rows per Section + viewModel.isHibernationState = true + XCTAssertEqual(viewModel.numberOfRows(in: 0), 1) + viewModel.isHibernationState = false XCTAssertEqual(viewModel.numberOfRows(in: 0), 0) - XCTAssertEqual(viewModel.numberOfRows(in: 1), 1) + + XCTAssertEqual(viewModel.numberOfRows(in: 1), 0) XCTAssertEqual(viewModel.numberOfRows(in: 2), 1) XCTAssertEqual(viewModel.numberOfRows(in: 3), 1) XCTAssertEqual(viewModel.numberOfRows(in: 4), 1) XCTAssertEqual(viewModel.numberOfRows(in: 5), 1) XCTAssertEqual(viewModel.numberOfRows(in: 6), 1) + XCTAssertEqual(viewModel.numberOfRows(in: 7), 1) // Check riskAndTestResultsRows XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk]) @@ -86,7 +91,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .familyTestResults]) } @@ -168,7 +173,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .pcrTestResult(.default)]) } @@ -301,7 +306,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .pcrTestResult(.positiveResultWasShown)]) } @@ -346,7 +351,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .pcrTestResult(.positiveResultWasShown)]) } @@ -391,7 +396,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .pcrTestResult(.default)]) } @@ -434,7 +439,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .pcrTestResult(.default)]) } @@ -479,7 +484,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .antigenTestResult(.default)]) } @@ -612,7 +617,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .antigenTestResult(.positiveResultWasShown)]) } @@ -657,7 +662,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .antigenTestResult(.default)]) } @@ -702,7 +707,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .antigenTestResult(.default)]) } @@ -745,7 +750,7 @@ class HomeTableViewModelTests: CWATestCase { badgeWrapper: .fake() ) - XCTAssertEqual(viewModel.numberOfRows(in: 2), 2) + XCTAssertEqual(viewModel.numberOfRows(in: 3), 2) XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk, .antigenTestResult(.default)]) } From bab6ab2a25ddb0ac837fbde73d5cad53a3c5f39a Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 22 Feb 2023 06:51:05 +0100 Subject: [PATCH 027/137] add image identifier --- .../Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift | 3 +++ .../EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift | 5 ++--- .../ENA/Source/View Helpers/AccessibilityIdentifiers.swift | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift index 7121aa3b2f4..68e88b3eec3 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -32,9 +32,12 @@ final class EndOfLifeThankYouCell: UITableViewCell { func configure(with cellModel: EndOfLifeThankYouCellViewModel) { titleLabel.text = cellModel.title titleLabel.accessibilityIdentifier = cellModel.titleAccessibilityIdentifier + descriptionLabel.text = cellModel.description descriptionLabel.accessibilityIdentifier = cellModel.descriptionAccessibilityIdentifier + illustrationImageView.image = cellModel.image + illustrationImageView.accessibilityIdentifier = cellModel.imageAccessibilityIdentifier } // MARK: - Private diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index 7234f5bdc33..c1611e3c4f7 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -11,12 +11,11 @@ class EndOfLifeThankYouCellViewModel { var title = AppStrings.Home.EndOfLifeThankYouTile.title // to.do get the xx value in figma var description = String( - format: AppStrings.Home.EndOfLifeThankYouTile.description, - 4 - ) + format: AppStrings.Home.EndOfLifeThankYouTile.description,4) var image = UIImage(named: "EndOfLifeThankYouIllustration") var tintColor: UIColor = .enaColor(for: .textPrimary1) var titleAccessibilityIdentifier = AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.titleLabel var descriptionAccessibilityIdentifier = AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel + var imageAccessibilityIdentifier = AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.image } diff --git a/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift b/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift index 11c6292f61b..cbc4a6b8464 100644 --- a/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift +++ b/src/xcode/ENA/ENA/Source/View Helpers/AccessibilityIdentifiers.swift @@ -160,6 +160,7 @@ enum AccessibilityIdentifiers { enum EndOfLifeThankYouCell { static let titleLabel = "AppStrings.Home.EndOfLifeThankYouCell.titleLabel" static let descriptionLabel = "AppStrings.Home.EndOfLifeThankYouCell.descriptionLabel" + static let image = "AppStrings.Home.EndOfLifeThankYouCell.image" } enum TestRegistrationCell { From 95d6958d1650b48068b4ae0d011fdf7b3186890f Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 22 Feb 2023 06:51:51 +0100 Subject: [PATCH 028/137] add uitest for the new tile --- .../ENA/ENAUITests/Home/ENAUITests_01a_Home.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift b/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift index dd5aced3d09..b059422ec17 100644 --- a/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift +++ b/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift @@ -271,6 +271,16 @@ class ENAUITests_01a_Home: CWATestCase { XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.Home.AppClosureNoticeCell.Details.faqLabel].exists) } + func test_homescreen_endOfLife_ThankYoutile() throws { + app.setPreferredContentSizeCategory(accessibility: .accessibility, size: .XS) + app.setLaunchArgument(LaunchArguments.endOfLife.isHibernationStateEnabled, to: true) + app.launch() + + XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.images[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.image].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.titleLabel].waitForExistence(timeout: .medium)) + } + // MARK: - Screenshots func test_screenshot_homescreen_riskCardLow_DetailsScreen() throws { From e71cf25dba695898f7a3dcbceadd1d15761d5d1a Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 23 Feb 2023 04:57:49 +0100 Subject: [PATCH 029/137] fix failing uitest --- .../Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift | 4 +--- .../EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift index 68e88b3eec3..35b42ab04c5 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -54,9 +54,7 @@ illustrationImageView.isHidden = traitCollection.preferredContentSizeCategory >= } private func setupAccessibility() { - cardView.accessibilityElements = [titleLabel as Any, descriptionLabel as Any] - - titleLabel.accessibilityTraits = [.header, .button] + cardView.accessibilityElements = [titleLabel as Any, descriptionLabel as Any, illustrationImageView as Any] } @IBOutlet private weak var cardView: HomeCardView! diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index c1611e3c4f7..2f60c7e96c6 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -11,7 +11,7 @@ class EndOfLifeThankYouCellViewModel { var title = AppStrings.Home.EndOfLifeThankYouTile.title // to.do get the xx value in figma var description = String( - format: AppStrings.Home.EndOfLifeThankYouTile.description,4) + format: AppStrings.Home.EndOfLifeThankYouTile.description, 4) var image = UIImage(named: "EndOfLifeThankYouIllustration") var tintColor: UIColor = .enaColor(for: .textPrimary1) From f7c27c0ae49f2b72a718530151e773706ac4c119 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 23 Feb 2023 05:28:57 +0100 Subject: [PATCH 030/137] stop notification scheduling --- .../DMNotificationsViewModel.swift | 20 +++---- .../UNNotificationCenter+Extension.swift | 34 ++++++------ .../Models/Exposure/WarnOthersReminder.swift | 14 ++--- .../Events/Store/EventCheckoutService.swift | 9 ++-- .../DeadmanNotificationManager.swift | 52 ++++++++++--------- ...HealthCertificateNotificationService.swift | 20 +++---- 6 files changed, 80 insertions(+), 69 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMNotifications/DMNotificationsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMNotifications/DMNotificationsViewModel.swift index afe97c0e72d..299a6045bb5 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMNotifications/DMNotificationsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMNotifications/DMNotificationsViewModel.swift @@ -135,16 +135,18 @@ final class DMLocalNotificationsViewModel { ) return } - self?.notificationCenter.add(request) { error in - guard error == nil else { - Log.error( - "Could not schedule notification: \(private: request.identifier)", - log: .vaccination, - error: error - ) - return + if !CWAHibernationProvider.shared.isHibernationState { + self?.notificationCenter.add(request) { error in + guard error == nil else { + Log.error( + "Could not schedule notification: \(private: request.identifier)", + log: .vaccination, + error: error + ) + return + } + exit(0) } - exit(0) } } } diff --git a/src/xcode/ENA/ENA/Source/Extensions/UNNotificationCenter+Extension.swift b/src/xcode/ENA/ENA/Source/Extensions/UNNotificationCenter+Extension.swift index 8362fd66b67..1283c744d12 100644 --- a/src/xcode/ENA/ENA/Source/Extensions/UNNotificationCenter+Extension.swift +++ b/src/xcode/ENA/ENA/Source/Extensions/UNNotificationCenter+Extension.swift @@ -42,24 +42,26 @@ extension UserNotificationCenter { in timeInterval: TimeInterval = 1, info: [AnyHashable: Any] = [:] ) { - let content = UNMutableNotificationContent() + if !CWAHibernationProvider.shared.isHibernationState { + let content = UNMutableNotificationContent() - content.title = title - content.body = body - content.sound = UNNotificationSound.default - content.badge = 1 - content.categoryIdentifier = identifier - content.userInfo = info - if #available(iOS 15.0, *) { - content.interruptionLevel = .timeSensitive - } - - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false) - let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger) + content.title = title + content.body = body + content.sound = UNNotificationSound.default + content.badge = 1 + content.categoryIdentifier = identifier + content.userInfo = info + if #available(iOS 15.0, *) { + content.interruptionLevel = .timeSensitive + } + + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false) + let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger) - add(request) { error in - if let error = error { - Log.error(error.localizedDescription, log: .api) + add(request) { error in + if let error = error { + Log.error(error.localizedDescription, log: .api) + } } } } diff --git a/src/xcode/ENA/ENA/Source/Models/Exposure/WarnOthersReminder.swift b/src/xcode/ENA/ENA/Source/Models/Exposure/WarnOthersReminder.swift index f822b4f3897..c4bdf990d5e 100644 --- a/src/xcode/ENA/ENA/Source/Models/Exposure/WarnOthersReminder.swift +++ b/src/xcode/ENA/ENA/Source/Models/Exposure/WarnOthersReminder.swift @@ -41,12 +41,14 @@ class WarnOthersReminder { /// This function takes a `CoronaTestType` as parameter to schedule warn others notifications for this test type func scheduleNotifications(for coronaTestType: CoronaTestType) { - userNotificationCenter.scheduleWarnOthersNotifications( - coronaTestType: coronaTestType, - timeIntervalOne: TimeInterval(notificationOneTimeInterval), - timeIntervalTwo: TimeInterval(notificationTwoTimeInterval) - ) - Log.info("Warn others reminder: New notifications for type \(coronaTestType) have been scheduled: #1 \(store.warnOthersNotificationOneTimeInterval)/ #2 \(store.warnOthersNotificationTwoTimeInterval) seconds)") + if !CWAHibernationProvider.shared.isHibernationState { + userNotificationCenter.scheduleWarnOthersNotifications( + coronaTestType: coronaTestType, + timeIntervalOne: TimeInterval(notificationOneTimeInterval), + timeIntervalTwo: TimeInterval(notificationTwoTimeInterval) + ) + Log.info("Warn others reminder: New notifications for type \(coronaTestType) have been scheduled: #1 \(store.warnOthersNotificationOneTimeInterval)/ #2 \(store.warnOthersNotificationTwoTimeInterval) seconds)") + } } /// In case the user has informed others about the positive result, this function should be called to reset possible pending 'warn others' notifications diff --git a/src/xcode/ENA/ENA/Source/Scenes/Events/Store/EventCheckoutService.swift b/src/xcode/ENA/ENA/Source/Scenes/Events/Store/EventCheckoutService.swift index 261c03ea44b..668a09852f8 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Events/Store/EventCheckoutService.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Events/Store/EventCheckoutService.swift @@ -118,10 +118,11 @@ final class EventCheckoutService { content: content, trigger: trigger ) - - userNotificationCenter.add(request) { error in - if error != nil { - Log.error("Checkout notification could not be scheduled.") + if !CWAHibernationProvider.shared.isHibernationState { + userNotificationCenter.add(request) { error in + if error != nil { + Log.error("Checkout notification could not be scheduled.") + } } } } diff --git a/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/DeadmanNotificationManager.swift b/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/DeadmanNotificationManager.swift index 7840e1cdf76..feb8e096141 100644 --- a/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/DeadmanNotificationManager.swift +++ b/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/DeadmanNotificationManager.swift @@ -26,31 +26,33 @@ struct DeadmanNotificationManager: DeadmanNotificationManageable { /// Schedules a local notification to fire 36 hours from now, if there isn´t a notification already scheduled func scheduleDeadmanNotificationIfNeeded() { /// Check if Deadman Notification is already scheduled - userNotificationCenter.getPendingNotificationRequests { notificationRequests in - if notificationRequests.contains(where: { $0.identifier == Self.deadmanNotificationIdentifier }) { - /// Deadman Notification already setup -> return - return - } else { - /// No Deadman Notification setup, continue to setup a new one - let content = UNMutableNotificationContent() - content.title = AppStrings.Common.deadmanAlertTitle - content.body = AppStrings.Common.deadmanAlertBody - content.sound = .default - - let trigger = UNTimeIntervalNotificationTrigger( - timeInterval: 36 * 60 * 60, - repeats: false - ) - - let request = UNNotificationRequest( - identifier: Self.deadmanNotificationIdentifier, - content: content, - trigger: trigger - ) - - userNotificationCenter.add(request) { error in - if error != nil { - Log.error("Deadman notification could not be scheduled.") + if !CWAHibernationProvider.shared.isHibernationState { + userNotificationCenter.getPendingNotificationRequests { notificationRequests in + if notificationRequests.contains(where: { $0.identifier == Self.deadmanNotificationIdentifier }) { + /// Deadman Notification already setup -> return + return + } else { + /// No Deadman Notification setup, continue to setup a new one + let content = UNMutableNotificationContent() + content.title = AppStrings.Common.deadmanAlertTitle + content.body = AppStrings.Common.deadmanAlertBody + content.sound = .default + + let trigger = UNTimeIntervalNotificationTrigger( + timeInterval: 36 * 60 * 60, + repeats: false + ) + + let request = UNNotificationRequest( + identifier: Self.deadmanNotificationIdentifier, + content: content, + trigger: trigger + ) + + userNotificationCenter.add(request) { error in + if error != nil { + Log.error("Deadman notification could not be scheduled.") + } } } } diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift index 2b43dee4b5b..9fb004bb984 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift @@ -341,16 +341,18 @@ class HealthCertificateNotificationService { return } - self?.notificationCenter.add(request) { error in - if error != nil { - Log.error( - "Could not schedule notification: \(private: request.identifier)", - log: .vaccination, - error: error - ) + if !CWAHibernationProvider.shared.isHibernationState { + self?.notificationCenter.add(request) { error in + if error != nil { + Log.error( + "Could not schedule notification: \(private: request.identifier)", + log: .vaccination, + error: error + ) + } + + completion() } - - completion() } } } From c3c01aa23ce672550340fe9c003a1f6de05a648b Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 23 Feb 2023 05:29:21 +0100 Subject: [PATCH 031/137] redirect to home if notification is opened --- .../NotificationManager.swift | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/NotificationManager.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/NotificationManager.swift index 7d6a69effab..41de8b02e98 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/NotificationManager.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/NotificationManager.swift @@ -45,46 +45,52 @@ final class NotificationManager: NSObject, UNUserNotificationCenterDelegate { } func userNotificationCenter(_: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { - switch response.notification.request.identifier { - case ActionableNotificationIdentifier.riskDetection.identifier, - ActionableNotificationIdentifier.deviceTimeCheck.identifier, - DeadmanNotificationManager.deadmanNotificationIdentifier: + + if CWAHibernationProvider.shared.isHibernationState { showHome() + } else { + switch response.notification.request.identifier { + case ActionableNotificationIdentifier.riskDetection.identifier, + ActionableNotificationIdentifier.deviceTimeCheck.identifier, + DeadmanNotificationManager.deadmanNotificationIdentifier: + showHome() - case ActionableNotificationIdentifier.pcrWarnOthersReminder1.identifier, - ActionableNotificationIdentifier.pcrWarnOthersReminder2.identifier: - showPositivePCRTestResultIfNeeded() + case ActionableNotificationIdentifier.pcrWarnOthersReminder1.identifier, + ActionableNotificationIdentifier.pcrWarnOthersReminder2.identifier: + showPositivePCRTestResultIfNeeded() - case ActionableNotificationIdentifier.antigenWarnOthersReminder1.identifier, - ActionableNotificationIdentifier.antigenWarnOthersReminder2.identifier: - showPositiveAntigenTestResultIfNeeded() + case ActionableNotificationIdentifier.antigenWarnOthersReminder1.identifier, + ActionableNotificationIdentifier.antigenWarnOthersReminder2.identifier: + showPositiveAntigenTestResultIfNeeded() - case ActionableNotificationIdentifier.testResult.identifier: - let testIdentifier = ActionableNotificationIdentifier.testResult.identifier - let testTypeIdentifier = ActionableNotificationIdentifier.testResultType.identifier + case ActionableNotificationIdentifier.testResult.identifier: + let testIdentifier = ActionableNotificationIdentifier.testResult.identifier + let testTypeIdentifier = ActionableNotificationIdentifier.testResultType.identifier - guard let testResultRawValue = response.notification.request.content.userInfo[testIdentifier] as? Int, - let testResult = TestResult(rawValue: testResultRawValue), - let testResultTypeRawValue = response.notification.request.content.userInfo[testTypeIdentifier] as? Int, - let testResultType = CoronaTestType(rawValue: testResultTypeRawValue) else { - showHome() - return - } + guard let testResultRawValue = response.notification.request.content.userInfo[testIdentifier] as? Int, + let testResult = TestResult(rawValue: testResultRawValue), + let testResultTypeRawValue = response.notification.request.content.userInfo[testTypeIdentifier] as? Int, + let testResultType = CoronaTestType(rawValue: testResultTypeRawValue) else { + showHome() + return + } - switch testResult { - case .positive, .negative: - showTestResultFromNotification(.testResultFromNotification(testResultType)) - case .invalid: - showHome() - case .expired, .pending: - assertionFailure("Expired and Pending Test Results should not trigger the Local Notification") + switch testResult { + case .positive, .negative: + showTestResultFromNotification(.testResultFromNotification(testResultType)) + case .invalid: + showHome() + case .expired, .pending: + assertionFailure("Expired and Pending Test Results should not trigger the Local Notification") + } + case ActionableNotificationIdentifier.familyTestResult.identifier: + showFamilyMemberTests(.familyMemberTestResultFromNotification) + default: + // special action where we need to extract data from identifier + checkForLocalNotificationsActions(response.notification.request.identifier) } - case ActionableNotificationIdentifier.familyTestResult.identifier: - showFamilyMemberTests(.familyMemberTestResultFromNotification) - default: - // special action where we need to extract data from identifier - checkForLocalNotificationsActions(response.notification.request.identifier) } + completionHandler() } From c79319338cd396ff081bf1e8197be08d7149f761 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Thu, 23 Feb 2023 14:28:06 +0100 Subject: [PATCH 032/137] 14819: Prevent background tasks with BGTaskScheduler, if Hibernation is on. --- .../ENA/Source/AppDelegate & Globals/AppDelegate.swift | 2 +- .../ENATaskExecutionDelegate.swift | 6 ++++++ .../ENA/Source/Models/Exposure/ExposureManager.swift | 8 +++++++- .../Models/Task Scheduling/ENATaskScheduler.swift | 10 ++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift index 749d5b81f24..58e6ed16847 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift @@ -284,7 +284,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re let client: HTTPClient let cachingClient = CachingHTTPClient() let downloadedPackagesStore: DownloadedPackagesStore = DownloadedPackagesSQLLiteStore(fileName: "packages") - let taskScheduler: ENATaskScheduler = ENATaskScheduler.shared + lazy var taskScheduler: ENATaskScheduler = { ENATaskScheduler.shared }() let contactDiaryStore: DiaryStoringProviding let eventStore: EventStoringProviding = { #if DEBUG diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift index 09063d80cf9..6271a9351f6 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift @@ -65,6 +65,12 @@ class TaskExecutionHandler: ENATaskExecutionDelegate { return } + guard !CWAHibernationProvider.shared.isHibernationState else { + Log.info("CWA is in hibernation state. Background tasks won't be executed.", log: .background) + completion(true) + return + } + let group = DispatchGroup() group.enter() diff --git a/src/xcode/ENA/ENA/Source/Models/Exposure/ExposureManager.swift b/src/xcode/ENA/ENA/Source/Models/Exposure/ExposureManager.swift index 9a3d831a7aa..6e370337c2d 100644 --- a/src/xcode/ENA/ENA/Source/Models/Exposure/ExposureManager.swift +++ b/src/xcode/ENA/ENA/Source/Models/Exposure/ExposureManager.swift @@ -186,7 +186,13 @@ final class ENAExposureManager: NSObject, ExposureManager { Log.error("AppDelegate is not of Type AppDelegate, this should not happen!", log: .background) return } - Log.info("Starting backgroundTask via Bluetooth", log: .background) + + guard !CWAHibernationProvider.shared.isHibernationState else { + Log.info("CWA is in hibernation state. Background tasks won't be executed in this state.", log: .background) + return + } + + Log.info("Starting background task via Bluetooth", log: .background) appDelegate.taskExecutionDelegate.executeENABackgroundTask(completion: { success in Log.info("Background task was: \(success)", log: .background) }) diff --git a/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift b/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift index a01888765ac..ca6dfdf23ca 100644 --- a/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift +++ b/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift @@ -48,6 +48,12 @@ final class ENATaskScheduler { // MARK: - Task registration. @available(iOS 13.0, *) private func registerTask(with taskIdentifier: ENATaskIdentifier, execute: @escaping ((BGTask) -> Void)) { + guard !CWAHibernationProvider.shared.isHibernationState else { + Log.info("CWA is in hibernation state. The background task with identifier \(taskIdentifier) won't be registered.", log: .api) + return + } + + BGTaskScheduler.shared. let identifierString = taskIdentifier.backgroundTaskSchedulerIdentifier BGTaskScheduler.shared.register(forTaskWithIdentifier: identifierString, using: .main) { task in self.scheduleTask() @@ -71,6 +77,10 @@ final class ENATaskScheduler { @available(iOS 13.0, *) func scheduleTask() { do { + guard !CWAHibernationProvider.shared.isHibernationState else { + Log.info("CWA is in hibernation state, \(#function) won't submit task request.", log: .api) + return + } let taskRequest = BGProcessingTaskRequest(identifier: ENATaskIdentifier.exposureNotification.backgroundTaskSchedulerIdentifier) taskRequest.requiresNetworkConnectivity = true taskRequest.requiresExternalPower = false From 224708450d22dd2f16dfa55ce25a2fea43a7f282 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Thu, 23 Feb 2023 14:28:50 +0100 Subject: [PATCH 033/137] 14819: Remove one line. --- .../ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift b/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift index ca6dfdf23ca..51b8818a436 100644 --- a/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift +++ b/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift @@ -53,7 +53,6 @@ final class ENATaskScheduler { return } - BGTaskScheduler.shared. let identifierString = taskIdentifier.backgroundTaskSchedulerIdentifier BGTaskScheduler.shared.register(forTaskWithIdentifier: identifierString, using: .main) { task in self.scheduleTask() From f724f4071b374dedab9fede216fd97cd55e5d836 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Mon, 27 Feb 2023 04:44:58 +0100 Subject: [PATCH 034/137] increase timeout for tests --- .../__tests__/CoronaTestServiceTests.swift | 8 ++++---- .../__tests__/FamilyMemberCoronaTestServiceTests.swift | 4 ++-- .../__tests__/ExposureSubmissionServiceTests.swift | 4 ++-- .../Risk/Provider/__tests__/RiskProviderTests.swift | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/__tests__/CoronaTestServiceTests.swift b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/__tests__/CoronaTestServiceTests.swift index fa35831e303..1a370ccf052 100644 --- a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/__tests__/CoronaTestServiceTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/__tests__/CoronaTestServiceTests.swift @@ -2837,7 +2837,7 @@ class CoronaTestServiceTests: CWATestCase { testService.updateTestResults(presentNotification: true) { _ in completionExpectation.fulfill() } - waitForExpectations(timeout: .short) + waitForExpectations(timeout: .extraLong) XCTAssertEqual(mockNotificationCenter.notificationRequests.count, 2) } @@ -2945,7 +2945,7 @@ class CoronaTestServiceTests: CWATestCase { } completionExpectation.fulfill() } - waitForExpectations(timeout: .short) + waitForExpectations(timeout: .extraLong) } func test_When_UpdateTestResultsSuccessWithPending_Then_NoNotificationIsShown() { @@ -3025,7 +3025,7 @@ class CoronaTestServiceTests: CWATestCase { testService.updateTestResults(presentNotification: true) { _ in completionExpectation.fulfill() } - waitForExpectations(timeout: .short) + waitForExpectations(timeout: .extraLong) testService.createCoronaTestEntryInContactDiary(coronaTestType: .pcr) testService.createCoronaTestEntryInContactDiary(coronaTestType: .antigen) @@ -3170,7 +3170,7 @@ class CoronaTestServiceTests: CWATestCase { testService.updateTestResults(presentNotification: true) { _ in completionExpectation.fulfill() } - waitForExpectations(timeout: .short) + waitForExpectations(timeout: .extraLong) XCTAssertEqual(diaryStore.coronaTests.count, 0) XCTAssertFalse(try XCTUnwrap(testService.antigenTest.value?.journalEntryCreated)) diff --git a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/__tests__/FamilyMemberCoronaTestServiceTests.swift b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/__tests__/FamilyMemberCoronaTestServiceTests.swift index 4f60585fa77..20e4bc4b20f 100644 --- a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/__tests__/FamilyMemberCoronaTestServiceTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/__tests__/FamilyMemberCoronaTestServiceTests.swift @@ -2566,7 +2566,7 @@ class FamilyMemberCoronaTestServiceTests: CWATestCase { service.updateTestResults(presentNotification: true) { _ in completionExpectation.fulfill() } - waitForExpectations(timeout: .short) + waitForExpectations(timeout: .extraLong) XCTAssertEqual(mockNotificationCenter.notificationRequests.count, 2) } @@ -2678,7 +2678,7 @@ class FamilyMemberCoronaTestServiceTests: CWATestCase { } completionExpectation.fulfill() } - waitForExpectations(timeout: .short) + waitForExpectations(timeout: .extraLong) } func test_When_UpdateTestResultsSuccessWithPending_Then_NoNotificationIsShown() { diff --git a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/ExposureSubmissionServiceTests.swift b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/ExposureSubmissionServiceTests.swift index f759e7c61e0..785465853f2 100644 --- a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/ExposureSubmissionServiceTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/ExposureSubmissionServiceTests.swift @@ -129,7 +129,7 @@ class ExposureSubmissionServiceTests: CWATestCase { completionExpectation.fulfill() } - waitForExpectations(timeout: .short) + waitForExpectations(timeout: .extraLong) } func testSubmitExposure_NoSubmissionConsent() { @@ -854,7 +854,7 @@ class ExposureSubmissionServiceTests: CWATestCase { } } - waitForExpectations(timeout: .short) + waitForExpectations(timeout: .extraLong) } } diff --git a/src/xcode/ENA/ENA/Source/Services/Risk/Provider/__tests__/RiskProviderTests.swift b/src/xcode/ENA/ENA/Source/Services/Risk/Provider/__tests__/RiskProviderTests.swift index 4b8292d5ddb..c02fd6a6121 100644 --- a/src/xcode/ENA/ENA/Source/Services/Risk/Provider/__tests__/RiskProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/Risk/Provider/__tests__/RiskProviderTests.swift @@ -618,7 +618,7 @@ class RiskProviderTests: CWATestCase { didCalculateRiskExpectation.fulfill() } - waitForExpectations(timeout: .long) + waitForExpectations(timeout: .extraLong) XCTAssertTrue(store.shouldShowRiskStatusLoweredAlert) } @@ -660,7 +660,7 @@ class RiskProviderTests: CWATestCase { didCalculateRiskExpectation.fulfill() } - waitForExpectations(timeout: .long) + waitForExpectations(timeout: .extraLong) XCTAssertFalse(store.shouldShowRiskStatusLoweredAlert) } From 7af1e69ef22705826f5596d03c175c562de9891d Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Mon, 27 Feb 2023 04:45:46 +0100 Subject: [PATCH 035/137] call completion --- .../HealthCertificateNotificationService.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift index 9fb004bb984..198c419ea6b 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift @@ -350,9 +350,10 @@ class HealthCertificateNotificationService { error: error ) } - completion() } + } else { + completion() } } } From df2573b5ee125ee59279ff9d3fa3fe19bdc2b902 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 27 Feb 2023 10:56:25 +0100 Subject: [PATCH 036/137] changes to app info vc --- .../AppInformationViewController.swift | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift index 3fb99d1a7f1..c66dbd08e2a 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift @@ -47,25 +47,27 @@ class AppInformationViewController: DynamicTableViewController, NavigationBarOpa text: AppStrings.AppInformation.legalNavigation, accessibilityIdentifier: AccessibilityIdentifiers.AppInformation.legalNavigation, action: .push(model: AppInformationViewController.legalModel, separators: true, withTitle: AppStrings.AppInformation.legalNavigation) - ), - .contact: AppInformationCellModel( - text: AppStrings.AppInformation.contactNavigation, - accessibilityIdentifier: AccessibilityIdentifiers.AppInformation.contactNavigation, - action: .push(model: AppInformationModel.contactModel, withTitle: AppStrings.AppInformation.contactNavigation) - ), - .errorReport: AppInformationCellModel( + )] + + if !CWAHibernationProvider.shared.isHibernationState { + self.model[.contact] = AppInformationCellModel( + text: AppStrings.AppInformation.contactNavigation, + accessibilityIdentifier: AccessibilityIdentifiers.AppInformation.contactNavigation, + action: .push(model: AppInformationModel.contactModel, withTitle: AppStrings.AppInformation.contactNavigation) + ) + + self.model[.errorReport] = AppInformationCellModel( text: AppStrings.ErrorReport.title, accessibilityIdentifier: AccessibilityIdentifiers.ErrorReport.navigation, - action: .pushErrorLogsCoordinator( - elsService: elsService - ) - ), - .imprint: AppInformationCellModel( - text: AppStrings.AppInformation.imprintNavigation, - accessibilityIdentifier: AccessibilityIdentifiers.AppInformation.imprintNavigation, - action: .push(model: imprintViewModel.dynamicTable, withTitle: AppStrings.AppInformation.imprintNavigation) + action: .pushErrorLogsCoordinator(elsService: elsService) ) - ] + } + + self.model[.imprint] = AppInformationCellModel( + text: AppStrings.AppInformation.imprintNavigation, + accessibilityIdentifier: AccessibilityIdentifiers.AppInformation.imprintNavigation, + action: .push(model: imprintViewModel.dynamicTable, withTitle: AppStrings.AppInformation.imprintNavigation) + ) super.init(nibName: nil, bundle: nil) } From 14633102d793b6e495e70ae26f824a03d6242e70 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 27 Feb 2023 10:56:55 +0100 Subject: [PATCH 037/137] changes to home table vm and vc --- .../Scenes/Home/HomeTableViewController.swift | 22 +++++++++++++------ .../Scenes/Home/HomeTableViewModel.swift | 8 +++---- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index a86a536ff52..5853b64f910 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -112,7 +112,13 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega self?.tableView.reloadSections( [ HomeTableViewModel.Section.appClosureNotice.rawValue, - HomeTableViewModel.Section.endOfLifeThankYou.rawValue + HomeTableViewModel.Section.endOfLifeThankYou.rawValue, + HomeTableViewModel.Section.exposureLogging.rawValue, + HomeTableViewModel.Section.riskAndTestResults.rawValue, + HomeTableViewModel.Section.statistics.rawValue, + HomeTableViewModel.Section.testRegistration.rawValue, + HomeTableViewModel.Section.traceLocations.rawValue, + HomeTableViewModel.Section.moreInfo.rawValue ], with: .none ) @@ -376,12 +382,14 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega navigationItem.leftBarButtonItem?.accessibilityLabel = AppStrings.Home.leftBarButtonDescription navigationItem.leftBarButtonItem?.accessibilityIdentifier = AccessibilityIdentifiers.Home.leftBarButtonDescription - let infoButton = UIButton(type: .infoLight) - infoButton.addTarget(self, action: #selector(infoButtonTapped), for: .touchUpInside) - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: infoButton) - navigationItem.rightBarButtonItem?.isAccessibilityElement = true - navigationItem.rightBarButtonItem?.accessibilityLabel = AppStrings.Home.rightBarButtonDescription - navigationItem.rightBarButtonItem?.accessibilityIdentifier = AccessibilityIdentifiers.Home.rightBarButtonDescription + if !CWAHibernationProvider.shared.isHibernationState { + let infoButton = UIButton(type: .infoLight) + infoButton.addTarget(self, action: #selector(infoButtonTapped), for: .touchUpInside) + navigationItem.rightBarButtonItem = UIBarButtonItem(customView: infoButton) + navigationItem.rightBarButtonItem?.isAccessibilityElement = true + navigationItem.rightBarButtonItem?.accessibilityLabel = AppStrings.Home.rightBarButtonDescription + navigationItem.rightBarButtonItem?.accessibilityIdentifier = AccessibilityIdentifiers.Home.rightBarButtonDescription + } } private func setupTableView() { diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift index d8449cc6233..00b23de0bbf 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift @@ -131,15 +131,15 @@ class HomeTableViewModel { #endif return shouldShowAppClosureNotice ? 1 : 0 case .exposureLogging: - return 1 + return !isHibernationState ? 1 : 0 case .riskAndTestResults: - return riskAndTestResultsRows.count + return !isHibernationState ? riskAndTestResultsRows.count : 0 case .testRegistration: - return 1 + return !isHibernationState ? 1 : 0 case .statistics: return 1 case .traceLocations: - return 1 + return !isHibernationState ? 1 : 0 case .moreInfo: return 1 case .none: From 91535605c006303f7a52453ebaa28214e3da339a Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 27 Feb 2023 10:57:18 +0100 Subject: [PATCH 038/137] changes to home more info table view cell --- .../More/HomeMoreInfoTableViewCell.swift | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift index 0aa2f03ac3a..c13427b28b5 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift @@ -13,20 +13,25 @@ class HomeMoreInfoTableViewCell: UITableViewCell { accessibilityIdentifier = AccessibilityIdentifiers.Home.MoreInfoCell.moreCell isAccessibilityElement = false - - } // MARK: - Internal func configure(onItemTap: @escaping ((MoreInfoItem) -> Void)) { - guard !isCellConfigured else { - return - } - titleLabel.text = AppStrings.Home.MoreInfoCard.title - for item in MoreInfoItem.allCases { + var items: [MoreInfoItem] = [] + stackView.removeAllArrangedSubviews() + + if CWAHibernationProvider.shared.isHibernationState { + items = MoreInfoItem.allCases.filter({ + $0 != .settings && $0 != .share + }) + } else { + items = MoreInfoItem.allCases + } + + for item in items { let nibName = String(describing: MoreActionItemView.self) let nib = UINib(nibName: nibName, bundle: .main) @@ -39,8 +44,6 @@ class HomeMoreInfoTableViewCell: UITableViewCell { } accessibilityElements = [titleLabel as Any] + stackView.arrangedSubviews - - isCellConfigured = true } // MARK: - Private From 8e65c0a17158e6a34fcb4256da3b8728d2a922a2 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 27 Feb 2023 10:57:40 +0100 Subject: [PATCH 039/137] changes to home statistics cell model --- .../Home/Cells/Statistics/HomeStatisticsCellModel.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsCellModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsCellModel.swift index ce8d1c1a612..15a44cf33ec 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsCellModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsCellModel.swift @@ -15,7 +15,7 @@ class HomeStatisticsCellModel { ) { self.homeState = homeState self.localStatisticsProvider = localStatisticsProvider - + homeState.$statistics .sink { [weak self] statistics in self?.keyFigureCards = statistics.supportedStatisticsCardIDSequence @@ -74,7 +74,7 @@ class HomeStatisticsCellModel { private let homeState: HomeState private let localStatisticsProvider: LocalStatisticsProviding - + private var subscriptions = Set() #if DEBUG From 1f198b258e9b1100fe011afa1f0a67b3f07a4c93 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 27 Feb 2023 10:58:10 +0100 Subject: [PATCH 040/137] changes to home statistics table view cell --- .../HomeStatisticsTableViewCell.swift | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift index fbf0a9d690a..4dc52e702b8 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift @@ -150,31 +150,39 @@ class HomeStatisticsTableViewCell: UITableViewCell { onDeviceOfflineInfo: @escaping CompletionVoid ) { clearStackView() - - configureManageLocalStatisticsCell( - store: store, - onAddLocalStatisticsButtonTap: onAddLocalStatisticsButtonTap, - onAddDistrict: onAddDistrict, - onDismissState: onDismissState, - onDismissDistrict: onDismissDistrict, - onAccessibilityFocus: onAccessibilityFocus, - onDeviceOfflineInfo: onDeviceOfflineInfo - ) - configurePandemicRadarCard( - onInfoButtonTap: onInfoButtonTap, - onAccessibilityFocus: {}, - onUpdate: {} - ) - configureLocalStatisticsCards( - onInfoButtonTap: onInfoButtonTap, - onAccessibilityFocus: onAccessibilityFocus, - onUpdate: onUpdate - ) - configureKeyFigureCards( - for: keyFigureCellModel.keyFigureCards, - onInfoButtonTap: onInfoButtonTap, - onAccessibilityFocus: onAccessibilityFocus - ) + + if CWAHibernationProvider.shared.isHibernationState { + configurePandemicRadarCard( + onInfoButtonTap: onInfoButtonTap, + onAccessibilityFocus: {}, + onUpdate: {} + ) + } else { + configureManageLocalStatisticsCell( + store: store, + onAddLocalStatisticsButtonTap: onAddLocalStatisticsButtonTap, + onAddDistrict: onAddDistrict, + onDismissState: onDismissState, + onDismissDistrict: onDismissDistrict, + onAccessibilityFocus: onAccessibilityFocus, + onDeviceOfflineInfo: onDeviceOfflineInfo + ) + configurePandemicRadarCard( + onInfoButtonTap: onInfoButtonTap, + onAccessibilityFocus: {}, + onUpdate: {} + ) + configureLocalStatisticsCards( + onInfoButtonTap: onInfoButtonTap, + onAccessibilityFocus: onAccessibilityFocus, + onUpdate: onUpdate + ) + configureKeyFigureCards( + for: keyFigureCellModel.keyFigureCards, + onInfoButtonTap: onInfoButtonTap, + onAccessibilityFocus: onAccessibilityFocus + ) + } onUpdate() } @@ -263,8 +271,7 @@ class HomeStatisticsTableViewCell: UITableViewCell { let nib = UINib(nibName: nibName, bundle: .main) guard - let linkCardView = nib.instantiate(withOwner: self, options: nil).first as? HomeLinkCardView, - !stackView.arrangedSubviews.isEmpty + let linkCardView = nib.instantiate(withOwner: self, options: nil).first as? HomeLinkCardView else { return } stackView.addArrangedSubview(linkCardView) @@ -274,6 +281,7 @@ class HomeStatisticsTableViewCell: UITableViewCell { linkCardView.configure( viewModel: HomeLinkCardViewModel(for: pandemicLinkCard), + isInfoButtonHidden: CWAHibernationProvider.shared.isHibernationState, onInfoButtonTap: { onInfoButtonTap() }, From 117240e582718e1206407bb58433f740615128ad Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 27 Feb 2023 10:58:31 +0100 Subject: [PATCH 041/137] changes to home link card view --- .../Cells/Statistics/HomeLinkCardView/HomeLinkCardView.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeLinkCardView/HomeLinkCardView.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeLinkCardView/HomeLinkCardView.swift index 495784e70b4..8403c084bd8 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeLinkCardView/HomeLinkCardView.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeLinkCardView/HomeLinkCardView.swift @@ -57,6 +57,7 @@ class HomeLinkCardView: UIView { func configure( viewModel: HomeLinkCardViewModel, + isInfoButtonHidden: Bool, onInfoButtonTap: @escaping CompletionVoid, onDeleteButtonTap: CompletionVoid?, onButtonTap: @escaping CompletionURL @@ -102,6 +103,8 @@ class HomeLinkCardView: UIView { self.onDeleteButtonTap = onDeleteButtonTap self.onButtonTap = onButtonTap + self.infoButton.isHidden = isInfoButtonHidden + setupAccessibility() } From d66793fa9f2113e4d6c4a0e8cfaa45bf692464a2 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 27 Feb 2023 11:03:15 +0100 Subject: [PATCH 042/137] fix indentation --- .../Scenes/AppInformation/AppInformationViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift index c66dbd08e2a..ebcca352731 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift @@ -54,7 +54,7 @@ class AppInformationViewController: DynamicTableViewController, NavigationBarOpa text: AppStrings.AppInformation.contactNavigation, accessibilityIdentifier: AccessibilityIdentifiers.AppInformation.contactNavigation, action: .push(model: AppInformationModel.contactModel, withTitle: AppStrings.AppInformation.contactNavigation) - ) + ) self.model[.errorReport] = AppInformationCellModel( text: AppStrings.ErrorReport.title, From 3c53ff8875d2fc8fd91bddb26c8a0d0b2799eba7 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 27 Feb 2023 13:46:52 +0100 Subject: [PATCH 043/137] 14814: Hibernation Width. --- .../Statistics/HomeStatisticsTableViewCell.swift | 5 +++++ .../Cells/Statistics/HomeStatisticsTableViewCell.xib | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift index 4dc52e702b8..15b39d44884 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift @@ -387,6 +387,11 @@ class HomeStatisticsTableViewCell: UITableViewCell { } } + guard !CWAHibernationProvider.shared.isHibernationState else { + trailingConstraint.constant = 12 + return + } + if UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.bounds.size.width <= 320 { trailingConstraint.constant = 12 } else { diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.xib b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.xib index ad005f8af18..0f116f96ce5 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.xib +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.xib @@ -1,9 +1,9 @@ - + - + @@ -18,13 +18,13 @@ - + - + - + @@ -51,7 +51,7 @@ - + From a1ad0429b468074decf1887d31d6bb2d6b3ddf25 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 27 Feb 2023 16:44:08 +0100 Subject: [PATCH 044/137] 14814: Fix top right corner visibility of LinkCardView --- .../Cells/Statistics/HomeLinkCardView/HomeLinkCardView.xib | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeLinkCardView/HomeLinkCardView.xib b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeLinkCardView/HomeLinkCardView.xib index f84e7d92792..1fe98c70d87 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeLinkCardView/HomeLinkCardView.xib +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeLinkCardView/HomeLinkCardView.xib @@ -1,9 +1,9 @@ - + - + @@ -30,7 +30,7 @@ - + From 5d9e9f308bcfb9d0cf29044d884cbf34a35bcf97 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Mon, 27 Feb 2023 16:46:31 +0100 Subject: [PATCH 045/137] fixing the constraint position --- .../Cells/Statistics/HomeStatisticsTableViewCell.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift index 15b39d44884..319b11e8a71 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/Statistics/HomeStatisticsTableViewCell.swift @@ -293,6 +293,11 @@ class HomeStatisticsTableViewCell: UITableViewCell { linkCardView.accessibilityIdentifier = AccessibilityIdentifiers.LinkCard.PandemicRadar.card + guard !CWAHibernationProvider.shared.isHibernationState else { + trailingConstraint.constant = 12 + return + } + // Pandemic Radar shouldn't be removable linkCardView.set(editMode: false, animated: false) } @@ -387,11 +392,6 @@ class HomeStatisticsTableViewCell: UITableViewCell { } } - guard !CWAHibernationProvider.shared.isHibernationState else { - trailingConstraint.constant = 12 - return - } - if UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.bounds.size.width <= 320 { trailingConstraint.constant = 12 } else { From 4f784177854fc13cf7d00a89a49c258461eb1f01 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 27 Feb 2023 19:02:03 +0100 Subject: [PATCH 046/137] 14427: Prevent submit PPA data, when app is in hibernation state. --- .../CWAHibernationProvider.swift | 2 +- .../Model/PPASError.swift | 1 + .../PPAnalyticsSubmitter.swift | 13 ++++- .../__tests__/PPAnalyticsSubmitterTests.swift | 51 +++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index afc3b9ac983..5126c713783 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -32,7 +32,7 @@ class CWAHibernationProvider: RequiresAppDependencies { } /// CWA hibernation threshold date. - private let hibernationStartDate: Date = { + let hibernationStartDate: Date = { var hibernationStartDateComponents = DateComponents() hibernationStartDateComponents.year = 2023 hibernationStartDateComponents.month = 6 diff --git a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/Model/PPASError.swift b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/Model/PPASError.swift index 82813440418..7f5fa305305 100644 --- a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/Model/PPASError.swift +++ b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/Model/PPASError.swift @@ -19,6 +19,7 @@ enum PPASError: Error { case submissionTimeAmountUndercutError case probibilityError case userConsentError + case hibernationError case restServiceError(ServiceError) } diff --git a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift index d2d2ab8f99a..bf0f3af49be 100644 --- a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift +++ b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift @@ -38,7 +38,8 @@ final class PPAnalyticsSubmitter: PPAnalyticsSubmitting { restServiceProvider: RestServiceProviding, appConfig: AppConfigurationProviding, coronaTestService: CoronaTestServiceProviding, - ppacService: PrivacyPreservingAccessControl + ppacService: PrivacyPreservingAccessControl, + cwaHibernationProvider: CWAHibernationProvider = CWAHibernationProvider.shared ) { guard let store = store as? (Store & PPAnalyticsData) else { Log.error("I will never submit any analytics data. Could not cast to correct store protocol", log: .ppa) @@ -50,6 +51,7 @@ final class PPAnalyticsSubmitter: PPAnalyticsSubmitting { self.configurationProvider = appConfig self.coronaTestService = coronaTestService self.ppacService = ppacService + self.cwaHibernationProvider = cwaHibernationProvider self.fakeRequestService = FakeRequestService(restServiceProvider: restServiceProvider, ppacService: ppacService, appConfiguration: appConfig) } @@ -128,6 +130,14 @@ final class PPAnalyticsSubmitter: PPAnalyticsSubmitting { completion?(.failure(.appResetError)) return } + + // Hibernation check + if strongSelf.cwaHibernationProvider.isHibernationState { + Log.warning("Analytics submission \(strongSelf.applicationState) abort due to app is in hibernation state.", log: .ppa) + strongSelf.submissionState = .readyForSubmission + completion?(.failure(.hibernationError)) + return + } if let token = ppacToken { Log.info("Analytics submission \(strongSelf.applicationState)) has an injected ppac token.", log: .ppa) @@ -179,6 +189,7 @@ final class PPAnalyticsSubmitter: PPAnalyticsSubmitting { private let coronaTestService: CoronaTestServiceProviding private let ppacService: PrivacyPreservingAccessControl private let fakeRequestService: FakeRequestService + private let cwaHibernationProvider: CWAHibernationProvider private var submissionState: PPASubmissionState private var subscriptions: Set = [] diff --git a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift index 16a776e3fc5..640f10dcdb2 100644 --- a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift @@ -538,6 +538,57 @@ class PPAnalyticsSubmitterTests: CWATestCase { XCTAssertEqual(ppasError, .appResetError) } + func testGIVEN_SubmissionIsTriggered_WHEN_Hibernation_THEN_HibernationErrorIsReturned() { + // GIVEN + let store = MockTestStore() + store.isPrivacyPreservingAnalyticsConsentGiven = true + store.lastSubmissionAnalytics = Calendar.current.date(byAdding: .day, value: -5, to: Date()) + store.dateOfAcceptedPrivacyNotice = Calendar.current.date(byAdding: .day, value: -5, to: Date()) + + var config = SAP_Internal_V2_ApplicationConfigurationIOS() + config.privacyPreservingAnalyticsParameters.common.probabilityToSubmit = 3 + + let appConfigurationProvider = CachedAppConfigurationMock(with: config) + + #if targetEnvironment(simulator) + let deviceCheck = PPACDeviceCheckMock(true, deviceToken: "iPhone") + #else + let deviceCheck = PPACDeviceCheck() + #endif + + let loadResource = LoadResource(result: .success(()), willLoadResource: nil) + + let cwaHibernationProvider = CWAHibernationProvider(customStore: store) + store.hibernationComparisonDate = cwaHibernationProvider.hibernationStartDate + + let sut = PPAnalyticsSubmitter( + store: store, + restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), + appConfig: appConfigurationProvider, + coronaTestService: MockCoronaTestService(), + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: cwaHibernationProvider + ) + + let expectation = self.expectation(description: "completion handler is called with an error") + + // WHEN + var ppasError: PPASError? + sut.triggerSubmitData(ppacToken: nil, completion: { result in + switch result { + case .success: + XCTFail("Test should not success") + case let .failure(error): + ppasError = error + expectation.fulfill() + } + }) + + // THEN + waitForExpectations(timeout: .medium) + XCTAssertEqual(ppasError, .hibernationError) + } + func testGIVEN_SubmissionIsTriggered_WHEN_PpacCouldNotAuthorize_THEN_PpacErrorIsReturned() { // GIVEN let store = MockTestStore() From 8d3a78a1810bd938e5966ec344e33fef6c25ccb7 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 28 Feb 2023 13:08:05 +0100 Subject: [PATCH 047/137] 14820: Check hibernation state as first condition when try to submit PPA data. --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 9 ++- .../MockCWAHibernationProvider.swift | 28 ++++++++ .../PPAnalyticsSubmitter.swift | 16 ++--- .../__tests__/PPAnalyticsSubmitterTests.swift | 69 ++++++++++++------- 4 files changed, 85 insertions(+), 37 deletions(-) create mode 100644 src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/MockCWAHibernationProvider.swift diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index 996875269e8..8259ee5c5ba 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 0104CBCF273EAC5B009A543D /* TicketValidationResultToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0104CBCE273EAC5B009A543D /* TicketValidationResultToken.swift */; }; 0104CBD1273EAC7A009A543D /* TicketValidationResultToken+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0104CBD0273EAC7A009A543D /* TicketValidationResultToken+Fake.swift */; }; 0104CBD3273EACA1009A543D /* MockTicketValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0104CBD2273EACA1009A543D /* MockTicketValidation.swift */; }; - 0104CBD5273EAD72009A543D /* TicketValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0104CBD4273EAD72009A543D /* TicketValidation.swift */; }; 0104CBD5273EAD72009A543D /* TicketValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0104CBD4273EAD72009A543D /* TicketValidation.swift */; }; 0105D8AA25B87920007E288B /* SAP_Internal_Stats_KeyFigure+Formatting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105D8A925B87920007E288B /* SAP_Internal_Stats_KeyFigure+Formatting.swift */; }; 0109DB8726036E4400624BB3 /* CheckinsOverviewViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0109DB762603682C00624BB3 /* CheckinsOverviewViewModelTest.swift */; }; @@ -1759,9 +1758,9 @@ DC7003092858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7003082858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift */; }; DC8795AC2923ED8D00F478D5 /* UIViewController+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */; }; DC8BC2BF2953266B003C8CB1 /* InternetConnectivityMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */; }; + DC9390A2299F931A00C2F8F4 /* CWAHibernationProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */; }; DC9390A5299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A4299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift */; }; DC9390A7299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A6299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift */; }; - DC9390A2299F931A00C2F8F4 /* CWAHibernationProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */; }; DC9390A9299FC0F300C2F8F4 /* CWAHibernationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A8299FC0F300C2F8F4 /* CWAHibernationProvider.swift */; }; DC95881428BCF9FE00F4D03E /* MaskStateTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */; }; DC95881628BE3D5500F4D03E /* MaskStateCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */; }; @@ -1769,6 +1768,7 @@ DC9AB2392908174000A2F9D1 /* String+Attributed.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9AB2382908174000A2F9D1 /* String+Attributed.swift */; }; DCB2897D2948CB51000A3841 /* PPACServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB2897C2948CB51000A3841 /* PPACServiceMock.swift */; }; DCB78C47294B2FBC00EAE2AB /* MockRiskProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBD2D09F25A86C2A006E4220 /* MockRiskProvider.swift */; }; + DCBA940329AE21D100905B50 /* MockCWAHibernationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCBA940229AE21D100905B50 /* MockCWAHibernationProvider.swift */; }; DCD345B8291BF7B700E95A2D /* UIView+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCD345B7291BF7B700E95A2D /* UIView+Utils.swift */; }; DCDE5FD8292A9DE800F3E733 /* SRSErrorAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDE5FD7292A9DE800F3E733 /* SRSErrorAlert.swift */; }; DCDE5FDA292CFABC00F3E733 /* SRSPreconditionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDE5FD9292CFABC00F3E733 /* SRSPreconditionError.swift */; }; @@ -3662,15 +3662,16 @@ DC7003082858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogSubmissionProvidingMock.swift; sourceTree = ""; }; DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Helpers.swift"; sourceTree = ""; }; DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetConnectivityMonitor.swift; sourceTree = ""; }; + DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CWAHibernationProviderTests.swift; sourceTree = ""; }; DC9390A4299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMHibernationOptionsViewController.swift; sourceTree = ""; }; DC9390A6299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMHibernationOptionsViewModel.swift; sourceTree = ""; }; - DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CWAHibernationProviderTests.swift; sourceTree = ""; }; DC9390A8299FC0F300C2F8F4 /* CWAHibernationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CWAHibernationProvider.swift; sourceTree = ""; }; DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateTableViewCell.swift; sourceTree = ""; }; DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModel.swift; sourceTree = ""; }; DC95881728BE5E2800F4D03E /* MaskStateCellModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModelTests.swift; sourceTree = ""; }; DC9AB2382908174000A2F9D1 /* String+Attributed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Attributed.swift"; sourceTree = ""; }; DCB2897C2948CB51000A3841 /* PPACServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PPACServiceMock.swift; sourceTree = ""; }; + DCBA940229AE21D100905B50 /* MockCWAHibernationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCWAHibernationProvider.swift; sourceTree = ""; }; DCD345B7291BF7B700E95A2D /* UIView+Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Utils.swift"; sourceTree = ""; }; DCDE5FD7292A9DE800F3E733 /* SRSErrorAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRSErrorAlert.swift; sourceTree = ""; }; DCDE5FD9292CFABC00F3E733 /* SRSPreconditionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRSPreconditionError.swift; sourceTree = ""; }; @@ -5643,6 +5644,7 @@ BA7F15A02629D3F200CA4783 /* RouteTests.swift */, 502AB79826E64E5B00536DD2 /* NotificationManagerTests.swift */, DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */, + DCBA940229AE21D100905B50 /* MockCWAHibernationProvider.swift */, ); path = __tests__; sourceTree = ""; @@ -12643,6 +12645,7 @@ 509B1E4426D62BB2007B97E0 /* HealthCertificatePDFGenerationInfoViewModelTests.swift in Sources */, 358D780C2632FA7C00070BED /* HTTPClient+SubmitErrorLogFileTests.swift in Sources */, BA7D178E25D55EB1006B9EBF /* DefaultDataDonationViewModelTests.swift in Sources */, + DCBA940329AE21D100905B50 /* MockCWAHibernationProvider.swift in Sources */, 508266DA278DA60000091991 /* Archive+CBOR.swift in Sources */, 50C51CB625CDEA4300D4C33A /* HTTPClient+SubmitAnalyticsDataTests.swift in Sources */, 0127B09E272855D6008E30AF /* CoronaTestRestorationHandlerTests.swift in Sources */, diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/MockCWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/MockCWAHibernationProvider.swift new file mode 100644 index 00000000000..cf754025588 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/MockCWAHibernationProvider.swift @@ -0,0 +1,28 @@ +// +// 🦠 Corona-Warn-App +// + +import Foundation +@testable import ENA + +class MockCWAHibernationProvider: CWAHibernationProvider { + + // MARK: - Init + + init(testStore: MockTestStore = MockTestStore()) { + self.testStore = testStore + super.init(customStore: testStore) + } + + // MARK: - Overrides + + override var isHibernationState: Bool { + isHibernationStateToReturn + } + + // MARK: - Internal + + var isHibernationStateToReturn: Bool = false + + let testStore: MockTestStore +} diff --git a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift index bf0f3af49be..e427d40c0d4 100644 --- a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift +++ b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift @@ -98,6 +98,14 @@ final class PPAnalyticsSubmitter: PPAnalyticsSubmitting { return } + // Hibernation check + if strongSelf.cwaHibernationProvider.isHibernationState { + Log.warning("Analytics submission \(strongSelf.applicationState) abort due to app is in hibernation state.", log: .ppa) + strongSelf.submissionState = .readyForSubmission + completion?(.failure(.hibernationError)) + return + } + // Check configuration parameter let random = Double.random(in: 0...1) if random > strongSelf.probabilityToSubmitPPAUsageData { @@ -130,14 +138,6 @@ final class PPAnalyticsSubmitter: PPAnalyticsSubmitting { completion?(.failure(.appResetError)) return } - - // Hibernation check - if strongSelf.cwaHibernationProvider.isHibernationState { - Log.warning("Analytics submission \(strongSelf.applicationState) abort due to app is in hibernation state.", log: .ppa) - strongSelf.submissionState = .readyForSubmission - completion?(.failure(.hibernationError)) - return - } if let token = ppacToken { Log.info("Analytics submission \(strongSelf.applicationState)) has an injected ppac token.", log: .ppa) diff --git a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift index 640f10dcdb2..8461e5148c7 100644 --- a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift @@ -34,7 +34,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called without an error") @@ -113,7 +114,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) store.antigenTest = .mock(testResult: .positive, keysSubmitted: true) @@ -153,7 +155,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: coronaTestService, - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) // WHEN @@ -192,7 +195,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) // WHEN @@ -230,7 +234,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) // WHEN @@ -260,7 +265,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -301,7 +307,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -342,7 +349,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -382,7 +390,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -423,7 +432,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -467,7 +477,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -513,7 +524,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -540,10 +552,10 @@ class PPAnalyticsSubmitterTests: CWATestCase { func testGIVEN_SubmissionIsTriggered_WHEN_Hibernation_THEN_HibernationErrorIsReturned() { // GIVEN - let store = MockTestStore() - store.isPrivacyPreservingAnalyticsConsentGiven = true - store.lastSubmissionAnalytics = Calendar.current.date(byAdding: .day, value: -5, to: Date()) - store.dateOfAcceptedPrivacyNotice = Calendar.current.date(byAdding: .day, value: -5, to: Date()) + let mockStore = MockTestStore() + mockStore.isPrivacyPreservingAnalyticsConsentGiven = true + mockStore.lastSubmissionAnalytics = Calendar.current.date(byAdding: .day, value: -5, to: Date()) + mockStore.dateOfAcceptedPrivacyNotice = Calendar.current.date(byAdding: .day, value: -5, to: Date()) var config = SAP_Internal_V2_ApplicationConfigurationIOS() config.privacyPreservingAnalyticsParameters.common.probabilityToSubmit = 3 @@ -558,16 +570,17 @@ class PPAnalyticsSubmitterTests: CWATestCase { let loadResource = LoadResource(result: .success(()), willLoadResource: nil) - let cwaHibernationProvider = CWAHibernationProvider(customStore: store) - store.hibernationComparisonDate = cwaHibernationProvider.hibernationStartDate + let mockCWAHibernationProvider = MockCWAHibernationProvider() + mockCWAHibernationProvider.isHibernationStateToReturn = true +// mockStore.hibernationComparisonDate = mockCWAHibernationProvider.hibernationStartDate let sut = PPAnalyticsSubmitter( - store: store, + store: mockStore, restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck), - cwaHibernationProvider: cwaHibernationProvider + ppacService: PPACService(store: mockStore, deviceCheck: deviceCheck), + cwaHibernationProvider: mockCWAHibernationProvider ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -577,7 +590,7 @@ class PPAnalyticsSubmitterTests: CWATestCase { sut.triggerSubmitData(ppacToken: nil, completion: { result in switch result { case .success: - XCTFail("Test should not success") + XCTFail("Test should not succeed") case let .failure(error): ppasError = error expectation.fulfill() @@ -607,7 +620,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -648,7 +662,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(loadResources: [loadResource]), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called with an error") @@ -713,7 +728,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: restServiceProvider, appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) let expectation = self.expectation(description: "completion handler is called without an error") @@ -1283,7 +1299,8 @@ class PPAnalyticsSubmitterTests: CWATestCase { restServiceProvider: RestServiceProviderStub(), appConfig: appConfigurationProvider, coronaTestService: MockCoronaTestService(), - ppacService: PPACService(store: store, deviceCheck: deviceCheck) + ppacService: PPACService(store: store, deviceCheck: deviceCheck), + cwaHibernationProvider: MockCWAHibernationProvider() ) } From 3ce45529836ba693f1a2f272c9b8c77f470aa5ff Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 28 Feb 2023 13:10:00 +0100 Subject: [PATCH 048/137] 14820: Make `hibernationStartDate` private. --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 2 +- .../__tests__/PPAnalyticsSubmitterTests.swift | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 5126c713783..afc3b9ac983 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -32,7 +32,7 @@ class CWAHibernationProvider: RequiresAppDependencies { } /// CWA hibernation threshold date. - let hibernationStartDate: Date = { + private let hibernationStartDate: Date = { var hibernationStartDateComponents = DateComponents() hibernationStartDateComponents.year = 2023 hibernationStartDateComponents.month = 6 diff --git a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift index 8461e5148c7..2f91d0ef5fb 100644 --- a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift @@ -572,7 +572,6 @@ class PPAnalyticsSubmitterTests: CWATestCase { let mockCWAHibernationProvider = MockCWAHibernationProvider() mockCWAHibernationProvider.isHibernationStateToReturn = true -// mockStore.hibernationComparisonDate = mockCWAHibernationProvider.hibernationStartDate let sut = PPAnalyticsSubmitter( store: mockStore, From b184e08435b71abab4f8d0571cd547d65d39c7cd Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Tue, 28 Feb 2023 13:36:12 +0100 Subject: [PATCH 049/137] adding unit tests --- .../AppInformationViewControllerTests.swift | 15 ++++++ .../__tests__/HomeTableViewModelTests.swift | 52 ++++++++++++++++--- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift index 41fdce42b77..88fdf6c45c1 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift @@ -29,6 +29,21 @@ class AppInformationViewControllerTests: XCTestCase { fakeCCSService = nil } + func testModel_WHEN_modelEntriesInHibernation_THEN_equalCount() throws { + // WHEN + let store = MockTestStore() + store.hibernationComparisonDate = Calendar.current.date(byAdding: .day, value: 180, to: Date()) ?? Date() + + let sut = AppInformationViewController( + elsService: errorLogSubmissionProvidingMock, + finishedDeltaOnboardings: store.finishedDeltaOnboardings, + cclService: fakeCCSService + ) + + // THEN + XCTAssertEqual(sut.model.count, 7) + } + func testModel_WHEN_modelEntries_THEN_equalCategoryCount() throws { // WHEN let modelEntriesCount = sut.model.count diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift index 2085b747da6..a89f4a0c988 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift @@ -10,6 +10,50 @@ import HealthCertificateToolkit // swiftlint:disable type_body_length class HomeTableViewModelTests: CWATestCase { + func testSectionsRowsAndHeightsInHibernation() throws { + let store = MockTestStore() + + let viewModel = HomeTableViewModel( + state: .init( + store: store, + riskProvider: MockRiskProvider(), + exposureManagerState: .init(authorized: true, enabled: true, status: .active), + enState: .enabled, + statisticsProvider: StatisticsProvider( + client: CachingHTTPClientMock(), + store: store + ), + localStatisticsProvider: LocalStatisticsProvider( + client: CachingHTTPClientMock(), + store: store + ) + ), + store: store, + appConfiguration: CachedAppConfigurationMock(), + coronaTestService: MockCoronaTestService(), + familyMemberCoronaTestService: MockFamilyMemberCoronaTestService(), + cclService: FakeCCLService(), + onTestResultCellTap: { _ in }, + badgeWrapper: .fake() + ) + + // Number of Rows per Section + viewModel.isHibernationState = true + + // Number of Sections + XCTAssertEqual(viewModel.numberOfSections, 8) + + // Number of Rows + XCTAssertEqual(viewModel.numberOfRows(in: 0), 1) // end of life tile visible + XCTAssertEqual(viewModel.numberOfRows(in: 1), 0) // app closure notice invisible + XCTAssertEqual(viewModel.numberOfRows(in: 2), 0) // exposure Logging invisible + XCTAssertEqual(viewModel.numberOfRows(in: 3), 0) // riskAndTestResults invisible + XCTAssertEqual(viewModel.numberOfRows(in: 4), 0) // testRegistration invisible + XCTAssertEqual(viewModel.numberOfRows(in: 5), 1) // statistics visible + XCTAssertEqual(viewModel.numberOfRows(in: 6), 0) // traceLocations invisible + XCTAssertEqual(viewModel.numberOfRows(in: 7), 1) // moreInfo visible + } + func testSectionsRowsAndHeights() throws { let store = MockTestStore() @@ -40,12 +84,8 @@ class HomeTableViewModelTests: CWATestCase { // Number of Sections XCTAssertEqual(viewModel.numberOfSections, 8) - // Number of Rows per Section - viewModel.isHibernationState = true - XCTAssertEqual(viewModel.numberOfRows(in: 0), 1) - viewModel.isHibernationState = false + // Number of Rows XCTAssertEqual(viewModel.numberOfRows(in: 0), 0) - XCTAssertEqual(viewModel.numberOfRows(in: 1), 0) XCTAssertEqual(viewModel.numberOfRows(in: 2), 1) XCTAssertEqual(viewModel.numberOfRows(in: 3), 1) @@ -57,7 +97,7 @@ class HomeTableViewModelTests: CWATestCase { // Check riskAndTestResultsRows XCTAssertEqual(viewModel.riskAndTestResultsRows, [.risk]) } - + func testFamilyTestCellNotHiddenIfFamilyMemberTestsExist() { let store = MockTestStore() var defaultAppConfig = CachedAppConfigurationMock.defaultAppConfiguration From c3a53fc54b517ed6691b0fb6d48e7dd15b334a3c Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Tue, 28 Feb 2023 13:36:33 +0100 Subject: [PATCH 050/137] fixing UI test --- .../ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 5853b64f910..0268b31dd04 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -175,7 +175,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega #if DEBUG if isUITesting && LaunchArguments.test.common.showTestResultCards.boolValue { - tableView.scrollToRow(at: IndexPath(row: 1, section: 2), at: .top, animated: false) + tableView.scrollToRow(at: IndexPath(row: 1, section: 3), at: .top, animated: false) } #endif From eb0a0cc98e7eec8d799ace25c18fc4c17f68c114 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 28 Feb 2023 14:10:23 +0100 Subject: [PATCH 051/137] fix row number --- .../ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index a86a536ff52..e878f0a8539 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -169,7 +169,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega #if DEBUG if isUITesting && LaunchArguments.test.common.showTestResultCards.boolValue { - tableView.scrollToRow(at: IndexPath(row: 1, section: 2), at: .top, animated: false) + tableView.scrollToRow(at: IndexPath(row: 1, section: 3), at: .top, animated: false) } #endif From 34d19ac0a71879e6ed4756be3fbb8b121dec52f4 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Tue, 28 Feb 2023 16:16:01 +0100 Subject: [PATCH 052/137] fixing unit test --- .../Scenes/AppInformation/AppInformationViewController.swift | 5 +++-- .../AppInformation/AppInformationViewControllerTests.swift | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift index ebcca352731..28c4be65627 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewController.swift @@ -12,7 +12,8 @@ class AppInformationViewController: DynamicTableViewController, NavigationBarOpa init( elsService: ErrorLogSubmissionProviding, finishedDeltaOnboardings: [String: [String]], - cclService: CCLServable + cclService: CCLServable, + isHibernationState: Bool? = CWAHibernationProvider.shared.isHibernationState ) { self.cclService = cclService self.finishedDeltaOnboardings = finishedDeltaOnboardings @@ -49,7 +50,7 @@ class AppInformationViewController: DynamicTableViewController, NavigationBarOpa action: .push(model: AppInformationViewController.legalModel, separators: true, withTitle: AppStrings.AppInformation.legalNavigation) )] - if !CWAHibernationProvider.shared.isHibernationState { + if let hibernationState = isHibernationState, !hibernationState { self.model[.contact] = AppInformationCellModel( text: AppStrings.AppInformation.contactNavigation, accessibilityIdentifier: AccessibilityIdentifiers.AppInformation.contactNavigation, diff --git a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift index 88fdf6c45c1..a4124f11f1f 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift @@ -32,12 +32,12 @@ class AppInformationViewControllerTests: XCTestCase { func testModel_WHEN_modelEntriesInHibernation_THEN_equalCount() throws { // WHEN let store = MockTestStore() - store.hibernationComparisonDate = Calendar.current.date(byAdding: .day, value: 180, to: Date()) ?? Date() let sut = AppInformationViewController( elsService: errorLogSubmissionProvidingMock, finishedDeltaOnboardings: store.finishedDeltaOnboardings, - cclService: fakeCCSService + cclService: fakeCCSService, + isHibernationState: true ) // THEN From b5e0384ba65a8551cb0cf8d366fe35438c010a61 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 28 Feb 2023 17:25:54 +0100 Subject: [PATCH 053/137] 14819: PR remarks. --- .../ENATaskExecutionDelegate.swift | 10 +++++----- .../ENA/Source/Models/Exposure/ExposureManager.swift | 5 ----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift index 6271a9351f6..ccbaab00784 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift @@ -58,15 +58,15 @@ class TaskExecutionHandler: ENATaskExecutionDelegate { func executeENABackgroundTask(completion: @escaping ((Bool) -> Void)) { Log.info("Starting background task...", log: .background) - guard store.isOnboarded else { - Log.info("Cancelling background task because user is not onboarded yet.", log: .background) - + guard !CWAHibernationProvider.shared.isHibernationState else { + Log.info("CWA is in hibernation state. Background tasks won't be executed.", log: .background) completion(true) return } - guard !CWAHibernationProvider.shared.isHibernationState else { - Log.info("CWA is in hibernation state. Background tasks won't be executed.", log: .background) + guard store.isOnboarded else { + Log.info("Cancelling background task because user is not onboarded yet.", log: .background) + completion(true) return } diff --git a/src/xcode/ENA/ENA/Source/Models/Exposure/ExposureManager.swift b/src/xcode/ENA/ENA/Source/Models/Exposure/ExposureManager.swift index 6e370337c2d..28566e3a91a 100644 --- a/src/xcode/ENA/ENA/Source/Models/Exposure/ExposureManager.swift +++ b/src/xcode/ENA/ENA/Source/Models/Exposure/ExposureManager.swift @@ -186,11 +186,6 @@ final class ENAExposureManager: NSObject, ExposureManager { Log.error("AppDelegate is not of Type AppDelegate, this should not happen!", log: .background) return } - - guard !CWAHibernationProvider.shared.isHibernationState else { - Log.info("CWA is in hibernation state. Background tasks won't be executed in this state.", log: .background) - return - } Log.info("Starting background task via Bluetooth", log: .background) appDelegate.taskExecutionDelegate.executeENABackgroundTask(completion: { success in From 237b8e798dc45fe73939d9ac878ffdddc33d531e Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 28 Feb 2023 17:51:49 +0100 Subject: [PATCH 054/137] 14823: Stop and delete error logs when app call didFinishLaunchingWithOptions and hibernation is on. And prevent submit error logs. --- .../ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift | 4 ++++ .../Source/Services/ELS LoggingService/ELSService.swift | 7 +++++++ .../Services/ELS LoggingService/Model/ELSError.swift | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift index 749d5b81f24..466ea896ecf 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift @@ -190,6 +190,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re NotificationCenter.default.addObserver(self, selector: #selector(isOnboardedDidChange(_:)), name: .isOnboardedDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(backgroundRefreshStatusDidChange), name: UIApplication.backgroundRefreshStatusDidChangeNotification, object: nil) + if CWAHibernationProvider.shared.isHibernationState { + try? elsService.stopAndDeleteLog() + } + guard #available(iOS 13.5, *) else { // Background task registration on iOS 12.5 requires us to activate the ENManager (https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-8919) if store.isOnboarded, exposureManager.exposureManagerState.status == .unknown { diff --git a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/ELSService.swift b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/ELSService.swift index bf0dac0d102..65ffdfbdacb 100644 --- a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/ELSService.swift +++ b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/ELSService.swift @@ -69,6 +69,13 @@ final class ErrorLogSubmissionService: ErrorLogSubmissionProviding { private(set) lazy var logFileSizePublisher: AnyPublisher = setupFileSizePublisher() func submit(completion: @escaping (Result) -> Void) { + + // Hibernation + guard !CWAHibernationProvider.shared.isHibernationState else { + Log.info("In hibernation status it's not allowed to send error logs.", log: .els) + completion(.failure(.hibernation)) + return + } // get log data from the 'all logs' file guard diff --git a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/Model/ELSError.swift b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/Model/ELSError.swift index 6d310b7620e..727ab5808b4 100644 --- a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/Model/ELSError.swift +++ b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/Model/ELSError.swift @@ -15,7 +15,7 @@ indirect enum ELSError: Error { case emptyLogFile case couldNotReadLogfile(_ message: String? = nil) case restServiceError(ServiceError) - + case hibernation } extension ELSError: Equatable { From 2a897b05aa43fc5a7cbafafb160116beb3b51571 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 28 Feb 2023 18:47:05 +0100 Subject: [PATCH 055/137] 14820: Check hibernation state as first condition when try to submit PPA data. # Conflicts: # src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/__tests__/PPAnalyticsSubmitterTests.swift --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 8 ++++-- .../MockCWAHibernationProvider.swift | 28 +++++++++++++++++++ .../ELS LoggingService/ELSService.swift | 7 +++-- .../__tests__/ELSServiceTests.swift | 21 ++++++++++++-- 4 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/MockCWAHibernationProvider.swift diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index 33f2670688f..19a37dc9e11 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -1762,9 +1762,9 @@ DC7003092858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7003082858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift */; }; DC8795AC2923ED8D00F478D5 /* UIViewController+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */; }; DC8BC2BF2953266B003C8CB1 /* InternetConnectivityMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */; }; + DC9390A2299F931A00C2F8F4 /* CWAHibernationProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */; }; DC9390A5299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A4299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift */; }; DC9390A7299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A6299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift */; }; - DC9390A2299F931A00C2F8F4 /* CWAHibernationProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */; }; DC9390A9299FC0F300C2F8F4 /* CWAHibernationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9390A8299FC0F300C2F8F4 /* CWAHibernationProvider.swift */; }; DC95881428BCF9FE00F4D03E /* MaskStateTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */; }; DC95881628BE3D5500F4D03E /* MaskStateCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */; }; @@ -1772,6 +1772,7 @@ DC9AB2392908174000A2F9D1 /* String+Attributed.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9AB2382908174000A2F9D1 /* String+Attributed.swift */; }; DCB2897D2948CB51000A3841 /* PPACServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB2897C2948CB51000A3841 /* PPACServiceMock.swift */; }; DCB78C47294B2FBC00EAE2AB /* MockRiskProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBD2D09F25A86C2A006E4220 /* MockRiskProvider.swift */; }; + DCBA940329AE21D100905B50 /* MockCWAHibernationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCBA940229AE21D100905B50 /* MockCWAHibernationProvider.swift */; }; DCD345B8291BF7B700E95A2D /* UIView+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCD345B7291BF7B700E95A2D /* UIView+Utils.swift */; }; DCDE5FD8292A9DE800F3E733 /* SRSErrorAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDE5FD7292A9DE800F3E733 /* SRSErrorAlert.swift */; }; DCDE5FDA292CFABC00F3E733 /* SRSPreconditionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDE5FD9292CFABC00F3E733 /* SRSPreconditionError.swift */; }; @@ -3668,15 +3669,16 @@ DC7003082858A83800B164AC /* ErrorLogSubmissionProvidingMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogSubmissionProvidingMock.swift; sourceTree = ""; }; DC8795AB2923ED8D00F478D5 /* UIViewController+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Helpers.swift"; sourceTree = ""; }; DC8BC2BE2953266B003C8CB1 /* InternetConnectivityMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetConnectivityMonitor.swift; sourceTree = ""; }; + DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CWAHibernationProviderTests.swift; sourceTree = ""; }; DC9390A4299FAB6A00C2F8F4 /* DMHibernationOptionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMHibernationOptionsViewController.swift; sourceTree = ""; }; DC9390A6299FAB9B00C2F8F4 /* DMHibernationOptionsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMHibernationOptionsViewModel.swift; sourceTree = ""; }; - DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CWAHibernationProviderTests.swift; sourceTree = ""; }; DC9390A8299FC0F300C2F8F4 /* CWAHibernationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CWAHibernationProvider.swift; sourceTree = ""; }; DC95881328BCF9FE00F4D03E /* MaskStateTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateTableViewCell.swift; sourceTree = ""; }; DC95881528BE3D5500F4D03E /* MaskStateCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModel.swift; sourceTree = ""; }; DC95881728BE5E2800F4D03E /* MaskStateCellModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskStateCellModelTests.swift; sourceTree = ""; }; DC9AB2382908174000A2F9D1 /* String+Attributed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Attributed.swift"; sourceTree = ""; }; DCB2897C2948CB51000A3841 /* PPACServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PPACServiceMock.swift; sourceTree = ""; }; + DCBA940229AE21D100905B50 /* MockCWAHibernationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCWAHibernationProvider.swift; sourceTree = ""; }; DCD345B7291BF7B700E95A2D /* UIView+Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Utils.swift"; sourceTree = ""; }; DCDE5FD7292A9DE800F3E733 /* SRSErrorAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRSErrorAlert.swift; sourceTree = ""; }; DCDE5FD9292CFABC00F3E733 /* SRSPreconditionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRSPreconditionError.swift; sourceTree = ""; }; @@ -5650,6 +5652,7 @@ BA7F15A02629D3F200CA4783 /* RouteTests.swift */, 502AB79826E64E5B00536DD2 /* NotificationManagerTests.swift */, DC9390A1299F931A00C2F8F4 /* CWAHibernationProviderTests.swift */, + DCBA940229AE21D100905B50 /* MockCWAHibernationProvider.swift */, ); path = __tests__; sourceTree = ""; @@ -12663,6 +12666,7 @@ 509B1E4426D62BB2007B97E0 /* HealthCertificatePDFGenerationInfoViewModelTests.swift in Sources */, 358D780C2632FA7C00070BED /* HTTPClient+SubmitErrorLogFileTests.swift in Sources */, BA7D178E25D55EB1006B9EBF /* DefaultDataDonationViewModelTests.swift in Sources */, + DCBA940329AE21D100905B50 /* MockCWAHibernationProvider.swift in Sources */, 508266DA278DA60000091991 /* Archive+CBOR.swift in Sources */, 50C51CB625CDEA4300D4C33A /* HTTPClient+SubmitAnalyticsDataTests.swift in Sources */, 0127B09E272855D6008E30AF /* CoronaTestRestorationHandlerTests.swift in Sources */, diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/MockCWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/MockCWAHibernationProvider.swift new file mode 100644 index 00000000000..cf754025588 --- /dev/null +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/MockCWAHibernationProvider.swift @@ -0,0 +1,28 @@ +// +// 🦠 Corona-Warn-App +// + +import Foundation +@testable import ENA + +class MockCWAHibernationProvider: CWAHibernationProvider { + + // MARK: - Init + + init(testStore: MockTestStore = MockTestStore()) { + self.testStore = testStore + super.init(customStore: testStore) + } + + // MARK: - Overrides + + override var isHibernationState: Bool { + isHibernationStateToReturn + } + + // MARK: - Internal + + var isHibernationStateToReturn: Bool = false + + let testStore: MockTestStore +} diff --git a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/ELSService.swift b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/ELSService.swift index 65ffdfbdacb..d2dcb9f1d7b 100644 --- a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/ELSService.swift +++ b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/ELSService.swift @@ -53,12 +53,14 @@ final class ErrorLogSubmissionService: ErrorLogSubmissionProviding { restServicerProvider: RestServiceProviding, store: ErrorLogProviding, ppacService: PrivacyPreservingAccessControl, - otpService: OTPServiceProviding + otpService: OTPServiceProviding, + cwaHibernationProvider: CWAHibernationProvider = CWAHibernationProvider.shared ) { self.restServicerProvider = restServicerProvider self.store = store self.ppacService = ppacService self.otpService = otpService + self.cwaHibernationProvider = cwaHibernationProvider } // MARK: - Protocol ErrorLogSubmitting @@ -71,7 +73,7 @@ final class ErrorLogSubmissionService: ErrorLogSubmissionProviding { func submit(completion: @escaping (Result) -> Void) { // Hibernation - guard !CWAHibernationProvider.shared.isHibernationState else { + guard !cwaHibernationProvider.isHibernationState else { Log.info("In hibernation status it's not allowed to send error logs.", log: .els) completion(.failure(.hibernation)) return @@ -119,6 +121,7 @@ final class ErrorLogSubmissionService: ErrorLogSubmissionProviding { private let store: ErrorLogProviding private let ppacService: PrivacyPreservingAccessControl private let otpService: OTPServiceProviding + private let cwaHibernationProvider: CWAHibernationProvider private lazy var fileLogger = FileLogger() private lazy var fileManager = FileManager.default diff --git a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/__tests__/ELSServiceTests.swift b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/__tests__/ELSServiceTests.swift index 2ba83f1cc8e..1a1ba26f9bc 100644 --- a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/__tests__/ELSServiceTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/__tests__/ELSServiceTests.swift @@ -167,6 +167,19 @@ class ELSServiceTests: CWATestCase { } } + func testGIVEN_ELSService_WHEN_Hibernation_THEN_HibernationErrorIsReturned() throws { + let elsService = createELSService(isHibernation: true) + + elsService.submit { result in + switch result { + case .success: + XCTFail("Test should not succeed") + case .failure(let error): + XCTAssertEqual(ELSError.hibernation, error) + } + } + } + func testLogFetching() throws { let elsService = createELSService() @@ -186,7 +199,8 @@ class ELSServiceTests: CWATestCase { private func createELSService( store: Store & PPAnalyticsData = MockTestStore(), restService: RestServiceProviding = RestServiceProviderStub(), - ppacSucceeds: Bool = true + ppacSucceeds: Bool = true, + isHibernation: Bool = false ) -> ErrorLogSubmissionService { #if targetEnvironment(simulator) @@ -216,11 +230,14 @@ class ELSServiceTests: CWATestCase { ppacService: ppacService, appConfiguration: CachedAppConfigurationMock() ) + let mockCWAHibernationProvider = MockCWAHibernationProvider() + mockCWAHibernationProvider.isHibernationStateToReturn = isHibernation let elsService = ErrorLogSubmissionService( restServicerProvider: restService, store: store, ppacService: ppacService, - otpService: otpService + otpService: otpService, + cwaHibernationProvider: mockCWAHibernationProvider ) return elsService } From 381899792a8e8f7d1a58720b3f3c02f07d88a3c5 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 28 Feb 2023 18:48:55 +0100 Subject: [PATCH 056/137] 14823: Minor comments. --- .../ELS LoggingService/__tests__/ELSServiceTests.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/__tests__/ELSServiceTests.swift b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/__tests__/ELSServiceTests.swift index 1a1ba26f9bc..b5c7a551137 100644 --- a/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/__tests__/ELSServiceTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/ELS LoggingService/__tests__/ELSServiceTests.swift @@ -168,9 +168,13 @@ class ELSServiceTests: CWATestCase { } func testGIVEN_ELSService_WHEN_Hibernation_THEN_HibernationErrorIsReturned() throws { + // GIVEN let elsService = createELSService(isHibernation: true) + // WHEN elsService.submit { result in + + // THEN switch result { case .success: XCTFail("Test should not succeed") From 575cc0baf8026f024e7b24226508ff05c97b22a9 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Tue, 28 Feb 2023 19:21:42 +0100 Subject: [PATCH 057/137] adapting feedback --- .../AppInformation/AppInformationViewControllerTests.swift | 3 +-- .../Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift index a4124f11f1f..04040d534c8 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AppInformation/AppInformationViewControllerTests.swift @@ -30,9 +30,8 @@ class AppInformationViewControllerTests: XCTestCase { } func testModel_WHEN_modelEntriesInHibernation_THEN_equalCount() throws { - // WHEN + // GIVEN let store = MockTestStore() - let sut = AppInformationViewController( elsService: errorLogSubmissionProvidingMock, finishedDeltaOnboardings: store.finishedDeltaOnboardings, diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift index c13427b28b5..36eaf55554d 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift @@ -24,9 +24,7 @@ class HomeMoreInfoTableViewCell: UITableViewCell { stackView.removeAllArrangedSubviews() if CWAHibernationProvider.shared.isHibernationState { - items = MoreInfoItem.allCases.filter({ - $0 != .settings && $0 != .share - }) + items = MoreInfoItem.allCases.filter({ $0 != .settings && $0 != .share }) } else { items = MoreInfoItem.allCases } From 335519b8d76ec0d01ec2fbf5ec151fbb7c102287 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Tue, 28 Feb 2023 19:22:56 +0100 Subject: [PATCH 058/137] removing extra brackets --- .../Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift index 36eaf55554d..8773a6a1be1 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift @@ -24,7 +24,7 @@ class HomeMoreInfoTableViewCell: UITableViewCell { stackView.removeAllArrangedSubviews() if CWAHibernationProvider.shared.isHibernationState { - items = MoreInfoItem.allCases.filter({ $0 != .settings && $0 != .share }) + items = MoreInfoItem.allCases.filter { $0 != .settings && $0 != .share } } else { items = MoreInfoItem.allCases } From 2c37e58d617edd2af9bd66cdc0800693881dc390 Mon Sep 17 00:00:00 2001 From: Puneet Mahali Date: Tue, 28 Feb 2023 22:22:58 +0100 Subject: [PATCH 059/137] remove deeplinks inHibernation State --- .../ENA/ENA/Source/AppDelegate & Globals/Route.swift | 10 ++++++++++ .../Scenes/Events/Store/Model/TraceLocation.swift | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift index 219c6e0eed6..b9c0d8165c2 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift @@ -4,6 +4,7 @@ import Foundation +// swiftlint:disable function_body_length enum Route: Equatable { // MARK: - Init @@ -83,6 +84,9 @@ enum Route: Equatable { return } + if CWAHibernationProvider.shared.isHibernationState { + return nil + } self = .rapidAntigen(.success(.antigen(qrCodeInformation: testInformation, qrCodeHash: ENAHasher.sha256(url.absoluteString)))) case "p.coronawarn.app": guard let payloadUrl = components?.fragment, @@ -143,8 +147,14 @@ enum Route: Equatable { return } + if CWAHibernationProvider.shared.isHibernationState { + return nil + } self = .rapidPCR(.success(.rapidPCR(qrCodeInformation: testInformation, qrCodeHash: ENAHasher.sha256(url.absoluteString)))) case "e.coronawarn.app": + if CWAHibernationProvider.shared.isHibernationState { + return nil + } self = .checkIn(url.absoluteString) default: return nil diff --git a/src/xcode/ENA/ENA/Source/Scenes/Events/Store/Model/TraceLocation.swift b/src/xcode/ENA/ENA/Source/Scenes/Events/Store/Model/TraceLocation.swift index e87bacf5e37..e27b810c027 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Events/Store/Model/TraceLocation.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Events/Store/Model/TraceLocation.swift @@ -30,6 +30,10 @@ struct TraceLocation: Equatable { guard let base64URLEncodedString = qrCodePayloadData?.base64URLEncodedString() else { return nil } + + if CWAHibernationProvider.shared.isHibernationState { + return nil + } return String(format: "https://e.coronawarn.app?v=1#%@", base64URLEncodedString) } From 3fc9c36e482f52bc439531fcec3496dd5972d250 Mon Sep 17 00:00:00 2001 From: Puneet Mahali Date: Tue, 28 Feb 2023 23:30:21 +0100 Subject: [PATCH 060/137] Add UI Test for hibernation state --- ...NAUITests_13_CreateHealthCertificate.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/xcode/ENA/ENAUITests/HealthCertificate/ENAUITests_13_CreateHealthCertificate.swift b/src/xcode/ENA/ENAUITests/HealthCertificate/ENAUITests_13_CreateHealthCertificate.swift index 4008fa8f8e4..1f71d331bcd 100644 --- a/src/xcode/ENA/ENAUITests/HealthCertificate/ENAUITests_13_CreateHealthCertificate.swift +++ b/src/xcode/ENA/ENAUITests/HealthCertificate/ENAUITests_13_CreateHealthCertificate.swift @@ -247,6 +247,25 @@ class ENAUITests_13_CreateHealthCertificate: CWATestCase { XCTAssertTrue(healthCertificateCell.waitForExistence(timeout: .short)) } + func test_CompleteVaccinationProtectionWithTestCertificate_EndOfLifeState() throws { + app.setLaunchArgument(LaunchArguments.endOfLife.isHibernationStateEnabled, to: true) + app.setLaunchArgument(LaunchArguments.healthCertificate.firstAndSecondHealthCertificate, to: true) + app.setLaunchArgument(LaunchArguments.infoScreen.healthCertificateInfoScreenShown, to: true) + app.setLaunchArgument(LaunchArguments.healthCertificate.testCertificateRegistered, to: true) + app.launch() + + // Navigate to Certificates Tab. + app.buttons[AccessibilityIdentifiers.TabBar.certificates].waitAndTap() + + let healthCertificateCell = app.cells[AccessibilityIdentifiers.HealthCertificate.Overview.healthCertifiedPersonCell] + XCTAssertTrue(healthCertificateCell.waitForExistence(timeout: .medium)) + + // Navigate to Persons Tab. + app.cells[AccessibilityIdentifiers.HealthCertificate.Overview.healthCertifiedPersonCell].waitAndTap() + + XCTAssertTrue(app.cells[AccessibilityIdentifiers.HealthCertificate.Overview.healthCertifiedPersonCell].waitForExistence(timeout: .medium)) + } + func test_CompleteVaccination_AdmissionState() { app.setLaunchArgument(LaunchArguments.healthCertificate.firstAndSecondHealthCertificate, to: true) app.setLaunchArgument(LaunchArguments.infoScreen.healthCertificateInfoScreenShown, to: true) From 8acce42c93efdc2113c174a3dc888847c9bcc79a Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 1 Mar 2023 10:14:21 +0100 Subject: [PATCH 061/137] fix failing tests and lint --- .../AppDelegate & Globals/AppDelegate.swift | 5 +- .../NotificationManager.swift | 2 +- .../Events/Store/EventCheckoutService.swift | 10 +- .../Scenes/Home/HomeTableViewController.swift | 2 +- .../DeadmanNotificationManager.swift | 56 ++++----- ...HealthCertificateNotificationService.swift | 22 ++-- .../HealthCertificateService.swift | 107 ++++++++++-------- 7 files changed, 104 insertions(+), 100 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift index 749d5b81f24..38bde2d2f84 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift @@ -165,8 +165,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re UNUserNotificationCenter.current().delegate = notificationManager // Setup DeadmanNotification after AppLaunch - DeadmanNotificationManager().scheduleDeadmanNotificationIfNeeded() - + if !CWAHibernationProvider.shared.isHibernationState { + DeadmanNotificationManager().scheduleDeadmanNotificationIfNeeded() + } // Removing pdf documents from temporary directory FileManager.default.removePDFsFromTemporaryDirectory() diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/NotificationManager.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/NotificationManager.swift index 41de8b02e98..346ffb5a086 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/NotificationManager.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/NotificationManager.swift @@ -44,8 +44,8 @@ final class NotificationManager: NSObject, UNUserNotificationCenterDelegate { } } + // swiftlint:disable cyclomatic_complexity func userNotificationCenter(_: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { - if CWAHibernationProvider.shared.isHibernationState { showHome() } else { diff --git a/src/xcode/ENA/ENA/Source/Scenes/Events/Store/EventCheckoutService.swift b/src/xcode/ENA/ENA/Source/Scenes/Events/Store/EventCheckoutService.swift index 668a09852f8..b30d2be73fd 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Events/Store/EventCheckoutService.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Events/Store/EventCheckoutService.swift @@ -90,7 +90,7 @@ final class EventCheckoutService { if $0.createJournalEntry { self?.eventStore.updateCheckin($0.updatedCheckin(createJournalEntry: false)) } - } else { + } else if !CWAHibernationProvider.shared.isHibernationState { self?.triggerNotificationForCheckout(of: $0) } } @@ -118,11 +118,9 @@ final class EventCheckoutService { content: content, trigger: trigger ) - if !CWAHibernationProvider.shared.isHibernationState { - userNotificationCenter.add(request) { error in - if error != nil { - Log.error("Checkout notification could not be scheduled.") - } + userNotificationCenter.add(request) { error in + if error != nil { + Log.error("Checkout notification could not be scheduled.") } } } diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 03802bfc4fd..0919c72307b 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -161,7 +161,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega #if DEBUG if isUITesting && LaunchArguments.test.common.showTestResultCards.boolValue { - tableView.scrollToRow(at: IndexPath(row: 1, section: 2), at: .top, animated: false) + tableView.scrollToRow(at: IndexPath(row: 1, section: 3), at: .top, animated: false) } #endif diff --git a/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/DeadmanNotificationManager.swift b/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/DeadmanNotificationManager.swift index feb8e096141..3598164171c 100644 --- a/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/DeadmanNotificationManager.swift +++ b/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/DeadmanNotificationManager.swift @@ -26,33 +26,31 @@ struct DeadmanNotificationManager: DeadmanNotificationManageable { /// Schedules a local notification to fire 36 hours from now, if there isn´t a notification already scheduled func scheduleDeadmanNotificationIfNeeded() { /// Check if Deadman Notification is already scheduled - if !CWAHibernationProvider.shared.isHibernationState { - userNotificationCenter.getPendingNotificationRequests { notificationRequests in - if notificationRequests.contains(where: { $0.identifier == Self.deadmanNotificationIdentifier }) { - /// Deadman Notification already setup -> return - return - } else { - /// No Deadman Notification setup, continue to setup a new one - let content = UNMutableNotificationContent() - content.title = AppStrings.Common.deadmanAlertTitle - content.body = AppStrings.Common.deadmanAlertBody - content.sound = .default - - let trigger = UNTimeIntervalNotificationTrigger( - timeInterval: 36 * 60 * 60, - repeats: false - ) - - let request = UNNotificationRequest( - identifier: Self.deadmanNotificationIdentifier, - content: content, - trigger: trigger - ) - - userNotificationCenter.add(request) { error in - if error != nil { - Log.error("Deadman notification could not be scheduled.") - } + userNotificationCenter.getPendingNotificationRequests { notificationRequests in + if notificationRequests.contains(where: { $0.identifier == Self.deadmanNotificationIdentifier }) { + /// Deadman Notification already setup -> return + return + } else { + /// No Deadman Notification setup, continue to setup a new one + let content = UNMutableNotificationContent() + content.title = AppStrings.Common.deadmanAlertTitle + content.body = AppStrings.Common.deadmanAlertBody + content.sound = .default + + let trigger = UNTimeIntervalNotificationTrigger( + timeInterval: 36 * 60 * 60, + repeats: false + ) + + let request = UNNotificationRequest( + identifier: Self.deadmanNotificationIdentifier, + content: content, + trigger: trigger + ) + + userNotificationCenter.add(request) { error in + if error != nil { + Log.error("Deadman notification could not be scheduled.") } } } @@ -62,7 +60,9 @@ struct DeadmanNotificationManager: DeadmanNotificationManageable { /// Reset the Deadman Notification, should be called after a successful risk-calculation. func resetDeadmanNotification() { cancelDeadmanNotification() - scheduleDeadmanNotificationIfNeeded() + if !CWAHibernationProvider.shared.isHibernationState { + scheduleDeadmanNotificationIfNeeded() + } } // MARK: - Private diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift index 198c419ea6b..cd404511599 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift @@ -338,24 +338,20 @@ class HealthCertificateNotificationService { log: .vaccination ) completion() - + return } - if !CWAHibernationProvider.shared.isHibernationState { - self?.notificationCenter.add(request) { error in - if error != nil { - Log.error( - "Could not schedule notification: \(private: request.identifier)", - log: .vaccination, - error: error - ) - } - completion() + self?.notificationCenter.add(request) { error in + if error != nil { + Log.error( + "Could not schedule notification: \(private: request.identifier)", + log: .vaccination, + error: error + ) } - } else { completion() } } } - + } diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift index cb8e29bec93..76295858f27 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift @@ -300,14 +300,15 @@ class HealthCertificateService: HealthCertificateServiceServable { updateValidityState(for: newHealthCertificate, person: person) scheduleTimer() - dispatchGroup.enter() - healthCertificateNotificationService.createNotifications( - for: newHealthCertificate, - completion: { - dispatchGroup.leave() - } - ) - + if !CWAHibernationProvider.shared.isHibernationState { + dispatchGroup.enter() + healthCertificateNotificationService.createNotifications( + for: newHealthCertificate, + completion: { + dispatchGroup.leave() + } + ) + } for relation in certificateRef.relations where relation.action == "replace" { if relation.index < requestCertificates.count { let certificateBase45 = requestCertificates[relation.index] @@ -353,12 +354,12 @@ class HealthCertificateService: HealthCertificateServiceServable { updateValidityState(for: healthCertificate, person: healthCertifiedPerson) scheduleTimer() - - healthCertificateNotificationService.createNotifications( - for: healthCertificate, - completion: completedNotificationRegistration - ) - + if !CWAHibernationProvider.shared.isHibernationState { + healthCertificateNotificationService.createNotifications( + for: healthCertificate, + completion: completedNotificationRegistration + ) + } if isNewPersonAdded { Log.info("[HealthCertificateService] Successfully registered health certificate for a new person", log: .api) // Manual update needed as the person subscriptions were not set up when the certificate was added @@ -554,14 +555,17 @@ class HealthCertificateService: HealthCertificateServiceServable { let dispatchGroup = DispatchGroup() certificateTuples.forEach { healthCertificateTuple in updateValidityState(for: healthCertificateTuple.certificate, person: healthCertificateTuple.person) - dispatchGroup.enter() - healthCertificateNotificationService.createNotifications( - for: healthCertificateTuple.certificate, - completion: { - dispatchGroup.leave() - } - ) + if !CWAHibernationProvider.shared.isHibernationState { + dispatchGroup.enter() + healthCertificateNotificationService.createNotifications( + for: healthCertificateTuple.certificate, + completion: { + dispatchGroup.leave() + } + ) + } } + dispatchGroup.notify(queue: .global()) { completion() @@ -812,33 +816,36 @@ class HealthCertificateService: HealthCertificateServiceServable { let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - self.healthCertificateNotificationService.scheduleBoosterNotificationIfNeeded( - for: person, - previousBoosterNotificationIdentifier: previousBoosterNotificationIdentifier, - completion: { - dispatchGroup.leave() - } - ) - - dispatchGroup.enter() - self.healthCertificateNotificationService.scheduleCertificateReissuanceNotificationIfNeeded( - for: person, - previousCertificateReissuance: previousCertificateReissuance, - completion: { - dispatchGroup.leave() - } - ) - - dispatchGroup.enter() - self.healthCertificateNotificationService.scheduleAdmissionStateChangedNotificationIfNeeded( - for: person, - previousAdmissionStateIdentifier: previousAdmissionStateIdentifier, - completion: { - dispatchGroup.leave() - } - ) - + if !CWAHibernationProvider.shared.isHibernationState { + dispatchGroup.enter() + self.healthCertificateNotificationService.scheduleBoosterNotificationIfNeeded( + for: person, + previousBoosterNotificationIdentifier: previousBoosterNotificationIdentifier, + completion: { + dispatchGroup.leave() + } + ) + } + if !CWAHibernationProvider.shared.isHibernationState { + dispatchGroup.enter() + self.healthCertificateNotificationService.scheduleCertificateReissuanceNotificationIfNeeded( + for: person, + previousCertificateReissuance: previousCertificateReissuance, + completion: { + dispatchGroup.leave() + } + ) + } + if !CWAHibernationProvider.shared.isHibernationState { + dispatchGroup.enter() + self.healthCertificateNotificationService.scheduleAdmissionStateChangedNotificationIfNeeded( + for: person, + previousAdmissionStateIdentifier: previousAdmissionStateIdentifier, + completion: { + dispatchGroup.leave() + } + ) + } dispatchGroup.notify(queue: .global()) { completion?() } @@ -859,7 +866,9 @@ class HealthCertificateService: HealthCertificateServiceServable { $0.certificateRef.barcodeData == healthCertificate.base45 }) { healthCertificate.validityState = .blocked - healthCertificateNotificationService.createNotifications(for: healthCertificate, completion: {}) + if !CWAHibernationProvider.shared.isHibernationState { + healthCertificateNotificationService.createNotifications(for: healthCertificate, completion: {}) + } return true } return false From d7fc679085aeebb0c43a20a9dcd6970077acc7b9 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Wed, 1 Mar 2023 12:07:18 +0100 Subject: [PATCH 062/137] Change trailing space constant to fix a layout issue. --- .../DatePicker/DMDatePickerTableViewCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/ConfigureAbleCells/CellsAndViewModels/DatePicker/DMDatePickerTableViewCell.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/ConfigureAbleCells/CellsAndViewModels/DatePicker/DMDatePickerTableViewCell.swift index ade7389313e..f5f43eae350 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/ConfigureAbleCells/CellsAndViewModels/DatePicker/DMDatePickerTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/ConfigureAbleCells/CellsAndViewModels/DatePicker/DMDatePickerTableViewCell.swift @@ -79,7 +79,7 @@ class DMDatePickerTableViewCell: UITableViewCell, ConfigureableCell { NSLayoutConstraint.activate([ stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), - stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 16), + stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -16) ]) From fde83a0483e562e51c595685387777699a29a0f0 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Thu, 2 Mar 2023 11:18:03 +0100 Subject: [PATCH 063/137] 14820: Move hibernation check to the first line in `triggerSubmitData()` --- .../PPAnalyticsSubmitter.swift | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift index e427d40c0d4..38e53a54462 100644 --- a/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift +++ b/src/xcode/ENA/ENA/Source/Services/PPAnalyticsSubmitter/PPAnalyticsSubmitter.swift @@ -64,6 +64,13 @@ final class PPAnalyticsSubmitter: PPAnalyticsSubmitting { ) { Log.info("Analytics submission was triggered \(applicationState). Checking now if we can submit...", log: .ppa) + // Hibernation check + if cwaHibernationProvider.isHibernationState { + Log.warning("Analytics submission \(applicationState) abort due to app is in hibernation state.", log: .ppa) + completion?(.failure(.hibernationError)) + return + } + // Check if a submission is already in progress guard submissionState == .readyForSubmission else { Log.warning("Analytics submission \(applicationState) abort due to submission is already in progress", log: .ppa) @@ -98,14 +105,6 @@ final class PPAnalyticsSubmitter: PPAnalyticsSubmitting { return } - // Hibernation check - if strongSelf.cwaHibernationProvider.isHibernationState { - Log.warning("Analytics submission \(strongSelf.applicationState) abort due to app is in hibernation state.", log: .ppa) - strongSelf.submissionState = .readyForSubmission - completion?(.failure(.hibernationError)) - return - } - // Check configuration parameter let random = Double.random(in: 0...1) if random > strongSelf.probabilityToSubmitPPAUsageData { From 18f01000739516ada885a89f977b38627304767c Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 2 Mar 2023 12:25:06 +0100 Subject: [PATCH 064/137] refactor PR --- .../ENATaskExecutionDelegate.swift | 2 +- .../UNNotificationCenter+Extension.swift | 38 +++++++++---------- .../UNUserNotificationCenter+WarnOthers.swift | 15 ++++---- .../Models/Exposure/WarnOthersReminder.swift | 14 +++---- .../__tests__/WarnOthersReminderTests.swift | 35 ++++++++--------- .../CoronaTestService/CoronaTestService.swift | 6 +-- .../FamilyMemberCoronaTestService.swift | 2 +- .../__tests__/SRSErrorTests.swift | 16 ++++---- .../Services/Risk/Provider/RiskProvider.swift | 12 +++--- 9 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift index 09063d80cf9..a6aa78eb1de 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/ENATaskExecutionDelegate.swift @@ -336,7 +336,7 @@ class TaskExecutionHandler: ENATaskExecutionDelegate { switch error { case .failedRiskDetection(let reason): if case .wrongDeviceTime = reason { - if !self.dependencies.store.wasDeviceTimeErrorShown { + if !self.dependencies.store.wasDeviceTimeErrorShown && !CWAHibernationProvider.shared.isHibernationState { UNUserNotificationCenter.current().presentNotification( title: AppStrings.WrongDeviceTime.errorPushNotificationTitle, body: AppStrings.WrongDeviceTime.errorPushNotificationText, diff --git a/src/xcode/ENA/ENA/Source/Extensions/UNNotificationCenter+Extension.swift b/src/xcode/ENA/ENA/Source/Extensions/UNNotificationCenter+Extension.swift index 1283c744d12..78b63b883e0 100644 --- a/src/xcode/ENA/ENA/Source/Extensions/UNNotificationCenter+Extension.swift +++ b/src/xcode/ENA/ENA/Source/Extensions/UNNotificationCenter+Extension.swift @@ -42,26 +42,24 @@ extension UserNotificationCenter { in timeInterval: TimeInterval = 1, info: [AnyHashable: Any] = [:] ) { - if !CWAHibernationProvider.shared.isHibernationState { - let content = UNMutableNotificationContent() - - content.title = title - content.body = body - content.sound = UNNotificationSound.default - content.badge = 1 - content.categoryIdentifier = identifier - content.userInfo = info - if #available(iOS 15.0, *) { - content.interruptionLevel = .timeSensitive - } - - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false) - let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger) - - add(request) { error in - if let error = error { - Log.error(error.localizedDescription, log: .api) - } + let content = UNMutableNotificationContent() + + content.title = title + content.body = body + content.sound = UNNotificationSound.default + content.badge = 1 + content.categoryIdentifier = identifier + content.userInfo = info + if #available(iOS 15.0, *) { + content.interruptionLevel = .timeSensitive + } + + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false) + let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger) + + add(request) { error in + if let error = error { + Log.error(error.localizedDescription, log: .api) } } } diff --git a/src/xcode/ENA/ENA/Source/Extensions/UNUserNotificationCenter+WarnOthers.swift b/src/xcode/ENA/ENA/Source/Extensions/UNUserNotificationCenter+WarnOthers.swift index 549c3810d10..a5a44536aac 100644 --- a/src/xcode/ENA/ENA/Source/Extensions/UNUserNotificationCenter+WarnOthers.swift +++ b/src/xcode/ENA/ENA/Source/Extensions/UNUserNotificationCenter+WarnOthers.swift @@ -40,12 +40,13 @@ extension UserNotificationCenter { // MARK: - Private private func presentNotification(identifier: String, in timeInterval: TimeInterval) { - presentNotification( - title: AppStrings.WarnOthersNotification.title, - body: AppStrings.WarnOthersNotification.description, - identifier: identifier, - in: timeInterval - ) + if !CWAHibernationProvider.shared.isHibernationState { + presentNotification( + title: AppStrings.WarnOthersNotification.title, + body: AppStrings.WarnOthersNotification.description, + identifier: identifier, + in: timeInterval + ) + } } - } diff --git a/src/xcode/ENA/ENA/Source/Models/Exposure/WarnOthersReminder.swift b/src/xcode/ENA/ENA/Source/Models/Exposure/WarnOthersReminder.swift index c4bdf990d5e..f822b4f3897 100644 --- a/src/xcode/ENA/ENA/Source/Models/Exposure/WarnOthersReminder.swift +++ b/src/xcode/ENA/ENA/Source/Models/Exposure/WarnOthersReminder.swift @@ -41,14 +41,12 @@ class WarnOthersReminder { /// This function takes a `CoronaTestType` as parameter to schedule warn others notifications for this test type func scheduleNotifications(for coronaTestType: CoronaTestType) { - if !CWAHibernationProvider.shared.isHibernationState { - userNotificationCenter.scheduleWarnOthersNotifications( - coronaTestType: coronaTestType, - timeIntervalOne: TimeInterval(notificationOneTimeInterval), - timeIntervalTwo: TimeInterval(notificationTwoTimeInterval) - ) - Log.info("Warn others reminder: New notifications for type \(coronaTestType) have been scheduled: #1 \(store.warnOthersNotificationOneTimeInterval)/ #2 \(store.warnOthersNotificationTwoTimeInterval) seconds)") - } + userNotificationCenter.scheduleWarnOthersNotifications( + coronaTestType: coronaTestType, + timeIntervalOne: TimeInterval(notificationOneTimeInterval), + timeIntervalTwo: TimeInterval(notificationTwoTimeInterval) + ) + Log.info("Warn others reminder: New notifications for type \(coronaTestType) have been scheduled: #1 \(store.warnOthersNotificationOneTimeInterval)/ #2 \(store.warnOthersNotificationTwoTimeInterval) seconds)") } /// In case the user has informed others about the positive result, this function should be called to reset possible pending 'warn others' notifications diff --git a/src/xcode/ENA/ENA/Source/Models/Exposure/__tests__/WarnOthersReminderTests.swift b/src/xcode/ENA/ENA/Source/Models/Exposure/__tests__/WarnOthersReminderTests.swift index 147463acfa3..4ae452a117c 100644 --- a/src/xcode/ENA/ENA/Source/Models/Exposure/__tests__/WarnOthersReminderTests.swift +++ b/src/xcode/ENA/ENA/Source/Models/Exposure/__tests__/WarnOthersReminderTests.swift @@ -45,8 +45,9 @@ class WarnOthersReminderTests: CWATestCase { XCTAssertTrue(mockNotificationCenter.notificationRequests.isEmpty) - warnOthersReminder.scheduleNotifications(for: .pcr) - + if !CWAHibernationProvider.shared.isHibernationState { + warnOthersReminder.scheduleNotifications(for: .pcr) + } XCTAssertEqual(mockNotificationCenter.notificationRequests.count, 2) XCTAssertEqual( @@ -98,9 +99,9 @@ class WarnOthersReminderTests: CWATestCase { ) XCTAssertTrue(mockNotificationCenter.notificationRequests.isEmpty) - - warnOthersReminder.scheduleNotifications(for: .antigen) - + if !CWAHibernationProvider.shared.isHibernationState { + warnOthersReminder.scheduleNotifications(for: .antigen) + } XCTAssertEqual(mockNotificationCenter.notificationRequests.count, 2) XCTAssertEqual( @@ -152,10 +153,10 @@ class WarnOthersReminderTests: CWATestCase { ) XCTAssertTrue(mockNotificationCenter.notificationRequests.isEmpty) - - warnOthersReminder.scheduleNotifications(for: .pcr) - warnOthersReminder.scheduleNotifications(for: .antigen) - + if !CWAHibernationProvider.shared.isHibernationState { + warnOthersReminder.scheduleNotifications(for: .pcr) + warnOthersReminder.scheduleNotifications(for: .antigen) + } XCTAssertEqual(mockNotificationCenter.notificationRequests.count, 4) warnOthersReminder.cancelNotifications(for: .pcr) @@ -181,10 +182,10 @@ class WarnOthersReminderTests: CWATestCase { ) XCTAssertTrue(mockNotificationCenter.notificationRequests.isEmpty) - - warnOthersReminder.scheduleNotifications(for: .pcr) - warnOthersReminder.scheduleNotifications(for: .antigen) - + if !CWAHibernationProvider.shared.isHibernationState { + warnOthersReminder.scheduleNotifications(for: .pcr) + warnOthersReminder.scheduleNotifications(for: .antigen) + } XCTAssertEqual(mockNotificationCenter.notificationRequests.count, 4) warnOthersReminder.cancelNotifications(for: .antigen) @@ -210,10 +211,10 @@ class WarnOthersReminderTests: CWATestCase { ) XCTAssertTrue(mockNotificationCenter.notificationRequests.isEmpty) - - warnOthersReminder.scheduleNotifications(for: .pcr) - warnOthersReminder.scheduleNotifications(for: .antigen) - + if !CWAHibernationProvider.shared.isHibernationState { + warnOthersReminder.scheduleNotifications(for: .pcr) + warnOthersReminder.scheduleNotifications(for: .antigen) + } XCTAssertEqual(mockNotificationCenter.notificationRequests.count, 4) warnOthersReminder.reset() diff --git a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/CoronaTestService.swift b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/CoronaTestService.swift index f3ae280814c..edecbb2cbdf 100644 --- a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/CoronaTestService.swift +++ b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/CoronaTestService.swift @@ -954,9 +954,9 @@ class CoronaTestService: CoronaTestServiceProviding { } } - if presentNotification { + if presentNotification && !CWAHibernationProvider.shared.isHibernationState { Log.info("[CoronaTestService] Triggering Notification (coronaTestType: \(coronaTestType), testResult: \(testResult))", log: .api) - + // We attach the test result and type to determine which screen to show when user taps the notification self.notificationCenter.presentNotification( title: AppStrings.LocalNotifications.testResultsTitle, @@ -1024,7 +1024,7 @@ class CoronaTestService: CoronaTestServiceProviding { if let coronaTest = coronaTest(ofType: coronaTestType), coronaTest.testResult == .positive, coronaTest.positiveTestResultWasShown { DeadmanNotificationManager().resetDeadmanNotification() - if !coronaTest.isSubmissionConsentGiven, !coronaTest.keysSubmitted { + if !coronaTest.isSubmissionConsentGiven, !coronaTest.keysSubmitted, !CWAHibernationProvider.shared.isHibernationState { warnOthersReminder.scheduleNotifications(for: coronaTestType) } } diff --git a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/FamilyMemberCoronaTestService.swift b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/FamilyMemberCoronaTestService.swift index d6f4d1c09bc..21219a782e7 100644 --- a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/FamilyMemberCoronaTestService.swift +++ b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/FamilyMemberCoronaTestService.swift @@ -674,7 +674,7 @@ class FamilyMemberCoronaTestService: FamilyMemberCoronaTestServiceProviding { } } - if presentNotification && testResult != previousTestResult { + if presentNotification && testResult != previousTestResult && !CWAHibernationProvider.shared.isHibernationState{ Log.info("[FamilyMemberCoronaTestService] Triggering Notification (coronaTest: \(private: coronaTest), testResult: \(testResult))", log: .api) // We attach the test result and type to determine which screen to show when user taps the notification diff --git a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift index 7f2a0a176c1..97241a9a623 100644 --- a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift @@ -7,14 +7,14 @@ import XCTest final class SRSErrorTests: XCTestCase { - override func setUp() async throws { - InternetConnectivityMonitor.shared.isDeviceOnlineMock = true - } - - override func tearDown() async throws { - InternetConnectivityMonitor.shared.isDeviceOnlineMock = false - } - +// override func setUp() async throws { +// InternetConnectivityMonitor.shared.isDeviceOnlineMock = true +// } +// +// override func tearDown() async throws { +// InternetConnectivityMonitor.shared.isDeviceOnlineMock = false +// } +// func testDescription_ppacError() throws { // GIVEN let sut: SRSError = .ppacError(.submissionTooEarly) diff --git a/src/xcode/ENA/ENA/Source/Services/Risk/Provider/RiskProvider.swift b/src/xcode/ENA/ENA/Source/Services/Risk/Provider/RiskProvider.swift index 483faae0878..f50b31e16e6 100644 --- a/src/xcode/ENA/ENA/Source/Services/Risk/Provider/RiskProvider.swift +++ b/src/xcode/ENA/ENA/Source/Services/Risk/Provider/RiskProvider.swift @@ -444,11 +444,13 @@ final class RiskProvider: RiskProviding { } private func triggerRiskChangeNotification() { - UNUserNotificationCenter.current().presentNotification( - title: AppStrings.LocalNotifications.detectExposureTitle, - body: AppStrings.LocalNotifications.detectExposureBody, - identifier: ActionableNotificationIdentifier.riskDetection.identifier - ) + if !CWAHibernationProvider.shared.isHibernationState { + UNUserNotificationCenter.current().presentNotification( + title: AppStrings.LocalNotifications.detectExposureTitle, + body: AppStrings.LocalNotifications.detectExposureBody, + identifier: ActionableNotificationIdentifier.riskDetection.identifier + ) + } } private func checkIfRiskStatusLoweredAlertShouldBeShown(_ risk: Risk) { From 56ee1ea85e9493537b707e36f486ece6a73b34f5 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 2 Mar 2023 12:57:23 +0100 Subject: [PATCH 065/137] small fix --- .../DMHibernation/DMHibernationOptionsViewModel.swift | 4 +--- .../CoronaTestService/FamilyMemberCoronaTestService.swift | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index 3bd8be04801..47cfb1b5151 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -27,9 +27,7 @@ class DMHibernationOptionsViewModel { switch section { case .hibernationComparisonDate: - var title = "App will shutdown after selecting a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationComparisonDate))" - - return title + return "App will shutdown after selecting a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationComparisonDate))" case .reset: return "App will shutdown after reseting to today's date." } diff --git a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/FamilyMemberCoronaTestService.swift b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/FamilyMemberCoronaTestService.swift index 21219a782e7..95bf50707f9 100644 --- a/src/xcode/ENA/ENA/Source/Services/CoronaTestService/FamilyMemberCoronaTestService.swift +++ b/src/xcode/ENA/ENA/Source/Services/CoronaTestService/FamilyMemberCoronaTestService.swift @@ -674,7 +674,7 @@ class FamilyMemberCoronaTestService: FamilyMemberCoronaTestServiceProviding { } } - if presentNotification && testResult != previousTestResult && !CWAHibernationProvider.shared.isHibernationState{ + if presentNotification && testResult != previousTestResult && !CWAHibernationProvider.shared.isHibernationState { Log.info("[FamilyMemberCoronaTestService] Triggering Notification (coronaTest: \(private: coronaTest), testResult: \(testResult))", log: .api) // We attach the test result and type to determine which screen to show when user taps the notification From 3c28578ea0d6f20c0c6d2915d205204403937a9f Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Thu, 2 Mar 2023 13:48:40 +0100 Subject: [PATCH 066/137] 14819: Move hibernation guard into the constructor of `ENATaskScheduler`. --- .../Models/Task Scheduling/ENATaskScheduler.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift b/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift index 51b8818a436..d5cc0a82d73 100644 --- a/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift +++ b/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift @@ -41,6 +41,11 @@ final class ENATaskScheduler { // MARK: - Initializer. private init() { if #available(iOS 13.0, *) { + guard !CWAHibernationProvider.shared.isHibernationState else { + Log.info("CWA is in hibernation state. Background tasks won't be registered.", log: .api) + return + } + registerTask(with: .exposureNotification, execute: exposureNotificationTask(_:)) } } @@ -48,11 +53,6 @@ final class ENATaskScheduler { // MARK: - Task registration. @available(iOS 13.0, *) private func registerTask(with taskIdentifier: ENATaskIdentifier, execute: @escaping ((BGTask) -> Void)) { - guard !CWAHibernationProvider.shared.isHibernationState else { - Log.info("CWA is in hibernation state. The background task with identifier \(taskIdentifier) won't be registered.", log: .api) - return - } - let identifierString = taskIdentifier.backgroundTaskSchedulerIdentifier BGTaskScheduler.shared.register(forTaskWithIdentifier: identifierString, using: .main) { task in self.scheduleTask() From ee6814e217a6f1978c5e170aead4bf30d5b7bd25 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 3 Mar 2023 09:59:39 +0100 Subject: [PATCH 067/137] 14821: Simplify code and Unit Tests. --- .../Source/AppDelegate & Globals/Route.swift | 15 +++++---------- .../__tests__/RouteTests.swift | 19 +++++++++++++++++++ .../Model/__tests__/TraceLocationTests.swift | 12 ++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift index b9c0d8165c2..2eddec0cad5 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift @@ -18,6 +18,10 @@ enum Route: Equatable { } // swiftlint:disable:next cyclomatic_complexity init?(url: URL) { + if CWAHibernationProvider.shared.isHibernationState { + return nil + } + let components = URLComponents(url: url, resolvingAgainstBaseURL: true) guard let host = components?.host?.lowercased() else { return nil @@ -83,10 +87,7 @@ enum Route: Equatable { Log.error("recomputed hash: \(recomputedHashString) Doesn't match the original hash \(testInformation.hash)", log: .qrCode) return } - - if CWAHibernationProvider.shared.isHibernationState { - return nil - } + self = .rapidAntigen(.success(.antigen(qrCodeInformation: testInformation, qrCodeHash: ENAHasher.sha256(url.absoluteString)))) case "p.coronawarn.app": guard let payloadUrl = components?.fragment, @@ -147,14 +148,8 @@ enum Route: Equatable { return } - if CWAHibernationProvider.shared.isHibernationState { - return nil - } self = .rapidPCR(.success(.rapidPCR(qrCodeInformation: testInformation, qrCodeHash: ENAHasher.sha256(url.absoluteString)))) case "e.coronawarn.app": - if CWAHibernationProvider.shared.isHibernationState { - return nil - } self = .checkIn(url.absoluteString) default: return nil diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/RouteTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/RouteTests.swift index 39b0ddd58b0..60769aff9cf 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/RouteTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/RouteTests.swift @@ -6,6 +6,25 @@ import XCTest @testable import ENA class RouteTests: CWATestCase { + + func testInitURL_Hibernation_ShouldReturnNil() { + // GIVEN + let validRATTestURLString = "https://s.coronawarn.app?v=1#eyJ0aW1lc3RhbXAiOjE2MTk2MTcyNjksInNhbHQiOiI3QkZBMDZCNUFEOTMxMUI4NzE5QkI4MDY2MUM1NEVBRCIsInRlc3RpZCI6ImI0YTQwYzZjLWUwMmMtNDQ0OC1iOGFiLTBiNWI3YzM0ZDYwYSIsImhhc2giOiIxZWE0YzIyMmZmMGMwZTRlZDczNzNmMjc0Y2FhN2Y3NWQxMGZjY2JkYWM1NmM2MzI3NzFjZDk1OTIxMDJhNTU1IiwiZm4iOiJIZW5yeSIsImxuIjoiUGluemFuaSIsImRvYiI6IjE5ODktMDgtMzAifQ" + + guard let url = URL(string: validRATTestURLString) else { + return XCTFail("Expect a valid URL from a valid URL string.") + } + + // WHEN + let sut = Route(url: url) + + // THEN + if CWAHibernationProvider.shared.isHibernationState { + XCTAssertNil(sut) + } else { + XCTAssertNotNil(sut) + } + } func testGIVEN_validRATUrlWithoutDGCInfo_WHEN_parseRoute_THEN_isValid() { // GIVEN diff --git a/src/xcode/ENA/ENA/Source/Scenes/Events/Store/Model/__tests__/TraceLocationTests.swift b/src/xcode/ENA/ENA/Source/Scenes/Events/Store/Model/__tests__/TraceLocationTests.swift index 2b6a5f78b0d..be502749e7b 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Events/Store/Model/__tests__/TraceLocationTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Events/Store/Model/__tests__/TraceLocationTests.swift @@ -188,6 +188,18 @@ class TraceLocationTests: CWATestCase { // fallback length is 120 min XCTAssertEqual(traceLocation.suggestedOnBehalfWarningDurationInMinutes, 120) } + + func testQRCodeURL_Hibernation_ShouldReturnNil() { + // GIVEN + let sut = createMockTraceLocation(id: Data()) + + // THEN + if CWAHibernationProvider.shared.isHibernationState { + XCTAssertNil(sut.qrCodeURL) + } else { + XCTAssertNotNil(sut.qrCodeURL) + } + } // MARK: - Private From 98f699d85b83249248cc7eeea9906ef7418a28bf Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Fri, 3 Mar 2023 10:06:23 +0100 Subject: [PATCH 068/137] fix lint issues --- .../__tests__/SRSErrorTests.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift index 97241a9a623..7f2a0a176c1 100644 --- a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift @@ -7,14 +7,14 @@ import XCTest final class SRSErrorTests: XCTestCase { -// override func setUp() async throws { -// InternetConnectivityMonitor.shared.isDeviceOnlineMock = true -// } -// -// override func tearDown() async throws { -// InternetConnectivityMonitor.shared.isDeviceOnlineMock = false -// } -// + override func setUp() async throws { + InternetConnectivityMonitor.shared.isDeviceOnlineMock = true + } + + override func tearDown() async throws { + InternetConnectivityMonitor.shared.isDeviceOnlineMock = false + } + func testDescription_ppacError() throws { // GIVEN let sut: SRSError = .ppacError(.submissionTooEarly) From a59a8e617d50abb9a3a5c6d785d20fa29ab7d8ef Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Fri, 3 Mar 2023 12:46:44 +0100 Subject: [PATCH 069/137] add end of life uitest --- .../Onboarding/ENAUITests_00_Onboarding.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift b/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift index a01c97e5477..063dc2a79ff 100644 --- a/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift +++ b/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift @@ -18,6 +18,23 @@ class ENAUITests_00_Onboarding: CWATestCase { app.setLaunchArgument(LaunchArguments.consent.isDatadonationConsentGiven, to: false) app.setLaunchArgument(LaunchArguments.common.ENStatus, to: ENStatus.unknown.stringValue) } + + func test_0000_OnboardingFlow_After_EndOFLife_XXXL() throws { + app.setPreferredContentSizeCategory(accessibility: .normal, size: .XXXL) + app.setLaunchArgument(LaunchArguments.endOfLife.isHibernationStateEnabled, to: true) + app.launch() + + // only run if onboarding screen is present + XCTAssertTrue(app.staticTexts["AppStrings.Onboarding.onboardingInfo_togetherAgainstCoronaPage_title"].waitForExistence(timeout: 5.0)) + + // tap through the onboarding screens + app.buttons["AppStrings.Onboarding.onboardingLetsGo"].waitAndTap() + + app.buttons["AppStrings.Onboarding.onboardingContinue"].waitAndTap() + + // check that the homescreen element AppStrings.home.activateTitle is visible onscreen + XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel].waitForExistence(timeout: .medium)) + } func test_0000_OnboardingFlow_DisablePermissions_normal_XXXL() throws { app.setPreferredContentSizeCategory(accessibility: .normal, size: .XXXL) From 72ef67c2368dabb976d9449949dc68b70cf08782 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Fri, 3 Mar 2023 12:47:06 +0100 Subject: [PATCH 070/137] small fix --- .../__tests__/OTPAuthorizationForSRSResourceTests.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/HTTPClient/Resources/OTPAuthorizationForSRS/__tests__/OTPAuthorizationForSRSResourceTests.swift b/src/xcode/ENA/ENA/Source/HTTPClient/Resources/OTPAuthorizationForSRS/__tests__/OTPAuthorizationForSRSResourceTests.swift index 5351741e26e..f51a1701275 100644 --- a/src/xcode/ENA/ENA/Source/HTTPClient/Resources/OTPAuthorizationForSRS/__tests__/OTPAuthorizationForSRSResourceTests.swift +++ b/src/xcode/ENA/ENA/Source/HTTPClient/Resources/OTPAuthorizationForSRS/__tests__/OTPAuthorizationForSRSResourceTests.swift @@ -12,7 +12,6 @@ final class OTPAuthorizationForSRSResourceTests: XCTestCase { func testGIVEN_AuthorizeOTP_WHEN_SuccesWithAuthorization_THEN_ExpirationDateIsReturned() throws { // GIVEN let dateString = "2021-02-16T08:34:00+00:00" - let dateFormatter = ISO8601DateFormatter() let response: [String: String] = ["expirationDate": dateString] From 4751fe2c7d950d6b8f3cb2639816c5eb6b7012b1 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Fri, 3 Mar 2023 12:47:51 +0100 Subject: [PATCH 071/137] fix srs error tests --- .../Exposure Submission/__tests__/SRSErrorTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift index 7f2a0a176c1..1de00e8a959 100644 --- a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift @@ -7,11 +7,11 @@ import XCTest final class SRSErrorTests: XCTestCase { - override func setUp() async throws { + override func setUp() { InternetConnectivityMonitor.shared.isDeviceOnlineMock = true } - override func tearDown() async throws { + override func tearDown() { InternetConnectivityMonitor.shared.isDeviceOnlineMock = false } From 526126c158a41571c631ec87f4aef76a4eab4836 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Fri, 3 Mar 2023 12:49:03 +0100 Subject: [PATCH 072/137] fix lint issue --- .../Exposure Submission/__tests__/SRSErrorTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift index 7f2a0a176c1..1de00e8a959 100644 --- a/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/Exposure Submission/__tests__/SRSErrorTests.swift @@ -7,11 +7,11 @@ import XCTest final class SRSErrorTests: XCTestCase { - override func setUp() async throws { + override func setUp() { InternetConnectivityMonitor.shared.isDeviceOnlineMock = true } - override func tearDown() async throws { + override func tearDown() { InternetConnectivityMonitor.shared.isDeviceOnlineMock = false } From 5dcb07513879440c1814b1127d8757300a05a138 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 3 Mar 2023 14:14:21 +0100 Subject: [PATCH 073/137] 14427: Change hibernation start date from 01.06.2023 to 01.05.2023. --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 026e0050b04..f8ffade53d5 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -38,7 +38,7 @@ class CWAHibernationProvider: RequiresAppDependencies { private let hibernationStartDate: Date = { var hibernationStartDateComponents = DateComponents() hibernationStartDateComponents.year = 2023 - hibernationStartDateComponents.month = 6 + hibernationStartDateComponents.month = 5 hibernationStartDateComponents.day = 1 hibernationStartDateComponents.hour = 0 hibernationStartDateComponents.minute = 0 From c1008c7fd290653d7bfc1f203089369ddfdbb5d1 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 3 Mar 2023 14:15:11 +0100 Subject: [PATCH 074/137] 14427: Refactor `ActionTableViewCell` to more clearness. --- .../ENSetting/Cells/ActionTableViewCell.swift | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/ENSetting/Cells/ActionTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/ENSetting/Cells/ActionTableViewCell.swift index 66f53006294..ab0b34a7423 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/ENSetting/Cells/ActionTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/ENSetting/Cells/ActionTableViewCell.swift @@ -15,23 +15,7 @@ enum SettingAction { class ActionTableViewCell: UITableViewCell { - private var actionTitleLabel: ENALabel! - private var actionSwitch: ENASwitch! - private var detailLabel: ENALabel! - private var detailLabelTrailingAnchorConstrint: NSLayoutConstraint? - private var line: SeperatorLineLayer! - private var askForConsent = false - - weak var delegate: ActionTableViewCellDelegate? - - @objc - private func switchValueDidChange() { - if askForConsent { - delegate?.performAction(action: .askConsent) - } else { - delegate?.performAction(action: .enable(actionSwitch.isOn)) - } - } + // MARK: - Init override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -84,6 +68,13 @@ class ActionTableViewCell: UITableViewCell { fatalError("init(coder:) has not been implemented") } + // MARK: - Overrides + + override func accessibilityActivate() -> Bool { + toggle(self) + return true + } + override func layoutSubviews() { super.layoutSubviews() let path = UIBezierPath() @@ -95,9 +86,7 @@ class ActionTableViewCell: UITableViewCell { line.path = path.cgPath } - func turnSwitch(to on: Bool) { - actionSwitch.setOn(on, animated: true) - } + // MARK: Internal func configure(for state: ENStateHandler.State) { askForConsent = false @@ -133,13 +122,17 @@ class ActionTableViewCell: UITableViewCell { self.delegate = delegate configure(for: state) } + + // MARK: - Private + + private var actionTitleLabel: ENALabel! + private var actionSwitch: ENASwitch! + private var detailLabel: ENALabel! + private var detailLabelTrailingAnchorConstrint: NSLayoutConstraint? + private var line: SeperatorLineLayer! + private var askForConsent = false - @objc - func toggle(_ sender: Any) { - actionSwitch.isOn.toggle() - switchValueDidChange() - setupAccessibility() - } + private weak var delegate: ActionTableViewCellDelegate? private func setupAccessibility() { accessibilityIdentifier = AccessibilityIdentifiers.ExposureNotificationSetting.enableTracing @@ -179,9 +172,24 @@ class ActionTableViewCell: UITableViewCell { detailLabelTrailingAnchorConstrint?.isActive = true } } - - override func accessibilityActivate() -> Bool { - toggle(self) - return true + + @objc + private func switchValueDidChange() { + if askForConsent { + delegate?.performAction(action: .askConsent) + } else { + delegate?.performAction(action: .enable(actionSwitch.isOn)) + } + } + + @objc + private func toggle(_ sender: Any) { + actionSwitch.isOn.toggle() + switchValueDidChange() + setupAccessibility() + } + + private func turnSwitch(to on: Bool) { + actionSwitch.setOn(on, animated: true) } } From 893868f1d6f055d12f7977854f5b0b195b26b48d Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 3 Mar 2023 14:15:46 +0100 Subject: [PATCH 075/137] 14427: When app starts, disable ENF when hibernation state is given. --- .../AppDelegate & Globals/AppDelegate.swift | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift index 466ea896ecf..64d94c63c54 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift @@ -185,15 +185,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re } riskProvider.observeRisk(consumer) - exposureManager.observeExposureNotificationStatus(observer: self) - NotificationCenter.default.addObserver(self, selector: #selector(isOnboardedDidChange(_:)), name: .isOnboardedDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(backgroundRefreshStatusDidChange), name: UIApplication.backgroundRefreshStatusDidChangeNotification, object: nil) - + + // Hibernation if CWAHibernationProvider.shared.isHibernationState { + // Stop and delete error logging. try? elsService.stopAndDeleteLog() + + // Disable Exposure Notification (ENF) + disableExposureNotification() + } else { + + // Observe Exposure Notification (ENF) + exposureManager.observeExposureNotificationStatus(observer: self) } - + guard #available(iOS 13.5, *) else { // Background task registration on iOS 12.5 requires us to activate the ENManager (https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-8919) if store.isOnboarded, exposureManager.exposureManagerState.status == .unknown { @@ -1129,6 +1136,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re window?.makeKeyAndVisible() } + private func disableExposureNotification() { + Log.info("Try to disable exposure notification.") + + exposureManager.disable { exposureNotificationError in + if let exposureNotificationError = exposureNotificationError { + Log.error("The exposure notification couldn't be disabled by ExposureManager: \(exposureNotificationError.localizedDescription)") + } else { + Log.info("The exposure notification was disabled.") + } + } + } } private extension Array where Element == URLQueryItem { From 971df946164b6bd6a31cb2e459826fa7cfbfd630 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 3 Mar 2023 14:54:27 +0100 Subject: [PATCH 076/137] 14889: DM: hibernation comparison date is now selectavle by date and time with a separate save button. --- .../CWAHibernationProvider.swift | 1 - .../CWAHibernationProviderTests.swift | 2 - .../DMHibernationOptionsViewController.swift | 4 +- .../DMHibernationOptionsViewModel.swift | 38 +++++++++++++------ 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 026e0050b04..64469a23462 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -43,7 +43,6 @@ class CWAHibernationProvider: RequiresAppDependencies { hibernationStartDateComponents.hour = 0 hibernationStartDateComponents.minute = 0 hibernationStartDateComponents.second = 0 - hibernationStartDateComponents.timeZone = .utcTimeZone guard let hibernationStartDate = Calendar.current.date(from: hibernationStartDateComponents) else { fatalError("The hibernation start date couldn't be created.") diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index 94113d94a07..73586dd3ede 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -20,7 +20,6 @@ final class CWAHibernationProviderTests: CWATestCase { beforeHibernationStartDateComponents.hour = 23 beforeHibernationStartDateComponents.minute = 59 beforeHibernationStartDateComponents.second = 59 - beforeHibernationStartDateComponents.timeZone = .utcTimeZone guard let hibernationComparisonDate = Calendar.current.date(from: beforeHibernationStartDateComponents) else { return XCTFail("Expect the hibernation comparison date from the corresponding date components.") @@ -44,7 +43,6 @@ final class CWAHibernationProviderTests: CWATestCase { afterHibernationStartDateComponents.hour = 0 afterHibernationStartDateComponents.minute = 0 afterHibernationStartDateComponents.second = 0 - afterHibernationStartDateComponents.timeZone = .utcTimeZone guard let hibernationComparisonDate = Calendar.current.date(from: afterHibernationStartDateComponents) else { return XCTFail("Expect the hibernation comparison date from the corresponding date components.") diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift index 6adc94c0fdb..3b11933d956 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift @@ -83,8 +83,8 @@ class DMHibernationOptionsViewController: UITableViewController { let cell = tableView.dequeueReusableCell(cellType: DMDatePickerTableViewCell.self, for: indexPath) cell.configure(cellViewModel: cellViewModel) - cell.didSelectDate = { [weak self] hibernationComparisonDate in - self?.viewModel.store(hibernationComparisonDate: hibernationComparisonDate) + cell.didSelectDate = { [weak self] hibernationComparisonDateSelected in + self?.viewModel.hibernationComparisonDateSelected = hibernationComparisonDateSelected } return cell diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index 3bd8be04801..3ac1498dbce 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -12,24 +12,29 @@ class DMHibernationOptionsViewModel { init(store: Store) { self.store = store + self.hibernationComparisonDateSelected = store.hibernationComparisonDate } // MARK: - Internal + var hibernationComparisonDateSelected: Date + var numberOfSections: Int { Sections.allCases.count } func numberOfRows(in section: Int) -> Int { 1 } - func titleForFooter(in section: Int) -> String { + func titleForFooter(in section: Int) -> String? { guard let section = Sections(rawValue: section) else { fatalError("Invalid tableView section") } switch section { case .hibernationComparisonDate: - var title = "App will shutdown after selecting a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationComparisonDate))" + var title = "App will shutdown after selecting a new date value in the date picker. Currently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationComparisonDate))" return title + case .storeButton: + return nil case .reset: return "App will shutdown after reseting to today's date." } @@ -45,9 +50,18 @@ class DMHibernationOptionsViewModel { return DMDatePickerCellViewModel( title: "Hibernation Comparison Date", accessibilityIdentifier: AccessibilityIdentifiers.DeveloperMenu.Hibernation.datePicker, - datePickerMode: .date, + datePickerMode: .dateAndTime, date: store.hibernationComparisonDate ) + case .storeButton: + return DMButtonCellViewModel( + text: "Save Comparison Date", + textColor: .white, + backgroundColor: .enaColor(for: .buttonPrimary) + ) { [weak self] in + guard let self = self else { return } + self.store(hibernationComparisonDate: self.hibernationComparisonDateSelected) + } case .reset: return DMButtonCellViewModel( text: "Reset Comparison Date", @@ -59,22 +73,22 @@ class DMHibernationOptionsViewModel { } } - func store(hibernationComparisonDate: Date) { - Log.debug("[Debug-Menu] Set hibernation comparison date to: \(dateFormatter.string(from: hibernationComparisonDate)).") - store.hibernationComparisonDate = hibernationComparisonDate - - exitApp() - } - // MARK: - Private private let store: Store private let dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd" + dateFormatter.dateFormat = "yyyy-MM-dd, HH:mm" return dateFormatter }() + + private func store(hibernationComparisonDate: Date) { + Log.debug("[Debug-Menu] Set hibernation comparison date to: \(dateFormatter.string(from: hibernationComparisonDate)).") + store.hibernationComparisonDate = hibernationComparisonDate + + exitApp() + } private func exitApp() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { @@ -87,6 +101,8 @@ extension DMHibernationOptionsViewModel { enum Sections: Int, CaseIterable { /// The date, that will be used to compare it against the hibernation start date. case hibernationComparisonDate + /// Store the set hibernation comparison date + case storeButton /// Reset the stored fake date, the hibernation threshold compares to. case reset } From 9a63f31d94092792fd7aa7a65702dd175d796c8e Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 6 Mar 2023 10:32:40 +0100 Subject: [PATCH 077/137] 14887: Adapt unit test to new hibernation start date. --- .../__tests__/CWAHibernationProviderTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index 94113d94a07..022d2a020d3 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -15,8 +15,8 @@ final class CWAHibernationProviderTests: CWATestCase { // WHEN var beforeHibernationStartDateComponents = DateComponents() beforeHibernationStartDateComponents.year = 2023 - beforeHibernationStartDateComponents.month = 5 - beforeHibernationStartDateComponents.day = 31 + beforeHibernationStartDateComponents.month = 4 + beforeHibernationStartDateComponents.day = 30 beforeHibernationStartDateComponents.hour = 23 beforeHibernationStartDateComponents.minute = 59 beforeHibernationStartDateComponents.second = 59 @@ -39,7 +39,7 @@ final class CWAHibernationProviderTests: CWATestCase { // WHEN var afterHibernationStartDateComponents = DateComponents() afterHibernationStartDateComponents.year = 2023 - afterHibernationStartDateComponents.month = 6 + afterHibernationStartDateComponents.month = 5 afterHibernationStartDateComponents.day = 1 afterHibernationStartDateComponents.hour = 0 afterHibernationStartDateComponents.minute = 0 From ed840b3b6f057075986ebb104763cc5d265efb32 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Mon, 6 Mar 2023 12:01:43 +0100 Subject: [PATCH 078/137] update thank you text --- .../ENA/Resources/Localization/de.lproj/Localizable.strings | 2 +- .../EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings index d91408c4d71..4197605e8b3 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings @@ -1525,7 +1525,7 @@ Bei ausgeschalteter Hintergrundaktualisierung müssen Sie die App täglich aufru "Home_EndOfLifeThankYouTile_Title" = "Vielen Dank!"; -"Home_EndOfLifeThankYouTile_description" = "Der Betrieb der Corona-Warn-App wurde eingestellt. Vielen Dank für Ihre Nutzung. Mit Ihrer Unterstützung konnten während der Pandemie mehr als %i Millionen Warnungen verschickt werden. Sie können weiterhin auf Ihre bereits vorhandenen Zertifikate und das Kontakt-Tagebuch zugreifen. Alle anderen Funktionen stehen nicht mehr zur Verfügung. In den Geräteeinstellungen Ihres Smartphones können Sie jetzt die Benachrichtigungen für die App deaktivieren."; +"Home_EndOfLifeThankYouTile_description" = "Vielen Dank für die Nutzung der Corona-Warn-App. Während der Pandemie wurden durch die Nutzenden der Corona-Warn-App knapp 9 Millionen positive Testergebnisse geteilt. Durch diese Teilung positiver Testergebnisse konnten Personen schnell vor einem erhöhten Infektionsrisiko gewarnt werden, das sonst unerkannt geblieben wäre. Viele Gewarnte wurden anschließend positiv getestet. Die Corona-Warn-App hat dank Ihrer gemeinsamen Mithilfe ihren Zweck der frühzeitigen Warnung erfüllt und die Beendigung von Infektionsketten unterstützt.\n\nSeit dem 1. Juni 2023 wird die Corona-Warn-App nicht mehr weiterentwickelt. Sie können wei-terhin auf Ihre bereits vorhandenen Zertifikate und das Kontakt-Tagebuch zugreifen. Alle ande-ren Funktionen stehen nicht mehr zur Verfügung."; /* Home Test Registration Card */ diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index 2f60c7e96c6..9fadf51e1c1 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -9,9 +9,7 @@ class EndOfLifeThankYouCellViewModel { // MARK: - Internal var title = AppStrings.Home.EndOfLifeThankYouTile.title - // to.do get the xx value in figma - var description = String( - format: AppStrings.Home.EndOfLifeThankYouTile.description, 4) + var description = AppStrings.Home.EndOfLifeThankYouTile.description var image = UIImage(named: "EndOfLifeThankYouIllustration") var tintColor: UIColor = .enaColor(for: .textPrimary1) From d4384a951dd3f723522aa40e3dd1c5ae90896420 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Mon, 6 Mar 2023 12:13:51 +0100 Subject: [PATCH 079/137] fix text --- .../ENA/ENA/Resources/Localization/de.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings index 4197605e8b3..87ef7276fad 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings @@ -1525,7 +1525,7 @@ Bei ausgeschalteter Hintergrundaktualisierung müssen Sie die App täglich aufru "Home_EndOfLifeThankYouTile_Title" = "Vielen Dank!"; -"Home_EndOfLifeThankYouTile_description" = "Vielen Dank für die Nutzung der Corona-Warn-App. Während der Pandemie wurden durch die Nutzenden der Corona-Warn-App knapp 9 Millionen positive Testergebnisse geteilt. Durch diese Teilung positiver Testergebnisse konnten Personen schnell vor einem erhöhten Infektionsrisiko gewarnt werden, das sonst unerkannt geblieben wäre. Viele Gewarnte wurden anschließend positiv getestet. Die Corona-Warn-App hat dank Ihrer gemeinsamen Mithilfe ihren Zweck der frühzeitigen Warnung erfüllt und die Beendigung von Infektionsketten unterstützt.\n\nSeit dem 1. Juni 2023 wird die Corona-Warn-App nicht mehr weiterentwickelt. Sie können wei-terhin auf Ihre bereits vorhandenen Zertifikate und das Kontakt-Tagebuch zugreifen. Alle ande-ren Funktionen stehen nicht mehr zur Verfügung."; +"Home_EndOfLifeThankYouTile_description" = "Vielen Dank für die Nutzung der Corona-Warn-App. Während der Pandemie wurden durch die Nutzenden der Corona-Warn-App knapp 9 Millionen positive Testergebnisse geteilt. Durch diese Teilung positiver Testergebnisse konnten Personen schnell vor einem erhöhten Infektionsrisiko gewarnt werden, das sonst unerkannt geblieben wäre. Viele Gewarnte wurden anschließend positiv getestet. Die Corona-Warn-App hat dank Ihrer gemeinsamen Mithilfe ihren Zweck der frühzeitigen Warnung erfüllt und die Beendigung von Infektionsketten unterstützt.\n\nSeit dem 1. Juni 2023 wird die Corona-Warn-App nicht mehr weiterentwickelt. Sie können weiterhin auf Ihre bereits vorhandenen Zertifikate und das Kontakt-Tagebuch zugreifen. Alle anderen Funktionen stehen nicht mehr zur Verfügung."; /* Home Test Registration Card */ From 8be4612aae3d20baa374898a3b2e78e80380d9d8 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Mon, 6 Mar 2023 14:55:02 +0100 Subject: [PATCH 080/137] Update src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift --- src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift index 2eddec0cad5..318c80f447e 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/Route.swift @@ -4,7 +4,6 @@ import Foundation -// swiftlint:disable function_body_length enum Route: Equatable { // MARK: - Init From 0e55c434dbfd6bbfb47b25f9e7ce8b943de210c4 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 7 Mar 2023 05:52:36 +0100 Subject: [PATCH 081/137] update implementation to fix Local problem --- .../Source/AppDelegate & Globals/AppDelegate.swift | 14 ++++++++++---- .../Models/Task Scheduling/ENATaskScheduler.swift | 5 ----- .../Source/Protocols/RequiresAppDependencies.swift | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift index 2ebc1384eb4..e362d9a7f39 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift @@ -20,7 +20,7 @@ protocol CoronaWarnAppDelegate: AnyObject { var appConfigurationProvider: AppConfigurationProviding { get } var riskProvider: RiskProvider { get } var exposureManager: ExposureManager { get } - var taskScheduler: ENATaskScheduler { get } + var taskScheduler: ENATaskScheduler? { get } var environmentProvider: EnvironmentProviding { get } var contactDiaryStore: DiaryStoringProviding { get } @@ -161,7 +161,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re UIDevice.current.isBatteryMonitoringEnabled = true // Setting delegates - taskScheduler.delegate = taskExecutionDelegate + taskScheduler?.delegate = taskExecutionDelegate UNUserNotificationCenter.current().delegate = notificationManager // Setup DeadmanNotification after AppLaunch @@ -261,7 +261,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re func applicationDidEnterBackground(_ application: UIApplication) { showPrivacyProtectionWindow() if #available(iOS 13.0, *) { - taskScheduler.scheduleTask() + taskScheduler?.scheduleTask() } Log.info("Application did enter background.", log: .appLifecycle) } @@ -295,7 +295,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re let client: HTTPClient let cachingClient = CachingHTTPClient() let downloadedPackagesStore: DownloadedPackagesStore = DownloadedPackagesSQLLiteStore(fileName: "packages") - lazy var taskScheduler: ENATaskScheduler = { ENATaskScheduler.shared }() + var taskScheduler: ENATaskScheduler? { + guard !CWAHibernationProvider.shared.isHibernationState else { + Log.info("CWA is in hibernation state. Background tasks won't be executed.", log: .background) + return nil + } + return ENATaskScheduler.shared + } let contactDiaryStore: DiaryStoringProviding let eventStore: EventStoringProviding = { #if DEBUG diff --git a/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift b/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift index d5cc0a82d73..54604ea0dd6 100644 --- a/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift +++ b/src/xcode/ENA/ENA/Source/Models/Task Scheduling/ENATaskScheduler.swift @@ -41,11 +41,6 @@ final class ENATaskScheduler { // MARK: - Initializer. private init() { if #available(iOS 13.0, *) { - guard !CWAHibernationProvider.shared.isHibernationState else { - Log.info("CWA is in hibernation state. Background tasks won't be registered.", log: .api) - return - } - registerTask(with: .exposureNotification, execute: exposureNotificationTask(_:)) } } diff --git a/src/xcode/ENA/ENA/Source/Protocols/RequiresAppDependencies.swift b/src/xcode/ENA/ENA/Source/Protocols/RequiresAppDependencies.swift index 984b508223d..e7b40a18d7b 100644 --- a/src/xcode/ENA/ENA/Source/Protocols/RequiresAppDependencies.swift +++ b/src/xcode/ENA/ENA/Source/Protocols/RequiresAppDependencies.swift @@ -11,7 +11,7 @@ typealias DownloadedPackagesSQLLiteStore = DownloadedPackagesSQLLiteStoreV3 protocol RequiresAppDependencies { var client: HTTPClient { get } var store: Store { get } - var taskScheduler: ENATaskScheduler { get } + var taskScheduler: ENATaskScheduler? { get } var downloadedPackagesStore: DownloadedPackagesStore { get } var appConfigurationProvider: AppConfigurationProviding { get } var riskProvider: RiskProviding { get } @@ -43,7 +43,7 @@ extension RequiresAppDependencies { UIApplication.coronaWarnDelegate().exposureManager } - var taskScheduler: ENATaskScheduler { + var taskScheduler: ENATaskScheduler? { UIApplication.coronaWarnDelegate().taskScheduler } } From bc9de7609e72a0b00c2f7b8093d3c1552116cc95 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 7 Mar 2023 15:39:18 +0100 Subject: [PATCH 082/137] 14865: Antigen Profile Nav Tint Color --- .../AntigenTestProfileViewController.swift | 26 +++++++------------ ...TestProfileInformationViewController.swift | 4 +++ ...ntigenTestProfileInputViewController.swift | 4 +++ ...genTestProfileOverviewViewController.swift | 4 +-- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfile/AntigenTestProfileViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfile/AntigenTestProfileViewController.swift index 5fa5db5155c..8b79be255b6 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfile/AntigenTestProfileViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfile/AntigenTestProfileViewController.swift @@ -46,6 +46,15 @@ class AntigenTestProfileViewController: UIViewController, UITableViewDataSource, setupBackground() setupTableView() + + navigationItem.largeTitleDisplayMode = .never + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + setupNavigationBar(animated: animated) + tableView.reloadData() } override func viewWillDisappear(_ animated: Bool) { @@ -53,21 +62,7 @@ class AntigenTestProfileViewController: UIViewController, UITableViewDataSource, navigationController?.navigationBar.setBackgroundImage(originalBackgroundImage, for: .default) navigationController?.navigationBar.shadowImage = originalShadowImage - navigationController?.navigationBar.prefersLargeTitles = true - - if traitCollection.userInterfaceStyle == .dark { - navigationController?.navigationBar.tintColor = .enaColor(for: .textContrast) - } else { - navigationController?.navigationBar.tintColor = .enaColor(for: .tint) - } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - setupNavigationBar(animated: animated) - - tableView.reloadData() + navigationController?.navigationBar.tintColor = .enaColor(for: .tint) } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { @@ -207,7 +202,6 @@ class AntigenTestProfileViewController: UIViewController, UITableViewDataSource, navigationController?.navigationBar.isTranslucent = true navigationController?.view.backgroundColor = .clear - navigationController?.navigationBar.prefersLargeTitles = false navigationController?.navigationBar.sizeToFit() navigationItem.largeTitleDisplayMode = .never } diff --git a/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileInformation/AntigenTestProfileInformationViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileInformation/AntigenTestProfileInformationViewController.swift index d1b9ae5f23f..e2742735f7d 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileInformation/AntigenTestProfileInformationViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileInformation/AntigenTestProfileInformationViewController.swift @@ -31,6 +31,10 @@ class AntigenTestProfileInformationViewController: DynamicTableViewController, F navigationItem.title = viewModel.title navigationItem.rightBarButtonItem = dismissHandlingCloseBarButton + navigationItem.largeTitleDisplayMode = .always + + navigationController?.navigationBar.tintColor = .enaColor(for: .tint) + setupView() } diff --git a/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileInput/AntigenTestProfileInputViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileInput/AntigenTestProfileInputViewController.swift index 2a4da4c312d..a6d0897d415 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileInput/AntigenTestProfileInputViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileInput/AntigenTestProfileInputViewController.swift @@ -37,6 +37,10 @@ class AntigenTestProfileInputViewController: UITableViewController, FooterViewHa super.viewDidLoad() setupView() setupBindings() + + navigationItem.largeTitleDisplayMode = .always + + navigationController?.navigationBar.tintColor = .enaColor(for: .tint) } override func viewWillDisappear(_ animated: Bool) { diff --git a/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileOverview/AntigenTestProfileOverviewViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileOverview/AntigenTestProfileOverviewViewController.swift index 03df7dbf330..28bb55e30bd 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileOverview/AntigenTestProfileOverviewViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/AntigenTestProfile/AntigenTestProfileOverview/AntigenTestProfileOverviewViewController.swift @@ -56,9 +56,9 @@ class AntigenTestProfileOverviewViewController: UITableViewController, DismissHa super.viewWillAppear(animated) viewModel.refreshFromStore() - - parent?.navigationController?.navigationBar.prefersLargeTitles = true + parent?.navigationController?.navigationBar.sizeToFit() + navigationController?.navigationBar.tintColor = .enaColor(for: .tint) } override func viewDidAppear(_ animated: Bool) { From 8853badd53b203b20bc8a05342fcb753536282f4 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 7 Mar 2023 15:45:53 +0100 Subject: [PATCH 083/137] change expectations to extra long --- .../__tests__/HealthCertificateServiceTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/__tests__/HealthCertificateServiceTests.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/__tests__/HealthCertificateServiceTests.swift index ef55511d48a..0ceb9be8b30 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/__tests__/HealthCertificateServiceTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/__tests__/HealthCertificateServiceTests.swift @@ -2081,7 +2081,7 @@ class HealthCertificateServiceTests: CWATestCase { expectation.fulfill() } - waitForExpectations(timeout: .medium) + waitForExpectations(timeout: .extraLong) // To keep service in memory until expectation is fulfilled service.moveHealthCertificateToBin(vaccinationHealthCertificate) From 254aeca54440292dac56b9f05daf28ede926a388 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Tue, 7 Mar 2023 16:58:44 +0100 Subject: [PATCH 084/137] comment healthcertificate check --- .../Services/HealthCertificate/HealthCertificateService.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift index 76295858f27..bf941ccafad 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift @@ -836,7 +836,7 @@ class HealthCertificateService: HealthCertificateServiceServable { } ) } - if !CWAHibernationProvider.shared.isHibernationState { +// if !CWAHibernationProvider.shared.isHibernationState { dispatchGroup.enter() self.healthCertificateNotificationService.scheduleAdmissionStateChangedNotificationIfNeeded( for: person, @@ -845,7 +845,7 @@ class HealthCertificateService: HealthCertificateServiceServable { dispatchGroup.leave() } ) - } +// } dispatchGroup.notify(queue: .global()) { completion?() } From 52d6d47d3e0535180a7ab131b1e82679fad3b259 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Wed, 8 Mar 2023 15:37:55 +0100 Subject: [PATCH 085/137] Update the description text for `EndOfLifeThankYouCell` and prepare to give a tappable FAQ link inside of it. --- .../bg.lproj/Localizable.links.strings | 2 ++ .../de.lproj/Localizable.links.strings | 2 ++ .../en.lproj/Localizable.links.strings | 2 ++ .../pl.lproj/Localizable.links.strings | 2 ++ .../ro.lproj/Localizable.links.strings | 2 ++ .../tr.lproj/Localizable.links.strings | 2 ++ .../EndOfLifeThankYouCell.swift | 23 ++++++++++--- .../EndOfLifeThankYouCell.xib | 29 ++++++++-------- .../EndOfLifeThankYouCellViewModel.swift | 34 +++++++++++++++++-- .../ENA/Source/View Helpers/AppStrings.swift | 2 ++ 10 files changed, 78 insertions(+), 22 deletions(-) diff --git a/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.links.strings index 55b506635b0..5196e364eb0 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.links.strings @@ -67,3 +67,5 @@ "Stiko_VaccinationRecommendations" = "https://www.rki.de/stiko"; "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; + +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL diff --git a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.links.strings index 9299beebdce..4928b237f3c 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.links.strings @@ -69,3 +69,5 @@ "Stiko_VaccinationRecommendations" = "https://www.rki.de/stiko"; "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/de/faq/results/#warn_without_tan"; + +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL diff --git a/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.links.strings index 6f43cda99f4..6f344b57ee8 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.links.strings @@ -69,3 +69,5 @@ "Stiko_VaccinationRecommendations" = "https://www.rki.de/stiko"; "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; + +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL diff --git a/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.links.strings index 87ab62d088a..06ef125f466 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.links.strings @@ -67,3 +67,5 @@ "Stiko_VaccinationRecommendations" = "https://www.rki.de/stiko"; "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; + +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL diff --git a/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.links.strings index 77282f462df..593c53f2f34 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.links.strings @@ -67,3 +67,5 @@ "Stiko_VaccinationRecommendations" = "https://www.rki.de/stiko"; "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; + +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL diff --git a/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.links.strings index 14598e48157..7d07fc69362 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.links.strings @@ -67,3 +67,5 @@ "Stiko_VaccinationRecommendations" = "https://www.rki.de/stiko"; "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; + +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift index 35b42ab04c5..02c34a3132d 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -33,8 +33,8 @@ final class EndOfLifeThankYouCell: UITableViewCell { titleLabel.text = cellModel.title titleLabel.accessibilityIdentifier = cellModel.titleAccessibilityIdentifier - descriptionLabel.text = cellModel.description - descriptionLabel.accessibilityIdentifier = cellModel.descriptionAccessibilityIdentifier + descriptionTextView.attributedText = cellModel.description + descriptionTextView.accessibilityIdentifier = cellModel.descriptionAccessibilityIdentifier illustrationImageView.image = cellModel.image illustrationImageView.accessibilityIdentifier = cellModel.imageAccessibilityIdentifier @@ -43,22 +43,35 @@ final class EndOfLifeThankYouCell: UITableViewCell { // MARK: - Private private func setup() { + selectionStyle = .none updateIllustration(for: traitCollection) clipsToBounds = false + + descriptionTextView.isUserInteractionEnabled = true + descriptionTextView.isScrollEnabled = false + descriptionTextView.isEditable = false + descriptionTextView.adjustsFontForContentSizeCategory = true + descriptionTextView.delegate = self setupAccessibility() } private func updateIllustration(for traitCollection: UITraitCollection) { -illustrationImageView.isHidden = traitCollection.preferredContentSizeCategory >= .accessibilityLarge + illustrationImageView.isHidden = traitCollection.preferredContentSizeCategory >= .accessibilityLarge } private func setupAccessibility() { - cardView.accessibilityElements = [titleLabel as Any, descriptionLabel as Any, illustrationImageView as Any] + cardView.accessibilityElements = [titleLabel as Any, descriptionTextView as Any, illustrationImageView as Any] } @IBOutlet private weak var cardView: HomeCardView! @IBOutlet private weak var illustrationImageView: UIImageView! - @IBOutlet private weak var descriptionLabel: ENALabel! + @IBOutlet private weak var descriptionTextView: UITextView! @IBOutlet private weak var titleLabel: ENALabel! } + +extension EndOfLifeThankYouCell: UITextViewDelegate { + func textView(_ textView: UITextView, shouldInteractWith url: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + LinkHelper.open(url: url, interaction: interaction) == .allow + } +} diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib index ab81bdb15f3..a2168a1c37f 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib @@ -5,6 +5,7 @@ + @@ -32,19 +33,17 @@ - - + + - + + + @@ -69,7 +68,7 @@ - + @@ -77,9 +76,6 @@ - - - @@ -95,5 +91,8 @@ + + + diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index 9fadf51e1c1..35df94dfc3c 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -9,9 +9,39 @@ class EndOfLifeThankYouCellViewModel { // MARK: - Internal var title = AppStrings.Home.EndOfLifeThankYouTile.title - var description = AppStrings.Home.EndOfLifeThankYouTile.description + var image = UIImage(named: "EndOfLifeThankYouIllustration") - var tintColor: UIColor = .enaColor(for: .textPrimary1) + + var description: NSAttributedString { + let faqLinkText = AppStrings.Home.EndOfLifeThankYouTile.faqLinkText + let faqLinkAnchor = AppStrings.Home.EndOfLifeThankYouTile.faqLinkAnchor + + let string = String( + format: AppStrings.Home.EndOfLifeThankYouTile.description, + faqLinkText + ) + + let textAttributes: [NSAttributedString.Key: Any] = [ + .font: UIFont.enaFont(for: .body), + .foregroundColor: UIColor.enaColor(for: .textPrimary2) + ] + + + let attributedString = NSMutableAttributedString( + string: string, + attributes: textAttributes + ) + + // to.do 08.03.2023: wait for final decision whether the FAQ link is tappable or not + // attributedString.mark( + // faqLinkText, + // with: LinkHelper.urlString(suffix: faqLinkAnchor, type: .faq) + // ) + + return attributedString + } + + // MARK: - Accessibility var titleAccessibilityIdentifier = AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.titleLabel var descriptionAccessibilityIdentifier = AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel diff --git a/src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift b/src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift index 2089b5fcb2e..3d0bdb1f291 100644 --- a/src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift +++ b/src/xcode/ENA/ENA/Source/View Helpers/AppStrings.swift @@ -1103,6 +1103,8 @@ enum AppStrings { enum EndOfLifeThankYouTile { static let title = NSLocalizedString("Home_EndOfLifeThankYouTile_Title", comment: "") static let description = NSLocalizedString("Home_EndOfLifeThankYouTile_description", comment: "") + static let faqLinkText = NSLocalizedString("Home_EndOfLifeThankYouTile_faq", comment: "") + static let faqLinkAnchor = NSLocalizedString("Home_EndOfLifeThankYouTile_FAQLink", tableName: "Localizable.links", comment: "") } enum TestRegistration { From 1fb90c12a2bc001e81fe8736feaa5bf386bd3ce5 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Wed, 8 Mar 2023 16:02:00 +0100 Subject: [PATCH 086/137] Fix a background color issue in dark mode --- .../Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift index 02c34a3132d..b7536d2026f 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -51,6 +51,7 @@ final class EndOfLifeThankYouCell: UITableViewCell { descriptionTextView.isScrollEnabled = false descriptionTextView.isEditable = false descriptionTextView.adjustsFontForContentSizeCategory = true + descriptionTextView.backgroundColor = .clear descriptionTextView.delegate = self setupAccessibility() From 36e91454a35ae7c958107bb11ba6bbac79fa94e4 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 8 Mar 2023 16:23:10 +0100 Subject: [PATCH 087/137] bump Project version to 3.2.0 2 --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index 0f53155d2c1..40942a5f368 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -13181,7 +13181,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENACommunity.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = $IPHONE_APP_DEV_TEAM; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13336,7 +13336,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13515,7 +13515,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13757,7 +13757,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENATest.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13797,7 +13797,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info.plist; IPHONE_APP_CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -13940,7 +13940,7 @@ CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -13984,7 +13984,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -14027,7 +14027,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; From 603524e10c97b46b32d34dfc241a74ea2ecfd74c Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 8 Mar 2023 16:58:06 +0100 Subject: [PATCH 088/137] fix error --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 4 ++-- .../EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index ef54efa8ddc..1ca10e17dce 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -11,7 +11,7 @@ class CWAHibernationProvider: RequiresAppDependencies { /// Use shared instance instead private init() {} - #if DEBUG + #if !RELEASE /// For UI/Unit purposes only init(customStore: Store) { self.customStore = customStore @@ -59,7 +59,7 @@ class CWAHibernationProvider: RequiresAppDependencies { #endif } - #if DEBUG + #if !RELEASE /// For UI/Unit Test purposes only private var customStore: Store? #endif diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index 35df94dfc3c..78432964cfd 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -14,7 +14,7 @@ class EndOfLifeThankYouCellViewModel { var description: NSAttributedString { let faqLinkText = AppStrings.Home.EndOfLifeThankYouTile.faqLinkText - let faqLinkAnchor = AppStrings.Home.EndOfLifeThankYouTile.faqLinkAnchor + // let faqLinkAnchor = AppStrings.Home.EndOfLifeThankYouTile.faqLinkAnchor let string = String( format: AppStrings.Home.EndOfLifeThankYouTile.description, From ca97378b94959ea7e3f19130864db96d284b5e56 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 9 Mar 2023 13:09:17 +0100 Subject: [PATCH 089/137] check hibrnation after dispatching --- .../EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift | 1 - .../HealthCertificate/HealthCertificateService.swift | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index 78432964cfd..47530016978 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -14,7 +14,6 @@ class EndOfLifeThankYouCellViewModel { var description: NSAttributedString { let faqLinkText = AppStrings.Home.EndOfLifeThankYouTile.faqLinkText - // let faqLinkAnchor = AppStrings.Home.EndOfLifeThankYouTile.faqLinkAnchor let string = String( format: AppStrings.Home.EndOfLifeThankYouTile.description, diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift index bf941ccafad..8e7d8dd5ecf 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift @@ -825,8 +825,6 @@ class HealthCertificateService: HealthCertificateServiceServable { dispatchGroup.leave() } ) - } - if !CWAHibernationProvider.shared.isHibernationState { dispatchGroup.enter() self.healthCertificateNotificationService.scheduleCertificateReissuanceNotificationIfNeeded( for: person, @@ -835,8 +833,6 @@ class HealthCertificateService: HealthCertificateServiceServable { dispatchGroup.leave() } ) - } -// if !CWAHibernationProvider.shared.isHibernationState { dispatchGroup.enter() self.healthCertificateNotificationService.scheduleAdmissionStateChangedNotificationIfNeeded( for: person, @@ -845,7 +841,7 @@ class HealthCertificateService: HealthCertificateServiceServable { dispatchGroup.leave() } ) -// } + } dispatchGroup.notify(queue: .global()) { completion?() } From 92849a90c8a2bd54f74ff502ab86ec782a458ec1 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 9 Mar 2023 16:35:55 +0100 Subject: [PATCH 090/137] update dev menu logic to change the start of EOL --- .../CWAHibernationProvider.swift | 6 ++++- .../CWAHibernationProviderTests.swift | 4 +-- .../DMHibernationOptionsViewModel.swift | 25 ++++++++++--------- .../__tests__/Mocks/MockTestStore.swift | 2 +- .../Source/Workers/Store/SecureStore.swift | 6 ++--- .../ENA/ENA/Source/Workers/Store/Store.swift | 2 +- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 1ca10e17dce..0457fed83bc 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -28,7 +28,11 @@ class CWAHibernationProvider: RequiresAppDependencies { if isUITesting { return LaunchArguments.endOfLife.isHibernationStateEnabled.boolValue } - return secureStore.hibernationComparisonDate >= hibernationStartDate + Log.debug("current hibernationStartDate \(secureStore.hibernationStartDate)") + return secureStore.hibernationStartDate >= hibernationStartDate + #elseif !RELEASE + Log.debug("current hibernationStartDate \(secureStore.hibernationStartDate)") + return secureStore.hibernationStartDate >= hibernationStartDate #else return Date() >= hibernationStartDate #endif diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index 42ed3174a9e..47c857e4b0e 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -24,7 +24,7 @@ final class CWAHibernationProviderTests: CWATestCase { guard let hibernationComparisonDate = Calendar.current.date(from: beforeHibernationStartDateComponents) else { return XCTFail("Expect the hibernation comparison date from the corresponding date components.") } - mockTestStore.hibernationComparisonDate = hibernationComparisonDate + mockTestStore.hibernationStartDate = hibernationComparisonDate // THEN XCTAssertFalse(sut.isHibernationState) @@ -47,7 +47,7 @@ final class CWAHibernationProviderTests: CWATestCase { guard let hibernationComparisonDate = Calendar.current.date(from: afterHibernationStartDateComponents) else { return XCTFail("Expect the hibernation comparison date from the corresponding date components.") } - mockTestStore.hibernationComparisonDate = hibernationComparisonDate + mockTestStore.hibernationStartDate = hibernationComparisonDate // THEN XCTAssertTrue(sut.isHibernationState) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index c11ece6da82..87deb0a22a3 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -12,7 +12,7 @@ class DMHibernationOptionsViewModel { init(store: Store) { self.store = store - self.hibernationComparisonDateSelected = store.hibernationComparisonDate + self.hibernationComparisonDateSelected = store.hibernationStartDate } // MARK: - Internal @@ -29,8 +29,8 @@ class DMHibernationOptionsViewModel { } switch section { - case .hibernationComparisonDate: - return "App will shutdown after selecting a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationComparisonDate))" + case .hibernationStartDate: + return "App will shutdown after selecting a new date value in the date picker.\n\nCurrently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationStartDate))" case .storeButton: return nil case .reset: @@ -44,12 +44,12 @@ class DMHibernationOptionsViewModel { } switch section { - case .hibernationComparisonDate: + case .hibernationStartDate: return DMDatePickerCellViewModel( - title: "Hibernation Comparison Date", + title: "Hibernation Start Date", accessibilityIdentifier: AccessibilityIdentifiers.DeveloperMenu.Hibernation.datePicker, datePickerMode: .dateAndTime, - date: store.hibernationComparisonDate + date: store.hibernationStartDate ) case .storeButton: return DMButtonCellViewModel( @@ -58,7 +58,7 @@ class DMHibernationOptionsViewModel { backgroundColor: .enaColor(for: .buttonPrimary) ) { [weak self] in guard let self = self else { return } - self.store(hibernationComparisonDate: self.hibernationComparisonDateSelected) + self.store(hibernationStartDate: self.hibernationComparisonDateSelected) } case .reset: return DMButtonCellViewModel( @@ -66,7 +66,7 @@ class DMHibernationOptionsViewModel { textColor: .white, backgroundColor: .enaColor(for: .buttonDestructive) ) { [weak self] in - self?.store(hibernationComparisonDate: Date()) + self?.store(hibernationStartDate: Date()) } } } @@ -81,9 +81,10 @@ class DMHibernationOptionsViewModel { return dateFormatter }() - private func store(hibernationComparisonDate: Date) { - Log.debug("[Debug-Menu] Set hibernation comparison date to: \(dateFormatter.string(from: hibernationComparisonDate)).") - store.hibernationComparisonDate = hibernationComparisonDate + private func store(hibernationStartDate: Date) { + Log.debug("[Debug-Menu] Set hibernation comparison date to: \(dateFormatter.string(from: hibernationStartDate)).") + store.hibernationStartDate = hibernationStartDate + Log.debug("did save ") exitApp() } @@ -98,7 +99,7 @@ class DMHibernationOptionsViewModel { extension DMHibernationOptionsViewModel { enum Sections: Int, CaseIterable { /// The date, that will be used to compare it against the hibernation start date. - case hibernationComparisonDate + case hibernationStartDate /// Store the set hibernation comparison date case storeButton /// Reset the stored fake date, the hibernation threshold compares to. diff --git a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift index 8b7dcea598b..6375c8275b5 100644 --- a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift +++ b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift @@ -63,7 +63,7 @@ final class MockTestStore: Store, PPAnalyticsData { var forceAPITokenAuthorization = false var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? var isSrsPrechecksEnabled = false - var hibernationComparisonDate = Date() + var hibernationStartDate = Date() #endif // MARK: - AppConfigCaching diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift index efdb0073791..33e72b56cd6 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift @@ -378,9 +378,9 @@ final class SecureStore: SecureKeyValueStoring, Store { set { kvStore["recentTraceLocationCheckedInto"] = newValue } } - var hibernationComparisonDate: Date { - get { kvStore["hibernationComparisonDate"] as Date? ?? Date() } - set { kvStore["hibernationComparisonDate"] = newValue } + var hibernationStartDate: Date { + get { kvStore["hibernationStartDate"] as Date? ?? Date() } + set { kvStore["hibernationStartDate"] = newValue } } #endif diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift index 275c0376d81..3b39c6bf772 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift @@ -87,7 +87,7 @@ protocol StoreProtocol: AnyObject { var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? { get set } - var hibernationComparisonDate: Date { get set } + var hibernationStartDate: Date { get set } #endif From a87fc7016e889f6b5cb7a5c2372bb78b65ce6288 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 9 Mar 2023 16:40:45 +0100 Subject: [PATCH 091/137] fix logic --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 0457fed83bc..9d44f83bc5f 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -29,10 +29,10 @@ class CWAHibernationProvider: RequiresAppDependencies { return LaunchArguments.endOfLife.isHibernationStateEnabled.boolValue } Log.debug("current hibernationStartDate \(secureStore.hibernationStartDate)") - return secureStore.hibernationStartDate >= hibernationStartDate + return secureStore.hibernationStartDate >= Date() #elseif !RELEASE Log.debug("current hibernationStartDate \(secureStore.hibernationStartDate)") - return secureStore.hibernationStartDate >= hibernationStartDate + return secureStore.hibernationStartDate >= Date() #else return Date() >= hibernationStartDate #endif From 43a13af6e3fbe7b43d97a5a615ab02071264393b Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 9 Mar 2023 19:27:59 +0100 Subject: [PATCH 092/137] bump version to 3.2.0 3 --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index 40942a5f368..33ced980a7b 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -13181,7 +13181,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENACommunity.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = $IPHONE_APP_DEV_TEAM; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13336,7 +13336,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13515,7 +13515,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13757,7 +13757,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENATest.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13797,7 +13797,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info.plist; IPHONE_APP_CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -13940,7 +13940,7 @@ CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -13984,7 +13984,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -14027,7 +14027,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; From c8c461662109334bf83119efe98fa99efeccc096 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 10 Mar 2023 09:09:42 +0100 Subject: [PATCH 093/137] 14904: `MoreActionItemView` is now configurable to hide separator view. --- .../Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift index 8773a6a1be1..0649be22792 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift @@ -34,7 +34,10 @@ class HomeMoreInfoTableViewCell: UITableViewCell { let nib = UINib(nibName: nibName, bundle: .main) if let actionItemView = nib.instantiate(withOwner: self, options: nil).first as? MoreActionItemView { - actionItemView.configure(actionItem: item) { selectedItem in + actionItemView.configure( + actionItem: item, + hideSeparatorView: item == items.last // index == items.count - 1 + ) { selectedItem in onItemTap(selectedItem) } stackView.addArrangedSubview(actionItemView) From 5775bb37c3fcca7d32ba9b7ec8c808ad41b2a8f7 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 10 Mar 2023 09:09:57 +0100 Subject: [PATCH 094/137] 14904: `MoreActionItemView` is now configurable to hide separator view. --- .../Home/Cells/More/MoreActionItem/MoreActionItemView.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/MoreActionItem/MoreActionItemView.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/MoreActionItem/MoreActionItemView.swift index cc255606827..1de706c213e 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/MoreActionItem/MoreActionItemView.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/MoreActionItem/MoreActionItemView.swift @@ -23,6 +23,7 @@ class MoreActionItemView: UIView { func configure( actionItem: MoreInfoItem, + hideSeparatorView: Bool = false, completion: @escaping ((MoreInfoItem) -> Void) ) { imageView.image = actionItem.image @@ -31,7 +32,7 @@ class MoreActionItemView: UIView { accessibilityIdentifier = actionItem.accessibilityIdentifier accessibilityLabel = actionItem.title - separatorView.isHidden = actionItem == .share + separatorView.isHidden = hideSeparatorView self.actionItem = actionItem self.completion = completion From 8d249e64cf0d194b976386443ded2b8eb92b89a4 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 10 Mar 2023 09:13:14 +0100 Subject: [PATCH 095/137] 14904: Remove unused code. --- .../Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift index 0649be22792..d570429cdaa 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/More/HomeMoreInfoTableViewCell.swift @@ -36,7 +36,7 @@ class HomeMoreInfoTableViewCell: UITableViewCell { if let actionItemView = nib.instantiate(withOwner: self, options: nil).first as? MoreActionItemView { actionItemView.configure( actionItem: item, - hideSeparatorView: item == items.last // index == items.count - 1 + hideSeparatorView: item == items.last ) { selectedItem in onItemTap(selectedItem) } From fa1334a0734d20655d7ed409da6d64ae9653c8d9 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 10 Mar 2023 09:29:19 +0100 Subject: [PATCH 096/137] 14905: Fix some spacing issues. --- .../Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib index a2168a1c37f..74c201560f3 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib @@ -34,10 +34,10 @@ - + - + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -50,10 +50,14 @@ + + + + From 223c2b17e109eadcbff32655024dd2ed9bf6a9d5 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 10 Mar 2023 11:02:27 +0100 Subject: [PATCH 097/137] 14903: Adapt `EndOfLifeThankYouCell` for dark mode and trait collection accessibility large. --- .../Contents.json | 3 +- .../EndOfLifeThankYouIllustration-dark.pdf | Bin 0 -> 45207 bytes ...> EndOfLifeThankYouIllustration-light.pdf} | Bin .../EndOfLifeThankYouCell.swift | 30 ++++++++++++++---- .../EndOfLifeThankYouCell.xib | 28 ++++++++++++---- .../Scenes/Home/Views/HomeCardView.swift | 10 +++--- 6 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration-dark.pdf rename src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/{EndOfLifeThankYouIllustration.pdf => EndOfLifeThankYouIllustration-light.pdf} (100%) diff --git a/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/Contents.json b/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/Contents.json index cff99bbf028..ca5901301f3 100644 --- a/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/Contents.json +++ b/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "EndOfLifeThankYouIllustration.pdf", + "filename" : "EndOfLifeThankYouIllustration-light.pdf", "idiom" : "universal" }, { @@ -11,6 +11,7 @@ "value" : "dark" } ], + "filename" : "EndOfLifeThankYouIllustration-dark.pdf", "idiom" : "universal" } ], diff --git a/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration-dark.pdf b/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration-dark.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b07e3961bee03c44d2b365fddb69ada1b53ee344 GIT binary patch literal 45207 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 ArvLx| literal 0 HcmV?d00001 diff --git a/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration.pdf b/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration-light.pdf similarity index 100% rename from src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration.pdf rename to src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration-light.pdf diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift index b7536d2026f..39a252a3bf6 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -11,19 +11,19 @@ final class EndOfLifeThankYouCell: UITableViewCell { override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() - setup() + setupView() } override func awakeFromNib() { super.awakeFromNib() - setup() + setupView() } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - updateIllustration(for: traitCollection) + updateView(for: traitCollection) } @@ -33,6 +33,9 @@ final class EndOfLifeThankYouCell: UITableViewCell { titleLabel.text = cellModel.title titleLabel.accessibilityIdentifier = cellModel.titleAccessibilityIdentifier + titleLabelAccessibilityLarge.text = cellModel.title + titleLabelAccessibilityLarge.accessibilityIdentifier = cellModel.titleAccessibilityIdentifier + descriptionTextView.attributedText = cellModel.description descriptionTextView.accessibilityIdentifier = cellModel.descriptionAccessibilityIdentifier @@ -42,10 +45,13 @@ final class EndOfLifeThankYouCell: UITableViewCell { // MARK: - Private - private func setup() { + private func setupView() { selectionStyle = .none - updateIllustration(for: traitCollection) - clipsToBounds = false + updateView(for: traitCollection) + + illustrationImageView.clipsToBounds = true + illustrationImageView.layer.cornerRadius = HomeCardView.cornerRadius + illustrationImageView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] descriptionTextView.isUserInteractionEnabled = true descriptionTextView.isScrollEnabled = false @@ -57,8 +63,13 @@ final class EndOfLifeThankYouCell: UITableViewCell { setupAccessibility() } - private func updateIllustration(for traitCollection: UITraitCollection) { + private func updateView(for traitCollection: UITraitCollection) { + let stackViewTopHeight: CGFloat = traitCollection.preferredContentSizeCategory >= .accessibilityLarge ? 20 : 0 + stackViewTopConstraint.constant = stackViewTopHeight + illustrationImageView.isHidden = traitCollection.preferredContentSizeCategory >= .accessibilityLarge + titleLabel.isHidden = traitCollection.preferredContentSizeCategory >= .accessibilityLarge + titleLabelAccessibilityLarge.isHidden = traitCollection.preferredContentSizeCategory < .accessibilityLarge } private func setupAccessibility() { @@ -69,8 +80,13 @@ final class EndOfLifeThankYouCell: UITableViewCell { @IBOutlet private weak var illustrationImageView: UIImageView! @IBOutlet private weak var descriptionTextView: UITextView! @IBOutlet private weak var titleLabel: ENALabel! + @IBOutlet private weak var titleLabelAccessibilityLarge: ENALabel! + @IBOutlet private weak var stackViewTopConstraint: NSLayoutConstraint! + } +// MARK: - UITextViewDelegate + extension EndOfLifeThankYouCell: UITextViewDelegate { func textView(_ textView: UITextView, shouldInteractWith url: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { LinkHelper.open(url: url, interaction: interaction) == .allow diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib index 74c201560f3..10078df6c4b 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib @@ -22,10 +22,10 @@ - + - + - + + + + @@ -74,7 +86,9 @@ + + diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Views/HomeCardView.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Views/HomeCardView.swift index 6ac935d6eb8..5094ebf4169 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Views/HomeCardView.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Views/HomeCardView.swift @@ -32,21 +32,21 @@ class HomeCardView: UIView { } // MARK: - Internal - + + static let cornerRadius: CGFloat = 14.0 + func setHighlighted(_ highlighted: Bool, animated: Bool) { highlightView.backgroundColor = highlighted ? .enaColor(for: .listHighlight) : .clear } // MARK: - Private - private let cornerRadius: CGFloat = 14.0 - private let highlightView = UIView() private func setupView() { translatesAutoresizingMaskIntoConstraints = false clipsToBounds = false - layer.cornerRadius = cornerRadius + layer.cornerRadius = Self.cornerRadius layer.shadowColor = UIColor.enaColor(for: .shadow).cgColor layer.shadowOffset = .init(width: 0.0, height: 10.0) @@ -54,7 +54,7 @@ class HomeCardView: UIView { layer.shadowOpacity = 1 highlightView.backgroundColor = .clear - highlightView.layer.cornerRadius = cornerRadius + highlightView.layer.cornerRadius = Self.cornerRadius highlightView.isUserInteractionEnabled = false From 51c72a61401c73608c00774dd88e78a011499bb7 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 10 Mar 2023 12:02:03 +0100 Subject: [PATCH 098/137] 14903: Change EndOfLifeThankYouIllustration-light to correct image version. --- .../EndOfLifeThankYouIllustration-light.pdf | Bin 40032 -> 43149 bytes .../EndOfLifeThankYouCell.xib | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration-light.pdf b/src/xcode/ENA/ENA/Resources/Assets/Assets.xcassets/Illustrations/EndOfLifeThankYouIllustration.imageset/EndOfLifeThankYouIllustration-light.pdf index f645d29cf742cfee90156f0dc33142fcad1cbf3f..166cea067d4d2f0e384f41309d79c9351e3d403d 100644 GIT binary patch delta 4965 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 CU7Lsi delta 2148 zcmZuyOKg=@5YB%K?d?U71`%jT`Q_fWw$T5c_d^g7gAXWDo~A&8m0nAUwh3*u7NORl zgvOHUQ6kTRhKI&P%n9+aAVwsS6_Eu#NWjF6xRAJzg@owLxq#HrP22hB%zX3BH#0-u zr+)b&H9X~kdGj)bj@HiSHf1s_CNcgI$8+b#`Nl#=TldD8yS+ym+@;c_oSVcj!Kn40 zqKyjI=-= z@-jGUe6Rp=T4dpy+4n@HfSn5A9^GE+uQxOxb6OZ8bRc|1J~V|YWX=zgvtywlibAav zW4dkX3Z&J{NUD6Nex)RQ4zRF;ljdBF(ju{%AYBNe;oX_G0%QF4#6i@B;RIVAHD�Po0m(0O`t&EU9xR79WCuR541d zt7y*pEsZfIHJW2x70os7)0L&rgUd(|!~i(shE$NF5x3#1r-#(yUg<6 zp%^8BVi6w9SkV%dYMUq~T}4^mom}}VIB)~(uz>6Is;?sGD%ZvmH?g_KfBejPR8xQ^ zd`0tw@E`D{Ap)dWwB`yR;G98^+?=(i%OScnq0TvLv#x&KX{bzURE+;?-B=_>7nP5n ztJm))KX334fvW`LM(U!4@?^sJSlXGfhTaT1;5kQe}}R7{4TCqQzC3kIlv@DLU0Y^ zEHnaQiR7G6jmdRlDX5tubVjK`7`PoIQ37h@)N&<9o8}j7@c1r{8b(QQ$OjZF;7McE zR*j;}=UWz)gpQyd{XlCHm2prAsMnFIod3DdhEfEqIPEC;7usG&OIU9LT9|dy+Rvk^ zibK;qKkM(`baGs&f*G*f?Ha1~*Lv3AlxS^nVbQ8;zxCzSs6+*_AjDtn)nQrTaxlKK zZ)G%=0CwtzhHCttElp7xx@rli(Es`B)~H-qXfhhYi0<8X15~1vA~2#O{pWDlq!2jI zFAbc*-DwRf)(x~)`;FTtq;M!Wh703)_)XXVXhBWFuF3lAJDPFh1-P!MHs||yHloU@ z2IaU8o%7cQpTrHygge($>)YR&fhxDeKmFm8{mYdmlY zT8!6(+VDgk`~X%bTV - + From 15458b1cf1a6ff50dd8680749c5a3ee79bd91a65 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 10 Mar 2023 12:06:16 +0100 Subject: [PATCH 099/137] 14903: Update accessibility elements dependent from traitCollection. --- .../Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift index 39a252a3bf6..6c5c1d28e0f 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -24,6 +24,7 @@ final class EndOfLifeThankYouCell: UITableViewCell { super.traitCollectionDidChange(previousTraitCollection) updateView(for: traitCollection) + setupAccessibility() } @@ -73,7 +74,11 @@ final class EndOfLifeThankYouCell: UITableViewCell { } private func setupAccessibility() { - cardView.accessibilityElements = [titleLabel as Any, descriptionTextView as Any, illustrationImageView as Any] + if traitCollection.preferredContentSizeCategory >= .accessibilityLarge { + cardView.accessibilityElements = [titleLabelAccessibilityLarge as Any, descriptionTextView as Any, illustrationImageView as Any] + } else { + cardView.accessibilityElements = [titleLabel as Any, descriptionTextView as Any, illustrationImageView as Any] + } } @IBOutlet private weak var cardView: HomeCardView! From a69ee2def8276a11edd647d627b74c7d02898ed6 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Fri, 10 Mar 2023 12:47:43 +0100 Subject: [PATCH 100/137] 14902: Do nothing in `HomeTableViewController` when the user taps on `EndOfLifeThankYouCell`. --- .../ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 0268b31dd04..2b43fc07250 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -285,7 +285,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega onTestRegistrationCellTap() case .traceLocations: onTraceLocationsCellTap() - case .statistics, .moreInfo: + case .statistics, .moreInfo, .endOfLifeThankYou: break default: fatalError("Invalid section") From 9598747235c6bcd842d087cc4add92d8bb072030 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Sat, 11 Mar 2023 09:07:41 +0100 Subject: [PATCH 101/137] 14901: Hide app closure notice also if should show by ccl config when hibernation is given. --- .../Scenes/Home/HomeTableViewModel.swift | 6 +- .../__tests__/HomeTableViewModelTests.swift | 82 ++++++++++++++++--- 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift index 00b23de0bbf..dd9420a4933 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift @@ -129,7 +129,11 @@ class HomeTableViewModel { return 1 } #endif - return shouldShowAppClosureNotice ? 1 : 0 + if shouldShowAppClosureNotice, !isHibernationState { + return 1 + } else { + return 0 + } case .exposureLogging: return !isHibernationState ? 1 : 0 case .riskAndTestResults: diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift index a89f4a0c988..c8ef3e5e2dc 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift @@ -10,10 +10,11 @@ import HealthCertificateToolkit // swiftlint:disable type_body_length class HomeTableViewModelTests: CWATestCase { - func testSectionsRowsAndHeightsInHibernation() throws { + func testNumberOfSections_isHibernation_true_showAppClosureNotice_false() throws { + // GIVEN let store = MockTestStore() - let viewModel = HomeTableViewModel( + let sut = HomeTableViewModel( state: .init( store: store, riskProvider: MockRiskProvider(), @@ -36,22 +37,77 @@ class HomeTableViewModelTests: CWATestCase { onTestResultCellTap: { _ in }, badgeWrapper: .fake() ) + + // WHEN - // Number of Rows per Section - viewModel.isHibernationState = true + // Is hibernation and should not show app closure notice + sut.isHibernationState = true + sut.shouldShowAppClosureNotice = false + + // THEN // Number of Sections - XCTAssertEqual(viewModel.numberOfSections, 8) + XCTAssertEqual(sut.numberOfSections, 8) + + // Number of Rows + XCTAssertEqual(sut.numberOfRows(in: 0), 1) // end of life tile visible + XCTAssertEqual(sut.numberOfRows(in: 1), 0) // app closure notice invisible + XCTAssertEqual(sut.numberOfRows(in: 2), 0) // exposure Logging invisible + XCTAssertEqual(sut.numberOfRows(in: 3), 0) // riskAndTestResults invisible + XCTAssertEqual(sut.numberOfRows(in: 4), 0) // testRegistration invisible + XCTAssertEqual(sut.numberOfRows(in: 5), 1) // statistics visible + XCTAssertEqual(sut.numberOfRows(in: 6), 0) // traceLocations invisible + XCTAssertEqual(sut.numberOfRows(in: 7), 1) // moreInfo visible + } + + func testNumberOfSections_isHibernation_true_showAppClosureNotice_true() throws { + // GIVEN + let store = MockTestStore() + + let sut = HomeTableViewModel( + state: .init( + store: store, + riskProvider: MockRiskProvider(), + exposureManagerState: .init(authorized: true, enabled: true, status: .active), + enState: .enabled, + statisticsProvider: StatisticsProvider( + client: CachingHTTPClientMock(), + store: store + ), + localStatisticsProvider: LocalStatisticsProvider( + client: CachingHTTPClientMock(), + store: store + ) + ), + store: store, + appConfiguration: CachedAppConfigurationMock(), + coronaTestService: MockCoronaTestService(), + familyMemberCoronaTestService: MockFamilyMemberCoronaTestService(), + cclService: FakeCCLService(), + onTestResultCellTap: { _ in }, + badgeWrapper: .fake() + ) + + // WHEN + + // Is hibernation and should show app closure notice + sut.isHibernationState = true + sut.shouldShowAppClosureNotice = true + + // THEN + + // Number of Sections + XCTAssertEqual(sut.numberOfSections, 8) // Number of Rows - XCTAssertEqual(viewModel.numberOfRows(in: 0), 1) // end of life tile visible - XCTAssertEqual(viewModel.numberOfRows(in: 1), 0) // app closure notice invisible - XCTAssertEqual(viewModel.numberOfRows(in: 2), 0) // exposure Logging invisible - XCTAssertEqual(viewModel.numberOfRows(in: 3), 0) // riskAndTestResults invisible - XCTAssertEqual(viewModel.numberOfRows(in: 4), 0) // testRegistration invisible - XCTAssertEqual(viewModel.numberOfRows(in: 5), 1) // statistics visible - XCTAssertEqual(viewModel.numberOfRows(in: 6), 0) // traceLocations invisible - XCTAssertEqual(viewModel.numberOfRows(in: 7), 1) // moreInfo visible + XCTAssertEqual(sut.numberOfRows(in: 0), 1) // end of life tile visible + XCTAssertEqual(sut.numberOfRows(in: 1), 0) // app closure notice invisible in hibernation although should show + XCTAssertEqual(sut.numberOfRows(in: 2), 0) // exposure Logging invisible + XCTAssertEqual(sut.numberOfRows(in: 3), 0) // riskAndTestResults invisible + XCTAssertEqual(sut.numberOfRows(in: 4), 0) // testRegistration invisible + XCTAssertEqual(sut.numberOfRows(in: 5), 1) // statistics visible + XCTAssertEqual(sut.numberOfRows(in: 6), 0) // traceLocations invisible + XCTAssertEqual(sut.numberOfRows(in: 7), 1) // moreInfo visible } func testSectionsRowsAndHeights() throws { From 6b4dde69d0c89091a01674a547d1b92423600081 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Sat, 11 Mar 2023 14:54:12 +0100 Subject: [PATCH 102/137] 14907: Search for Diary ViewControllers in the TabBar view controllers to open via QuickAction. --- .../AppDelegate+QuickActions.swift | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate+QuickActions.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate+QuickActions.swift index e86a59a55a2..d61ce81ab69 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate+QuickActions.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate+QuickActions.swift @@ -141,8 +141,19 @@ extension AppDelegate { case QuickAction.diaryNewEntry.rawValue: Log.info("Shortcut: Open new diary entry", log: .ui) - guard let tabBarController = coordinator.tabBarController else { return } - tabBarController.selectedIndex = 4 + guard let tabBarController = coordinator.tabBarController, let viewControllers = tabBarController.viewControllers else { return } + + guard let diaryOverviewTableViewControllerIndex = viewControllers.lastIndex(where: { + if let topViewController = ($0 as? UINavigationController)?.topViewController { + return topViewController is DiaryOverviewTableViewController || topViewController is DiaryDayViewController + } else { + return false + } + }) else { + return + } + + tabBarController.selectedIndex = diaryOverviewTableViewControllerIndex // dismiss an overlaying, modally presented view controller coordinator.diaryCoordinator?.viewController.presentedViewController?.dismiss(animated: false, completion: nil) From d697c1a4078359e7d4ab6dcbf3a4aab060080231 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Sat, 11 Mar 2023 15:08:58 +0100 Subject: [PATCH 103/137] 14907: Select quick action Tabbar index by corresponding localized title. --- .../AppDelegate+QuickActions.swift | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate+QuickActions.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate+QuickActions.swift index d61ce81ab69..31cb49ba047 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate+QuickActions.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate+QuickActions.swift @@ -111,11 +111,17 @@ extension AppDelegate { /// - Parameter shortcutItem: the item to launch func handleShortcutItem(_ shortcutItem: UIApplicationShortcutItem) { Log.debug("Did open app via shortcut \(shortcutItem.type)", log: .ui) + + guard let tabBarController = coordinator.tabBarController else { return } + switch shortcutItem.type { case QuickAction.qrCodeScanner.rawValue: Log.info("Shortcut: QR code scanner", log: .ui) - guard let tabBarController = coordinator.tabBarController else { return } - tabBarController.selectedIndex = 0 + + guard let indexToSelect = tabBarController.tabBar.items?.firstIndex(where: { $0.title == AppStrings.Tabbar.scannerTitle }) else { + return + } + tabBarController.selectedIndex = indexToSelect // dismiss an overlaying, modally presented view controller coordinator.checkinTabCoordinator?.viewController.presentedViewController?.dismiss(animated: false, completion: nil) @@ -125,35 +131,33 @@ extension AppDelegate { case QuickAction.showCertificates.rawValue: Log.info("Shortcut: Certificates", log: .ui) - guard let tabBarController = coordinator.tabBarController else { return } - tabBarController.selectedIndex = 1 + + guard let indexToSelect = tabBarController.tabBar.items?.firstIndex(where: { $0.title == AppStrings.Tabbar.certificatesTitle }) else { + return + } + tabBarController.selectedIndex = indexToSelect // dismiss an overlaying, modally presented view controller coordinator.checkinTabCoordinator?.viewController.presentedViewController?.dismiss(animated: false, completion: nil) case QuickAction.eventCheckin.rawValue: Log.info("Shortcut: Event checkin 📷", log: .ui) - guard let tabBarController = coordinator.tabBarController else { return } - tabBarController.selectedIndex = 3 + + guard let indexToSelect = tabBarController.tabBar.items?.firstIndex(where: { $0.title == AppStrings.Tabbar.checkInTitle }) else { + return + } + tabBarController.selectedIndex = indexToSelect // dismiss an overlaying, modally presented view controller coordinator.checkinTabCoordinator?.viewController.presentedViewController?.dismiss(animated: false, completion: nil) case QuickAction.diaryNewEntry.rawValue: Log.info("Shortcut: Open new diary entry", log: .ui) - guard let tabBarController = coordinator.tabBarController, let viewControllers = tabBarController.viewControllers else { return } - - guard let diaryOverviewTableViewControllerIndex = viewControllers.lastIndex(where: { - if let topViewController = ($0 as? UINavigationController)?.topViewController { - return topViewController is DiaryOverviewTableViewController || topViewController is DiaryDayViewController - } else { - return false - } - }) else { + + guard let indexToSelect = tabBarController.tabBar.items?.firstIndex(where: { $0.title == AppStrings.Tabbar.diaryTitle }) else { return } - - tabBarController.selectedIndex = diaryOverviewTableViewControllerIndex + tabBarController.selectedIndex = indexToSelect // dismiss an overlaying, modally presented view controller coordinator.diaryCoordinator?.viewController.presentedViewController?.dismiss(animated: false, completion: nil) From e3ecd40de1ae1025fcf558db2212846985c6d2c6 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Sat, 11 Mar 2023 15:37:37 +0100 Subject: [PATCH 104/137] 14901: Swiftlint --- .../Scenes/Home/HomeTableViewModel.swift | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift index dd9420a4933..283455d1f1d 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift @@ -124,16 +124,7 @@ class HomeTableViewModel { case .endOfLifeThankYou: return isHibernationState ? 1 : 0 case .appClosureNotice: - #if DEBUG - if isUITesting, LaunchArguments.appClosureNotice.showAppClosureNoticeTile.boolValue { - return 1 - } - #endif - if shouldShowAppClosureNotice, !isHibernationState { - return 1 - } else { - return 0 - } + return numberOfRowsForAppClosureNotice() case .exposureLogging: return !isHibernationState ? 1 : 0 case .riskAndTestResults: @@ -369,4 +360,16 @@ class HomeTableViewModel { } } + private func numberOfRowsForAppClosureNotice() -> Int { + #if DEBUG + if isUITesting, LaunchArguments.appClosureNotice.showAppClosureNoticeTile.boolValue { + return 1 + } + #endif + if shouldShowAppClosureNotice, !isHibernationState { + return 1 + } else { + return 0 + } + } } From b57129c4f3725d401caa728ae97e80a0abc030af Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Sun, 12 Mar 2023 09:29:43 +0100 Subject: [PATCH 105/137] 14909: Hibernation Start Date can be set freely. --- .../CWAHibernationProvider.swift | 26 ++++++++---- .../CWAHibernationProviderTests.swift | 42 ++++++------------- .../DMHibernationOptionsViewController.swift | 4 +- .../DMHibernationOptionsViewModel.swift | 37 ++++++++-------- .../__tests__/Mocks/MockTestStore.swift | 2 +- .../Source/Workers/Store/SecureStore.swift | 6 +-- .../ENA/ENA/Source/Workers/Store/Store.swift | 2 +- 7 files changed, 58 insertions(+), 61 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index ef54efa8ddc..17db49a9910 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -28,14 +28,11 @@ class CWAHibernationProvider: RequiresAppDependencies { if isUITesting { return LaunchArguments.endOfLife.isHibernationStateEnabled.boolValue } - return secureStore.hibernationComparisonDate >= hibernationStartDate - #else - return Date() >= hibernationStartDate #endif + return Date() >= hibernationStartDateForBuild } - /// CWA hibernation threshold date. - private let hibernationStartDate: Date = { + let hibernationStartDateDefault: Date = { var hibernationStartDateComponents = DateComponents() hibernationStartDateComponents.year = 2023 hibernationStartDateComponents.month = 5 @@ -44,13 +41,28 @@ class CWAHibernationProvider: RequiresAppDependencies { hibernationStartDateComponents.minute = 0 hibernationStartDateComponents.second = 0 - guard let hibernationStartDate = Calendar.current.date(from: hibernationStartDateComponents) else { + guard let hibernationStartDateDefault = Calendar.current.date(from: hibernationStartDateComponents) else { fatalError("The hibernation start date couldn't be created.") } - return hibernationStartDate + return hibernationStartDateDefault }() + /// CWA hibernation threshold date. + var hibernationStartDateForBuild: Date { + #if DEBUG + Log.debug("current hibernationStartDate \(String(describing: secureStore.hibernationStartDate))") + return secureStore.hibernationStartDate ?? hibernationStartDateDefault + + #elseif !RELEASE + Log.debug("current hibernationStartDate \(String(describing: secureStore.hibernationStartDate))") + return secureStore.hibernationStartDate ?? hibernationStartDateDefault + + #else + return hibernationStartDateDefault + #endif + } + private var secureStore: Store { #if RELEASE return store diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift index 42ed3174a9e..7657078d246 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/__tests__/CWAHibernationProviderTests.swift @@ -7,49 +7,31 @@ import XCTest final class CWAHibernationProviderTests: CWATestCase { - func testIsHibernationState_Store_HibernationComparisonDate_before_false() throws { + func testIsHibernationState_HibernationStartDate_beforeSystemDate_true() throws { // GIVEN let mockTestStore = MockTestStore() let sut = CWAHibernationProvider(customStore: mockTestStore) + let today = Date() + let yesterday = today.addingTimeInterval(-86400) // 1 day in seconds // WHEN - var beforeHibernationStartDateComponents = DateComponents() - beforeHibernationStartDateComponents.year = 2023 - beforeHibernationStartDateComponents.month = 4 - beforeHibernationStartDateComponents.day = 30 - beforeHibernationStartDateComponents.hour = 23 - beforeHibernationStartDateComponents.minute = 59 - beforeHibernationStartDateComponents.second = 59 - - guard let hibernationComparisonDate = Calendar.current.date(from: beforeHibernationStartDateComponents) else { - return XCTFail("Expect the hibernation comparison date from the corresponding date components.") - } - mockTestStore.hibernationComparisonDate = hibernationComparisonDate + mockTestStore.hibernationStartDate = yesterday // THEN - XCTAssertFalse(sut.isHibernationState) + XCTAssertTrue(sut.isHibernationState) } - - func testIsHibernationState_Store_HibernationComparisonDate_after_true() throws { + + func testIsHibernationState_HibernationStartDate_afterSystemDate_false() throws { // GIVEN let mockTestStore = MockTestStore() let sut = CWAHibernationProvider(customStore: mockTestStore) + let today = Date() + let tomorrow = today.addingTimeInterval(86400) // 1 day in seconds // WHEN - var afterHibernationStartDateComponents = DateComponents() - afterHibernationStartDateComponents.year = 2023 - afterHibernationStartDateComponents.month = 5 - afterHibernationStartDateComponents.day = 1 - afterHibernationStartDateComponents.hour = 0 - afterHibernationStartDateComponents.minute = 0 - afterHibernationStartDateComponents.second = 0 - - guard let hibernationComparisonDate = Calendar.current.date(from: afterHibernationStartDateComponents) else { - return XCTFail("Expect the hibernation comparison date from the corresponding date components.") - } - mockTestStore.hibernationComparisonDate = hibernationComparisonDate + mockTestStore.hibernationStartDate = tomorrow // THEN - XCTAssertTrue(sut.isHibernationState) - } + XCTAssertFalse(sut.isHibernationState) + } } diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift index 3b11933d956..e53676087be 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewController.swift @@ -83,8 +83,8 @@ class DMHibernationOptionsViewController: UITableViewController { let cell = tableView.dequeueReusableCell(cellType: DMDatePickerTableViewCell.self, for: indexPath) cell.configure(cellViewModel: cellViewModel) - cell.didSelectDate = { [weak self] hibernationComparisonDateSelected in - self?.viewModel.hibernationComparisonDateSelected = hibernationComparisonDateSelected + cell.didSelectDate = { [weak self] customHibernationStartDateSelected in + self?.viewModel.customHibernationStartDateSelected = customHibernationStartDateSelected } return cell diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index 3ac1498dbce..7e72fb9a272 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -12,12 +12,12 @@ class DMHibernationOptionsViewModel { init(store: Store) { self.store = store - self.hibernationComparisonDateSelected = store.hibernationComparisonDate + self.customHibernationStartDateSelected = CWAHibernationProvider.shared.hibernationStartDateForBuild } // MARK: - Internal - var hibernationComparisonDateSelected: Date + var customHibernationStartDateSelected: Date var numberOfSections: Int { Sections.allCases.count } @@ -29,14 +29,16 @@ class DMHibernationOptionsViewModel { } switch section { - case .hibernationComparisonDate: - var title = "App will shutdown after selecting a new date value in the date picker. Currently the hibernation threshold compares against the set date: \(dateFormatter.string(from: store.hibernationComparisonDate))" - - return title + case .hibernationStartDate: + if let customHibernationStartDate = store.hibernationStartDate { + return "App will shutdown after selecting a new date.\nCurrently the (custom) hibernation starts on: \(dateFormatter.string(from: customHibernationStartDate))" + } else { + return "App will shutdown after selecting a new date.\nCurrently the (default) hibernation starts on: \(dateFormatter.string(from: CWAHibernationProvider.shared.hibernationStartDateForBuild))" + } case .storeButton: return nil case .reset: - return "App will shutdown after reseting to today's date." + return "App will shutdown after reset." } } @@ -46,29 +48,29 @@ class DMHibernationOptionsViewModel { } switch section { - case .hibernationComparisonDate: + case .hibernationStartDate: return DMDatePickerCellViewModel( title: "Hibernation Comparison Date", accessibilityIdentifier: AccessibilityIdentifiers.DeveloperMenu.Hibernation.datePicker, datePickerMode: .dateAndTime, - date: store.hibernationComparisonDate + date: CWAHibernationProvider.shared.hibernationStartDateForBuild ) case .storeButton: return DMButtonCellViewModel( - text: "Save Comparison Date", + text: "Save Custom Start Date", textColor: .white, backgroundColor: .enaColor(for: .buttonPrimary) ) { [weak self] in guard let self = self else { return } - self.store(hibernationComparisonDate: self.hibernationComparisonDateSelected) + self.store(hibernationStartDate: self.customHibernationStartDateSelected) } case .reset: return DMButtonCellViewModel( - text: "Reset Comparison Date", + text: "Reset", textColor: .white, backgroundColor: .enaColor(for: .buttonDestructive) ) { [weak self] in - self?.store(hibernationComparisonDate: Date()) + self?.store(hibernationStartDate: CWAHibernationProvider.shared.hibernationStartDateDefault) } } } @@ -83,9 +85,10 @@ class DMHibernationOptionsViewModel { return dateFormatter }() - private func store(hibernationComparisonDate: Date) { - Log.debug("[Debug-Menu] Set hibernation comparison date to: \(dateFormatter.string(from: hibernationComparisonDate)).") - store.hibernationComparisonDate = hibernationComparisonDate + private func store(hibernationStartDate: Date) { + Log.debug("[Debug-Menu] Set hibernation start date to: \(dateFormatter.string(from: hibernationStartDate)).") + store.hibernationStartDate = hibernationStartDate + Log.debug("[Debug-Menu] Set hibernation start saved.") exitApp() } @@ -100,7 +103,7 @@ class DMHibernationOptionsViewModel { extension DMHibernationOptionsViewModel { enum Sections: Int, CaseIterable { /// The date, that will be used to compare it against the hibernation start date. - case hibernationComparisonDate + case hibernationStartDate /// Store the set hibernation comparison date case storeButton /// Reset the stored fake date, the hibernation threshold compares to. diff --git a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift index 8b7dcea598b..9b178d68fd9 100644 --- a/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift +++ b/src/xcode/ENA/ENA/Source/Services/__tests__/Mocks/MockTestStore.swift @@ -63,7 +63,7 @@ final class MockTestStore: Store, PPAnalyticsData { var forceAPITokenAuthorization = false var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? var isSrsPrechecksEnabled = false - var hibernationComparisonDate = Date() + var hibernationStartDate: Date? #endif // MARK: - AppConfigCaching diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift index efdb0073791..14e6bd1a778 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/SecureStore.swift @@ -378,9 +378,9 @@ final class SecureStore: SecureKeyValueStoring, Store { set { kvStore["recentTraceLocationCheckedInto"] = newValue } } - var hibernationComparisonDate: Date { - get { kvStore["hibernationComparisonDate"] as Date? ?? Date() } - set { kvStore["hibernationComparisonDate"] = newValue } + var hibernationStartDate: Date? { + get { kvStore["hibernationStartDate"] as Date? } + set { kvStore["hibernationStartDate"] = newValue } } #endif diff --git a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift index 275c0376d81..3eab2f2fc38 100644 --- a/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift +++ b/src/xcode/ENA/ENA/Source/Workers/Store/Store.swift @@ -87,7 +87,7 @@ protocol StoreProtocol: AnyObject { var recentTraceLocationCheckedInto: DMRecentTraceLocationCheckedInto? { get set } - var hibernationComparisonDate: Date { get set } + var hibernationStartDate: Date? { get set } #endif From 0bbbe5f81d44dcd78b237df35fb84882905abe92 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Sun, 12 Mar 2023 09:49:06 +0100 Subject: [PATCH 106/137] 14909: Choose some better understandable texts. --- .../DMHibernationOptionsViewModel.swift | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift index 7e72fb9a272..f4362e09c32 100644 --- a/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Developer Menu/Features/DMHibernation/DMHibernationOptionsViewModel.swift @@ -30,15 +30,11 @@ class DMHibernationOptionsViewModel { switch section { case .hibernationStartDate: - if let customHibernationStartDate = store.hibernationStartDate { - return "App will shutdown after selecting a new date.\nCurrently the (custom) hibernation starts on: \(dateFormatter.string(from: customHibernationStartDate))" - } else { - return "App will shutdown after selecting a new date.\nCurrently the (default) hibernation starts on: \(dateFormatter.string(from: CWAHibernationProvider.shared.hibernationStartDateForBuild))" - } + return "You can select a custom start here for testing. At the moment, the hibernation starts on \(dateFormatter.string(from: customHibernationStartDateSelected))." case .storeButton: - return nil + return "App will exit after saving." case .reset: - return "App will shutdown after reset." + return "App will exit after reset." } } @@ -50,7 +46,7 @@ class DMHibernationOptionsViewModel { switch section { case .hibernationStartDate: return DMDatePickerCellViewModel( - title: "Hibernation Comparison Date", + title: "Hibernation Start Date", accessibilityIdentifier: AccessibilityIdentifiers.DeveloperMenu.Hibernation.datePicker, datePickerMode: .dateAndTime, date: CWAHibernationProvider.shared.hibernationStartDateForBuild @@ -81,14 +77,14 @@ class DMHibernationOptionsViewModel { private let dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd, HH:mm" + dateFormatter.dateFormat = "dd.MM.yyyy, HH:mm" return dateFormatter }() private func store(hibernationStartDate: Date) { Log.debug("[Debug-Menu] Set hibernation start date to: \(dateFormatter.string(from: hibernationStartDate)).") store.hibernationStartDate = hibernationStartDate - Log.debug("[Debug-Menu] Set hibernation start saved.") + Log.debug("[Debug-Menu] Set hibernation start done.") exitApp() } From 753b24ccbb5ec55cb055b8996cc09c50a8027cd7 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 13 Mar 2023 08:38:20 +0100 Subject: [PATCH 107/137] 14908: Provide a new method `updateTabbarIfNeeded()` in `RootCoordinator`. --- .../AppDelegate & Globals/AppDelegate.swift | 3 ++ .../ENA/ENA/Source/RootCoordinator.swift | 33 ++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift index e362d9a7f39..7b46d4f26bd 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift @@ -256,6 +256,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re // Cleanup recycle-bin. Remove old entries. recycleBin.cleanup() + + // Refresh Tabbar if needed + coordinator.updateTabbarIfNeeded() } func applicationDidEnterBackground(_ application: UIApplication) { diff --git a/src/xcode/ENA/ENA/Source/RootCoordinator.swift b/src/xcode/ENA/ENA/Source/RootCoordinator.swift index 8af086d0683..fe1e631eb26 100644 --- a/src/xcode/ENA/ENA/Source/RootCoordinator.swift +++ b/src/xcode/ENA/ENA/Source/RootCoordinator.swift @@ -241,6 +241,23 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele ) self.diaryCoordinator = diaryCoordinator + setupTabbar() + } + + func updateTabbarIfNeeded() { + guard let viewControllers = tabBarController.viewControllers else { return } + + // Hibernation + if CWAHibernationProvider.shared.isHibernationState, viewControllers.count == 5 { + setupTabbar() + } + // No Hibernation + else if !CWAHibernationProvider.shared.isHibernationState, viewControllers.count == 3 { + setupTabbar() + } + } + + private func setupTabbar() { // Tabbar let startTabBarItem = UITabBarItem( title: AppStrings.Tabbar.homeTitle, @@ -248,7 +265,7 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele selectedImage: UIImage(named: "Icons_Tabbar_Home_Selected") ) startTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.home - homeCoordinator.rootViewController.tabBarItem = startTabBarItem + homeCoordinator?.rootViewController.tabBarItem = startTabBarItem let certificatesTabBarItem = UITabBarItem( title: AppStrings.Tabbar.certificatesTitle, @@ -256,7 +273,7 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele selectedImage: UIImage(named: "Icons_Tabbar_Certificates_Selected") ) certificatesTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.certificates - healthCertificatesTabCoordinator.viewController.tabBarItem = certificatesTabBarItem + healthCertificatesTabCoordinator?.viewController.tabBarItem = certificatesTabBarItem // CWA Hibernation hides scanner and check-in tab if !cwaHibernationProvider.isHibernationState { @@ -275,7 +292,7 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele selectedImage: UIImage(named: "Icons_Tabbar_Checkin_Selected") ) eventsTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.checkin - checkinTabCoordinator.viewController.tabBarItem = eventsTabBarItem + checkinTabCoordinator?.viewController.tabBarItem = eventsTabBarItem } let diaryTabBarItem = UITabBarItem( @@ -284,18 +301,18 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele selectedImage: UIImage(named: "Icons_Tabbar_Diary_Selected") ) diaryTabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.TabBar.diary - diaryCoordinator.viewController.tabBarItem = diaryTabBarItem + diaryCoordinator?.viewController.tabBarItem = diaryTabBarItem tabBarController.tabBar.tintColor = .enaColor(for: .tint) tabBarController.tabBar.unselectedItemTintColor = .enaColor(for: .textPrimary2) tabBarController.delegate = self let tabBarViewControllers = [ - homeCoordinator.rootViewController, - healthCertificatesTabCoordinator.viewController, + homeCoordinator?.rootViewController, + healthCertificatesTabCoordinator?.viewController, cwaHibernationProvider.isHibernationState ? nil : universalScannerDummyViewController, - cwaHibernationProvider.isHibernationState ? nil : checkinTabCoordinator.viewController, - diaryCoordinator.viewController + cwaHibernationProvider.isHibernationState ? nil : checkinTabCoordinator?.viewController, + diaryCoordinator?.viewController ].compactMap { $0 } tabBarController.setViewControllers(tabBarViewControllers, animated: false) From a4e72682cc5f6a3441530576fc7703dd24c649df Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 13 Mar 2023 10:03:56 +0100 Subject: [PATCH 108/137] Update src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift Co-authored-by: Omar Ahmed --- .../AppDelegate & Globals/CWAHibernationProvider.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 17db49a9910..9281e8b8972 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -50,11 +50,7 @@ class CWAHibernationProvider: RequiresAppDependencies { /// CWA hibernation threshold date. var hibernationStartDateForBuild: Date { - #if DEBUG - Log.debug("current hibernationStartDate \(String(describing: secureStore.hibernationStartDate))") - return secureStore.hibernationStartDate ?? hibernationStartDateDefault - - #elseif !RELEASE + #if !RELEASE Log.debug("current hibernationStartDate \(String(describing: secureStore.hibernationStartDate))") return secureStore.hibernationStartDate ?? hibernationStartDateDefault From f2bd49e2d21ef3003c688b8ad9d78ce6dc6bbdbc Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 13 Mar 2023 10:45:01 +0100 Subject: [PATCH 109/137] 14908: Swiftlint --- src/xcode/ENA/ENA/Source/RootCoordinator.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/RootCoordinator.swift b/src/xcode/ENA/ENA/Source/RootCoordinator.swift index fe1e631eb26..6c91251cad8 100644 --- a/src/xcode/ENA/ENA/Source/RootCoordinator.swift +++ b/src/xcode/ENA/ENA/Source/RootCoordinator.swift @@ -118,7 +118,6 @@ class RootCoordinator: NSObject, RequiresAppDependencies, UITabBarControllerDele return viewController }() - // swiftlint:disable function_body_length func showHome(enStateHandler: ENStateHandler, route: Route?, startupErrors: [Error]) { // only create and init the whole view stack if not done before // there for we check if the homeCoordinator exists From 22fdf95f4a1c8714bb7cac5f43c1be47a2b65166 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 13 Mar 2023 11:18:13 +0100 Subject: [PATCH 110/137] 14911: Observe `UIApplication.didBecomeActiveNotification` and refresh the BarItems. --- .../Scenes/Home/HomeTableViewController.swift | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 0268b31dd04..9d4b0df8522 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -130,6 +130,14 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega required init?(coder _: NSCoder) { fatalError("init(coder:) has intentionally not been implemented") } + + // MARK: - Deinit + + deinit { + if let didBecomeActiveNotificationObserver = didBecomeActiveNotificationObserver { + NotificationCenter.default.removeObserver(didBecomeActiveNotificationObserver) + } + } // MARK: - Overrides @@ -144,6 +152,12 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega NotificationCenter.default.addObserver(self, selector: #selector(refreshUIAfterResumingFromBackground), name: UIApplication.willEnterForegroundNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateStatistics), name: NSNotification.Name.NSCalendarDayChanged, object: nil) + didBecomeActiveNotificationObserver = NotificationCenter.default.addObserver( + self, + selector: #selector(onDidBecomeActiveNotification), + name: UIApplication.didBecomeActiveNotification, + object: nil + ) refreshUI() } @@ -373,6 +387,8 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega private var familyTestCell: FamilyTestsHomeCell? private var subscriptions = Set() + + private var didBecomeActiveNotificationObserver: NSObjectProtocol? private func setupBarButtonItems() { navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "Corona-Warn-App"), style: .plain, target: nil, action: nil) @@ -1114,6 +1130,11 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega self?.viewModel.state.updateStatistics() } } + + @objc + private func onDidBecomeActiveNotification() { + setupBarButtonItems() + } // swiftlint:disable:next file_length } From 37a29d70c25b18f683625097e52baa4b8fba82a6 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 13 Mar 2023 11:22:31 +0100 Subject: [PATCH 111/137] 14911: Append last commit. --- .../ENA/Source/Scenes/Home/HomeTableViewController.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 9d4b0df8522..dd064018fa4 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -134,9 +134,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega // MARK: - Deinit deinit { - if let didBecomeActiveNotificationObserver = didBecomeActiveNotificationObserver { - NotificationCenter.default.removeObserver(didBecomeActiveNotificationObserver) - } + NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) } // MARK: - Overrides @@ -152,7 +150,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega NotificationCenter.default.addObserver(self, selector: #selector(refreshUIAfterResumingFromBackground), name: UIApplication.willEnterForegroundNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateStatistics), name: NSNotification.Name.NSCalendarDayChanged, object: nil) - didBecomeActiveNotificationObserver = NotificationCenter.default.addObserver( + NotificationCenter.default.addObserver( self, selector: #selector(onDidBecomeActiveNotification), name: UIApplication.didBecomeActiveNotification, @@ -387,8 +385,6 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega private var familyTestCell: FamilyTestsHomeCell? private var subscriptions = Set() - - private var didBecomeActiveNotificationObserver: NSObjectProtocol? private func setupBarButtonItems() { navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "Corona-Warn-App"), style: .plain, target: nil, action: nil) From 687210a49517b979bbe3c1e64d2b6d58605f70a0 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Mon, 13 Mar 2023 11:56:40 +0100 Subject: [PATCH 112/137] fix accessability --- src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift | 2 +- .../ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift b/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift index b059422ec17..9d1f8761f4d 100644 --- a/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift +++ b/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift @@ -276,7 +276,7 @@ class ENAUITests_01a_Home: CWATestCase { app.setLaunchArgument(LaunchArguments.endOfLife.isHibernationStateEnabled, to: true) app.launch() - XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.textViews[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel].waitForExistence(timeout: .medium)) XCTAssertTrue(app.images[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.image].waitForExistence(timeout: .medium)) XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.titleLabel].waitForExistence(timeout: .medium)) } diff --git a/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift b/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift index 063dc2a79ff..40dcb4c3ed6 100644 --- a/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift +++ b/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift @@ -33,7 +33,7 @@ class ENAUITests_00_Onboarding: CWATestCase { app.buttons["AppStrings.Onboarding.onboardingContinue"].waitAndTap() // check that the homescreen element AppStrings.home.activateTitle is visible onscreen - XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.textViews[AccessibilityIdentifiers.Home.EndOfLifeThankYouCell.descriptionLabel].waitForExistence(timeout: .medium)) } func test_0000_OnboardingFlow_DisablePermissions_normal_XXXL() throws { From 70fe843be4efc787a99658adb3f1dae679afadd8 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Mon, 13 Mar 2023 13:01:12 +0100 Subject: [PATCH 113/137] 14911: Show Overview-Info Icon depending on Hibernation. --- .../Source/Scenes/Home/HomeTableViewController.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index dd064018fa4..835238aaa0f 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -393,14 +393,18 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega navigationItem.leftBarButtonItem?.accessibilityTraits = .none navigationItem.leftBarButtonItem?.accessibilityLabel = AppStrings.Home.leftBarButtonDescription navigationItem.leftBarButtonItem?.accessibilityIdentifier = AccessibilityIdentifiers.Home.leftBarButtonDescription - - if !CWAHibernationProvider.shared.isHibernationState { + } + + private func setupRightBarButtonItem() { + if CWAHibernationProvider.shared.isHibernationState { + navigationItem.rightBarButtonItem = nil + } else { let infoButton = UIButton(type: .infoLight) infoButton.addTarget(self, action: #selector(infoButtonTapped), for: .touchUpInside) navigationItem.rightBarButtonItem = UIBarButtonItem(customView: infoButton) navigationItem.rightBarButtonItem?.isAccessibilityElement = true - navigationItem.rightBarButtonItem?.accessibilityLabel = AppStrings.Home.rightBarButtonDescription navigationItem.rightBarButtonItem?.accessibilityIdentifier = AccessibilityIdentifiers.Home.rightBarButtonDescription + navigationItem.rightBarButtonItem?.accessibilityLabel = AppStrings.Home.rightBarButtonDescription } } @@ -1129,7 +1133,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega @objc private func onDidBecomeActiveNotification() { - setupBarButtonItems() + setupRightBarButtonItem() } // swiftlint:disable:next file_length From d812d4c964e3c6605a3a62a3b0c66858c2928a2d Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Mon, 13 Mar 2023 13:20:46 +0100 Subject: [PATCH 114/137] bump version to 3.2.0 4 --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index 33ced980a7b..ed2cce46164 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -13181,7 +13181,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENACommunity.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = $IPHONE_APP_DEV_TEAM; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13336,7 +13336,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13515,7 +13515,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13757,7 +13757,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENATest.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13797,7 +13797,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info.plist; IPHONE_APP_CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -13940,7 +13940,7 @@ CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -13984,7 +13984,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -14027,7 +14027,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; From 7e33c5a2942db053bbcbb1be667216cf50ad60e4 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Mon, 13 Mar 2023 17:49:23 +0100 Subject: [PATCH 115/137] bump version to 3.2.0 5 --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index ed2cce46164..42bbdbbbf6f 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -13181,7 +13181,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENACommunity.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = $IPHONE_APP_DEV_TEAM; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13336,7 +13336,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13515,7 +13515,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13757,7 +13757,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENATest.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13797,7 +13797,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info.plist; IPHONE_APP_CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -13940,7 +13940,7 @@ CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -13984,7 +13984,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -14027,7 +14027,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; From 4a30f45ca6f3c375be8ffd119612c924fb7f6d6e Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 14 Mar 2023 12:08:27 +0100 Subject: [PATCH 116/137] 14916: Adopt Thank You! Screen and show a tappable FAQ link. --- .../Localization/bg.lproj/Localizable.links.strings | 2 +- .../Localization/de.lproj/Localizable.links.strings | 2 +- .../Resources/Localization/de.lproj/Localizable.strings | 4 ++-- .../Localization/en.lproj/Localizable.links.strings | 2 +- .../Localization/pl.lproj/Localizable.links.strings | 2 +- .../Localization/ro.lproj/Localizable.links.strings | 2 +- .../Localization/tr.lproj/Localizable.links.strings | 2 +- .../Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift | 1 + .../Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib | 9 ++++++--- .../EndOfLifeThankYouCellViewModel.swift | 9 ++++----- 10 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.links.strings index 5196e364eb0..dcc244d738f 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.links.strings @@ -68,4 +68,4 @@ "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; -"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/en/faq/#ramp_down"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.links.strings index 4928b237f3c..61b2cb739d0 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.links.strings @@ -70,4 +70,4 @@ "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/de/faq/results/#warn_without_tan"; -"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/#ramp_down"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings index 841a6b18794..4fd1a2795a7 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings @@ -1525,9 +1525,9 @@ Bei ausgeschalteter Hintergrundaktualisierung müssen Sie die App täglich aufru "Home_EndOfLifeThankYouTile_Title" = "Vielen Dank!"; -"Home_EndOfLifeThankYouTile_description" = "Vielen Dank für die Nutzung der Corona-Warn-App. Während der Pandemie wurden durch die Nutzenden der Corona-Warn-App rund 9 Millionen positive Testergebnisse geteilt. Durch diese Teilung positiver Testergebnisse konnten Personen schnell vor einem erhöhten Infektionsrisiko gewarnt werden, das ihnen sonst unerkannt geblieben wäre. Viele Gewarnte wurden anschließend positiv getestet. Die Corona-Warn-App hat dank Ihrer Mithilfe ihren Zweck der frühzeitigen Warnung erfüllt und die Beendigung von Infektionsketten unterstützt.\n\nAb dem 1. Juni 2023 wird die Corona-Warn-App nicht mehr weiterentwickelt. Sie können weiterhin auf Ihre bereits in der CWA gespeicherten Zertifikate und das Kontakt-Tagebuch zugreifen. Alle anderen Funktionen stehen nicht mehr zur Verfügung.\n\nWeitere Informationen zum Betriebsende finden Sie in den %@."; +"Home_EndOfLifeThankYouTile_description" = "Vielen Dank für die Nutzung der Corona-Warn-App. Während der Pandemie wurden durch die Nutzenden der Corona-Warn-App rund 9 Millionen positive Testergebnisse geteilt. Durch diese Teilung positiver Testergebnisse konnten Personen schnell vor einem erhöhten Infektionsrisiko gewarnt werden, das ihnen sonst unerkannt geblieben wäre. Viele Gewarnte wurden anschließend positiv getestet. Die Corona-Warn-App hat dank Ihrer Mithilfe ihren Zweck der frühzeitigen Warnung erfüllt und die Beendigung von Infektionsketten unterstützt.\n\nAb dem 1. Juni 2023 wird die Corona-Warn-App nicht mehr weiterentwickelt. Sie können weiterhin auf Ihre bereits in der CWA gespeicherten Zertifikate und das Kontakt-Tagebuch zugreifen. Alle anderen Funktionen stehen nicht mehr zur Verfügung.\n\n%@"; -"Home_EndOfLifeThankYouTile_faq" = "FAQ"; +"Home_EndOfLifeThankYouTile_faq" = "Mehr Informationen finden Sie in den FAQ."; /* Home Test Registration Card */ diff --git a/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.links.strings index 6f344b57ee8..ba5dc036119 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.links.strings @@ -70,4 +70,4 @@ "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; -"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/en/faq/#ramp_down"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.links.strings index 06ef125f466..909dde4de12 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.links.strings @@ -68,4 +68,4 @@ "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; -"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/en/faq/#ramp_down"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.links.strings index 593c53f2f34..0b4101174f4 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.links.strings @@ -68,4 +68,4 @@ "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; -"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/en/faq/#ramp_down"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.links.strings b/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.links.strings index 7d07fc69362..e67b1b6bf99 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.links.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.links.strings @@ -68,4 +68,4 @@ "ExposureSubmission_WarnWithoutTAN_FAQLink" = "https://www.coronawarn.app/en/faq/results/#warn_without_tan"; -"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/de/faq/"; // to.do final URL +"Home_EndOfLifeThankYouTile_FAQLink" = "https://www.coronawarn.app/en/faq/#ramp_down"; diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift index 6c5c1d28e0f..9b5779a6705 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.swift @@ -60,6 +60,7 @@ final class EndOfLifeThankYouCell: UITableViewCell { descriptionTextView.adjustsFontForContentSizeCategory = true descriptionTextView.backgroundColor = .clear descriptionTextView.delegate = self + descriptionTextView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.enaColor(for: .textTint)] setupAccessibility() } diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib index 7beb50edea0..66c9cd08ec5 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCell.xib @@ -25,7 +25,7 @@ - + - + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -94,6 +94,9 @@ + + + diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index 35df94dfc3c..3983c50d422 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -32,11 +32,10 @@ class EndOfLifeThankYouCellViewModel { attributes: textAttributes ) - // to.do 08.03.2023: wait for final decision whether the FAQ link is tappable or not - // attributedString.mark( - // faqLinkText, - // with: LinkHelper.urlString(suffix: faqLinkAnchor, type: .faq) - // ) + attributedString.mark( + faqLinkText, + with: faqLinkAnchor + ) return attributedString } From f575cc056b527d355ac968b1eaa4ec4e006e9e7c Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 14 Mar 2023 12:08:57 +0100 Subject: [PATCH 117/137] 14916: Split the guard to get better log informations. --- .../Extensions/NSMutableAttributedString+Link.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Extensions/NSMutableAttributedString+Link.swift b/src/xcode/ENA/ENA/Source/Extensions/NSMutableAttributedString+Link.swift index 19e4ff4743e..6437da55a37 100644 --- a/src/xcode/ENA/ENA/Source/Extensions/NSMutableAttributedString+Link.swift +++ b/src/xcode/ENA/ENA/Source/Extensions/NSMutableAttributedString+Link.swift @@ -9,9 +9,14 @@ extension NSMutableAttributedString { /// looks for the given text and sets a link attribute public func mark(_ text: String, with link: String) { let foundRange = mutableString.range(of: text) - guard let linkURL = URL(string: link), - foundRange.location != NSNotFound else { - Log.debug("Link \(text) text not found") + + guard let linkURL = URL(string: link) else { + Log.debug("Link URL could not created from string: \(link).") + return + } + + guard foundRange.location != NSNotFound else { + Log.debug("Link \(text) text not found.") return } From b504d44f6cbc5afe703b6c7639da6e6749b34fad Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Tue, 14 Mar 2023 12:14:15 +0100 Subject: [PATCH 118/137] 16916: Replace the word CWA with App. --- .../ENA/ENA/Resources/Localization/de.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings index 4fd1a2795a7..837506b96b9 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings @@ -1525,7 +1525,7 @@ Bei ausgeschalteter Hintergrundaktualisierung müssen Sie die App täglich aufru "Home_EndOfLifeThankYouTile_Title" = "Vielen Dank!"; -"Home_EndOfLifeThankYouTile_description" = "Vielen Dank für die Nutzung der Corona-Warn-App. Während der Pandemie wurden durch die Nutzenden der Corona-Warn-App rund 9 Millionen positive Testergebnisse geteilt. Durch diese Teilung positiver Testergebnisse konnten Personen schnell vor einem erhöhten Infektionsrisiko gewarnt werden, das ihnen sonst unerkannt geblieben wäre. Viele Gewarnte wurden anschließend positiv getestet. Die Corona-Warn-App hat dank Ihrer Mithilfe ihren Zweck der frühzeitigen Warnung erfüllt und die Beendigung von Infektionsketten unterstützt.\n\nAb dem 1. Juni 2023 wird die Corona-Warn-App nicht mehr weiterentwickelt. Sie können weiterhin auf Ihre bereits in der CWA gespeicherten Zertifikate und das Kontakt-Tagebuch zugreifen. Alle anderen Funktionen stehen nicht mehr zur Verfügung.\n\n%@"; +"Home_EndOfLifeThankYouTile_description" = "Vielen Dank für die Nutzung der Corona-Warn-App. Während der Pandemie wurden durch die Nutzenden der Corona-Warn-App rund 9 Millionen positive Testergebnisse geteilt. Durch diese Teilung positiver Testergebnisse konnten Personen schnell vor einem erhöhten Infektionsrisiko gewarnt werden, das ihnen sonst unerkannt geblieben wäre. Viele Gewarnte wurden anschließend positiv getestet. Die Corona-Warn-App hat dank Ihrer Mithilfe ihren Zweck der frühzeitigen Warnung erfüllt und die Beendigung von Infektionsketten unterstützt.\n\nAb dem 1. Juni 2023 wird die Corona-Warn-App nicht mehr weiterentwickelt. Sie können weiterhin auf Ihre bereits in der App gespeicherten Zertifikate und das Kontakt-Tagebuch zugreifen. Alle anderen Funktionen stehen nicht mehr zur Verfügung.\n\n%@"; "Home_EndOfLifeThankYouTile_faq" = "Mehr Informationen finden Sie in den FAQ."; From e3edba2a1cd1b2c2c5fe477817f4781e91a44d10 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Tue, 14 Mar 2023 17:31:34 +0500 Subject: [PATCH 119/137] removing irrelevant unit test --- src/xcode/ENA/TestPlans/UnitTests.xctestplan | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xcode/ENA/TestPlans/UnitTests.xctestplan b/src/xcode/ENA/TestPlans/UnitTests.xctestplan index bc68eef0706..4bf2e0148ef 100644 --- a/src/xcode/ENA/TestPlans/UnitTests.xctestplan +++ b/src/xcode/ENA/TestPlans/UnitTests.xctestplan @@ -81,6 +81,7 @@ "ELSServiceTests\/testGIVEN_ELSService_WHEN_UploadIsTriggered_THEN_ServerErrorIsReturned()", "HTTPClientCertificatePinningTests\/testAllProductionEndpoints()", "HealthCertificateQRCodeViewModelTests", + "RiskProviderTests\/test_When_RequestRiskIsCalledFromDifferentThreads_Then_ItReturnsWithAlreadyRunningErrorOrCalculatedRisk()", "StatisticsProviderTests\/testFetchLiveStats()" ], "target" : { From cb89d0ebc1764e24b7d9cd111c0f186d20339a97 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Wed, 15 Mar 2023 10:11:56 +0100 Subject: [PATCH 120/137] 14911: Setup right bar button item when view will appear. --- .../ENA/Source/Scenes/Home/HomeTableViewController.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index ab9057a3650..6ab84dc2be2 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -142,7 +142,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega override func viewDidLoad() { super.viewDidLoad() - setupBarButtonItems() + setupLeftBarButtonItem() setupTableView() navigationItem.largeTitleDisplayMode = .automatic @@ -177,6 +177,8 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega /** navigationbar is a shared property - so we need to trigger a resizing because others could have set it to true*/ navigationController?.navigationBar.prefersLargeTitles = false navigationController?.navigationBar.sizeToFit() + + setupRightBarButtonItem() viewModel.state.requestRisk(userInitiated: false) viewModel.resetBadgeCount() @@ -386,7 +388,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega private var subscriptions = Set() - private func setupBarButtonItems() { + private func setupLeftBarButtonItem() { navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "Corona-Warn-App"), style: .plain, target: nil, action: nil) navigationItem.leftBarButtonItem?.customView = UIImageView(image: navigationItem.leftBarButtonItem?.image) navigationItem.leftBarButtonItem?.isAccessibilityElement = true From 2789fd7099c13900ce8a7808180326b498685725 Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Wed, 15 Mar 2023 11:08:55 +0100 Subject: [PATCH 121/137] 14916: Swiftlint. --- .../HealthCertifiedPersonCellModel.swift | 1 + .../EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/Overview/Cells/HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/Overview/Cells/HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift index b42c0f0d7f0..adb12982221 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/Overview/Cells/HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/Overview/Cells/HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift @@ -10,6 +10,7 @@ class HealthCertifiedPersonCellModel { // MARK: - Init + // swiftlint:disable:next cyclomatic_complexity init?( healthCertifiedPerson: HealthCertifiedPerson, cclService: CCLServable, diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift index 3983c50d422..410f6b30a7f 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/Cells/EndOfLifeThankYou/EndOfLifeThankYouCellViewModel.swift @@ -14,7 +14,6 @@ class EndOfLifeThankYouCellViewModel { var description: NSAttributedString { let faqLinkText = AppStrings.Home.EndOfLifeThankYouTile.faqLinkText - let faqLinkAnchor = AppStrings.Home.EndOfLifeThankYouTile.faqLinkAnchor let string = String( format: AppStrings.Home.EndOfLifeThankYouTile.description, @@ -32,10 +31,7 @@ class EndOfLifeThankYouCellViewModel { attributes: textAttributes ) - attributedString.mark( - faqLinkText, - with: faqLinkAnchor - ) + attributedString.mark(faqLinkText, with: AppStrings.Home.EndOfLifeThankYouTile.faqLinkAnchor) return attributedString } From 42aaa5bb9045aec0ba59f79d3ff882bd7ced861f Mon Sep 17 00:00:00 2001 From: Felix Schmidt Date: Wed, 15 Mar 2023 13:24:42 +0100 Subject: [PATCH 122/137] 14916: Swiftlint. --- .../HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/Overview/Cells/HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/Overview/Cells/HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift index adb12982221..b42c0f0d7f0 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/Overview/Cells/HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/HealthCertificates/Overview/Cells/HealthCertifiedPerson/HealthCertifiedPersonCellModel.swift @@ -10,7 +10,6 @@ class HealthCertifiedPersonCellModel { // MARK: - Init - // swiftlint:disable:next cyclomatic_complexity init?( healthCertifiedPerson: HealthCertifiedPerson, cclService: CCLServable, From e63ff564d59429355b9830cd9220d32906849c1a Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 15 Mar 2023 15:25:32 +0100 Subject: [PATCH 123/137] update homescreen when app becomes active --- .../Scenes/Home/HomeTableViewController.swift | 28 ++++--------------- .../Scenes/Home/HomeTableViewModel.swift | 3 +- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index ab9057a3650..87890c70c59 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -102,28 +102,6 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega ) } .store(in: &subscriptions) - - viewModel.cclService.shouldShowNoticeTile - .receive(on: DispatchQueue.OCombine(.main)) - .sink { [weak self] shouldShowNoticeTile in - let isHibernationState = CWAHibernationProvider.shared.isHibernationState - self?.viewModel.isHibernationState = isHibernationState - self?.viewModel.shouldShowAppClosureNotice = shouldShowNoticeTile - self?.tableView.reloadSections( - [ - HomeTableViewModel.Section.appClosureNotice.rawValue, - HomeTableViewModel.Section.endOfLifeThankYou.rawValue, - HomeTableViewModel.Section.exposureLogging.rawValue, - HomeTableViewModel.Section.riskAndTestResults.rawValue, - HomeTableViewModel.Section.statistics.rawValue, - HomeTableViewModel.Section.testRegistration.rawValue, - HomeTableViewModel.Section.traceLocations.rawValue, - HomeTableViewModel.Section.moreInfo.rawValue - ], - with: .none - ) - } - .store(in: &subscriptions) } @available(*, unavailable) @@ -1134,6 +1112,12 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega @objc private func onDidBecomeActiveNotification() { setupRightBarButtonItem() + + let isHibernationState = CWAHibernationProvider.shared.isHibernationState + viewModel.isHibernationState = isHibernationState + DispatchQueue.main.async { + self.tableView.reloadData() + } } // swiftlint:disable:next file_length diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift index 283455d1f1d..5a2b0286be1 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift @@ -94,7 +94,6 @@ class HomeTableViewModel { let familyMemberCoronaTestService: FamilyMemberCoronaTestServiceProviding let cclService: CCLServable var isUpdating: Bool = false - var shouldShowAppClosureNotice: Bool = false var isHibernationState: Bool = false @OpenCombine.Published var testResultLoadingError: Error? @@ -366,7 +365,7 @@ class HomeTableViewModel { return 1 } #endif - if shouldShowAppClosureNotice, !isHibernationState { + if !isHibernationState { return 1 } else { return 0 From f10538713a38b6fbd48766de76da2431fd9edc42 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Wed, 15 Mar 2023 16:03:00 +0100 Subject: [PATCH 124/137] fix tests --- .../Scenes/Home/__tests__/HomeTableViewModelTests.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift index c8ef3e5e2dc..89169a4e774 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift @@ -10,7 +10,7 @@ import HealthCertificateToolkit // swiftlint:disable type_body_length class HomeTableViewModelTests: CWATestCase { - func testNumberOfSections_isHibernation_true_showAppClosureNotice_false() throws { + func testNumberOfSections_isHibernation_true() throws { // GIVEN let store = MockTestStore() @@ -42,7 +42,6 @@ class HomeTableViewModelTests: CWATestCase { // Is hibernation and should not show app closure notice sut.isHibernationState = true - sut.shouldShowAppClosureNotice = false // THEN @@ -60,7 +59,7 @@ class HomeTableViewModelTests: CWATestCase { XCTAssertEqual(sut.numberOfRows(in: 7), 1) // moreInfo visible } - func testNumberOfSections_isHibernation_true_showAppClosureNotice_true() throws { + func testNumberOfSections_isHibernation_false() throws { // GIVEN let store = MockTestStore() @@ -91,8 +90,7 @@ class HomeTableViewModelTests: CWATestCase { // WHEN // Is hibernation and should show app closure notice - sut.isHibernationState = true - sut.shouldShowAppClosureNotice = true + sut.isHibernationState = false // THEN From 1728bdea494df44585d9cc426c301ecdf42a68fd Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 16 Mar 2023 08:35:26 +0100 Subject: [PATCH 125/137] fix failing tests --- .../AppDelegate & Globals/AppDelegate.swift | 3 + .../CWAHibernationProvider.swift | 10 ++- .../UserNotificationCenter.swift | 1 + .../Mocks/MockUserNotificationCenter.swift | 5 +- ...HealthCertificateNotificationService.swift | 20 ++++- .../HealthCertificateService.swift | 80 ++++++++----------- .../HealthCertificateServiceTests.swift | 8 +- 7 files changed, 78 insertions(+), 49 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift index 4cb68830c83..8980ed4b365 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/AppDelegate.swift @@ -196,6 +196,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re // Disable Exposure Notification (ENF) disableExposureNotification() + + // cancel pending notifications + UNUserNotificationCenter.current().removeAllPendingNotificationRequests() } else { // Observe Exposure Notification (ENF) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 1ca10e17dce..a18e2874cc3 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -18,16 +18,24 @@ class CWAHibernationProvider: RequiresAppDependencies { } #endif + // MARK: Public + + static let isHibernationInUnitTest = "isHibernationInUnitTest" + // MARK: Internal static let shared = CWAHibernationProvider() - + /// Determines if the CWA is in hibernation state. var isHibernationState: Bool { #if DEBUG if isUITesting { return LaunchArguments.endOfLife.isHibernationStateEnabled.boolValue } + // check if we are using unit testing environment then we return an expected value true or false based on the unit test + if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil { + return UserDefaults.standard.bool(forKey: CWAHibernationProvider.isHibernationInUnitTest) + } return secureStore.hibernationComparisonDate >= hibernationStartDate #else return Date() >= hibernationStartDate diff --git a/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/UserNotificationCenter.swift b/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/UserNotificationCenter.swift index 5d8bcc55a2e..8d961addf8f 100644 --- a/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/UserNotificationCenter.swift +++ b/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/UserNotificationCenter.swift @@ -8,6 +8,7 @@ protocol UserNotificationCenter { func getPendingNotificationRequests(completionHandler: @escaping ([UNNotificationRequest]) -> Void) func add(_ request: UNNotificationRequest, withCompletionHandler completionHandler: ((Error?) -> Void)?) func removePendingNotificationRequests(withIdentifiers identifiers: [String]) + func removeAllPendingNotificationRequests() } extension UNUserNotificationCenter: UserNotificationCenter { } diff --git a/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/__tests__/Mocks/MockUserNotificationCenter.swift b/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/__tests__/Mocks/MockUserNotificationCenter.swift index cd503914ef9..06b86ddfd21 100644 --- a/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/__tests__/Mocks/MockUserNotificationCenter.swift +++ b/src/xcode/ENA/ENA/Source/Services/DeadmanNotification/__tests__/Mocks/MockUserNotificationCenter.swift @@ -21,10 +21,13 @@ class MockUserNotificationCenter: UserNotificationCenter { func removePendingNotificationRequests(withIdentifiers identifiers: [String]) { notificationRequests.removeAll(where: { identifiers.contains($0.identifier) }) } + + func removeAllPendingNotificationRequests() { + } + // MARK: - Internal var notificationRequests = [UNNotificationRequest]() var onAdding: ((UNNotificationRequest) -> Void)? - } diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift index cd404511599..c6936ecb405 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift @@ -17,11 +17,15 @@ class HealthCertificateNotificationService { } // MARK: - Internal - + func createNotifications( for healthCertificate: HealthCertificate, completion: @escaping () -> Void ) { + guard !isHibernationState else { + completion() + return + } guard healthCertificate.type != .test else { completion() return @@ -100,6 +104,10 @@ class HealthCertificateNotificationService { previousBoosterNotificationIdentifier: String?, completion: @escaping () -> Void ) { + guard !isHibernationState else { + completion() + return + } let name = person.name?.standardizedName guard let newBoosterNotificationIdentifier = person.dccWalletInfo?.boosterNotification.identifier else { Log.info("No booster notification identifier found for person \(private: String(describing: name))", log: .vaccination) @@ -130,6 +138,10 @@ class HealthCertificateNotificationService { previousCertificateReissuance: DCCCertificateReissuance?, completion: @escaping () -> Void ) { + guard !isHibernationState else { + completion() + return + } let name = person.name?.standardizedName guard let newCertificateReissuance = person.dccWalletInfo?.certificateReissuance, let newIdentifier = newCertificateReissuance.reissuanceDivision.identifier, @@ -161,6 +173,10 @@ class HealthCertificateNotificationService { previousAdmissionStateIdentifier: String?, completion: @escaping () -> Void ) { + guard !isHibernationState else { + completion() + return + } let name = person.name?.standardizedName guard let newAdmissionStateIdentifier = person.dccWalletInfo?.admissionState.identifier else { Log.info("No New admissionState found for person \(private: String(describing: name))", log: .vaccination) @@ -354,4 +370,6 @@ class HealthCertificateNotificationService { } } + private let isHibernationState = CWAHibernationProvider.shared.isHibernationState + } diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift index 8e7d8dd5ecf..8073620744c 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateService.swift @@ -300,7 +300,6 @@ class HealthCertificateService: HealthCertificateServiceServable { updateValidityState(for: newHealthCertificate, person: person) scheduleTimer() - if !CWAHibernationProvider.shared.isHibernationState { dispatchGroup.enter() healthCertificateNotificationService.createNotifications( for: newHealthCertificate, @@ -308,7 +307,6 @@ class HealthCertificateService: HealthCertificateServiceServable { dispatchGroup.leave() } ) - } for relation in certificateRef.relations where relation.action == "replace" { if relation.index < requestCertificates.count { let certificateBase45 = requestCertificates[relation.index] @@ -354,12 +352,10 @@ class HealthCertificateService: HealthCertificateServiceServable { updateValidityState(for: healthCertificate, person: healthCertifiedPerson) scheduleTimer() - if !CWAHibernationProvider.shared.isHibernationState { healthCertificateNotificationService.createNotifications( for: healthCertificate, completion: completedNotificationRegistration ) - } if isNewPersonAdded { Log.info("[HealthCertificateService] Successfully registered health certificate for a new person", log: .api) // Manual update needed as the person subscriptions were not set up when the certificate was added @@ -555,15 +551,13 @@ class HealthCertificateService: HealthCertificateServiceServable { let dispatchGroup = DispatchGroup() certificateTuples.forEach { healthCertificateTuple in updateValidityState(for: healthCertificateTuple.certificate, person: healthCertificateTuple.person) - if !CWAHibernationProvider.shared.isHibernationState { - dispatchGroup.enter() - healthCertificateNotificationService.createNotifications( - for: healthCertificateTuple.certificate, - completion: { - dispatchGroup.leave() - } - ) - } + dispatchGroup.enter() + healthCertificateNotificationService.createNotifications( + for: healthCertificateTuple.certificate, + completion: { + dispatchGroup.leave() + } + ) } @@ -813,39 +807,37 @@ class HealthCertificateService: HealthCertificateServiceServable { } } #endif - + let dispatchGroup = DispatchGroup() - - if !CWAHibernationProvider.shared.isHibernationState { - dispatchGroup.enter() - self.healthCertificateNotificationService.scheduleBoosterNotificationIfNeeded( - for: person, - previousBoosterNotificationIdentifier: previousBoosterNotificationIdentifier, - completion: { - dispatchGroup.leave() - } - ) - dispatchGroup.enter() - self.healthCertificateNotificationService.scheduleCertificateReissuanceNotificationIfNeeded( - for: person, - previousCertificateReissuance: previousCertificateReissuance, - completion: { - dispatchGroup.leave() - } - ) - dispatchGroup.enter() - self.healthCertificateNotificationService.scheduleAdmissionStateChangedNotificationIfNeeded( - for: person, - previousAdmissionStateIdentifier: previousAdmissionStateIdentifier, - completion: { - dispatchGroup.leave() - } - ) - } + + dispatchGroup.enter() + self.healthCertificateNotificationService.scheduleBoosterNotificationIfNeeded( + for: person, + previousBoosterNotificationIdentifier: previousBoosterNotificationIdentifier, + completion: { + dispatchGroup.leave() + } + ) + dispatchGroup.enter() + self.healthCertificateNotificationService.scheduleCertificateReissuanceNotificationIfNeeded( + for: person, + previousCertificateReissuance: previousCertificateReissuance, + completion: { + dispatchGroup.leave() + } + ) + dispatchGroup.enter() + self.healthCertificateNotificationService.scheduleAdmissionStateChangedNotificationIfNeeded( + for: person, + previousAdmissionStateIdentifier: previousAdmissionStateIdentifier, + completion: { + dispatchGroup.leave() + } + ) dispatchGroup.notify(queue: .global()) { completion?() } - + case .failure(let error): Log.error("Wallet info update failed", error: error) person.mostRecentWalletInfoUpdateFailed = true @@ -862,9 +854,7 @@ class HealthCertificateService: HealthCertificateServiceServable { $0.certificateRef.barcodeData == healthCertificate.base45 }) { healthCertificate.validityState = .blocked - if !CWAHibernationProvider.shared.isHibernationState { - healthCertificateNotificationService.createNotifications(for: healthCertificate, completion: {}) - } + healthCertificateNotificationService.createNotifications(for: healthCertificate, completion: {}) return true } return false diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/__tests__/HealthCertificateServiceTests.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/__tests__/HealthCertificateServiceTests.swift index 0ceb9be8b30..e62219f42bc 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/__tests__/HealthCertificateServiceTests.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/__tests__/HealthCertificateServiceTests.swift @@ -11,7 +11,14 @@ import HealthCertificateToolkit // swiftlint:disable file_length // swiftlint:disable:next type_body_length class HealthCertificateServiceTests: CWATestCase { + override class func setUp() { + UserDefaults.standard.setValue(false, forKey: CWAHibernationProvider.isHibernationInUnitTest) + } + override class func tearDown() { + UserDefaults.standard.setValue(false, forKey: CWAHibernationProvider.isHibernationInUnitTest) + } + func testHealthCertifiedPersonsPublisherTriggeredAndStoreUpdatedOnCertificateRegistration() throws { let store = MockTestStore() let service = HealthCertificateService( @@ -2152,5 +2159,4 @@ class HealthCertificateServiceTests: CWATestCase { ["OtherNotification", "HealthCertificateNotificationOther", "OtherNotification2"] ) } - } From fcacf26180b37eea922c464282a8b426bf7793e2 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 16 Mar 2023 09:30:27 +0100 Subject: [PATCH 126/137] fix typo --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index b877355ebf1..04cbd258e4d 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -37,8 +37,9 @@ class CWAHibernationProvider: RequiresAppDependencies { return UserDefaults.standard.bool(forKey: CWAHibernationProvider.isHibernationInUnitTest) } #else - return Date() >= hibernationStartDate + return Date() >= hibernationStartDateForBuild #endif + return Date() >= hibernationStartDateForBuild } let hibernationStartDateDefault: Date = { From d49b94b2b43cab58b392ba13e4db3daf5a1418e2 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 16 Mar 2023 10:10:15 +0100 Subject: [PATCH 127/137] correct if statement --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 8b1dfb38d04..0dd459cd6f9 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -36,8 +36,6 @@ class CWAHibernationProvider: RequiresAppDependencies { if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil { return UserDefaults.standard.bool(forKey: CWAHibernationProvider.isHibernationInUnitTest) } - #else - return Date() >= hibernationStartDateForBuild #endif return Date() >= hibernationStartDateForBuild } From 5c62ae501ec0f7d5adeeccd18478420710c8ac6a Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 16 Mar 2023 10:56:32 +0100 Subject: [PATCH 128/137] Update src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift Co-authored-by: Felix Schmidt --- .../ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 87890c70c59..25ff856006a 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -1115,8 +1115,8 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega let isHibernationState = CWAHibernationProvider.shared.isHibernationState viewModel.isHibernationState = isHibernationState - DispatchQueue.main.async { - self.tableView.reloadData() + DispatchQueue.main.async { [weak self] in + self?.tableView.reloadData() } } From 6cd1e14ea600b7b03f2731b44d18cf0ea417ddd3 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 16 Mar 2023 10:56:43 +0100 Subject: [PATCH 129/137] Update src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift Co-authored-by: Felix Schmidt --- .../ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 25ff856006a..ce1354fed02 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -1113,8 +1113,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega private func onDidBecomeActiveNotification() { setupRightBarButtonItem() - let isHibernationState = CWAHibernationProvider.shared.isHibernationState - viewModel.isHibernationState = isHibernationState + viewModel.isHibernationState = CWAHibernationProvider.shared.isHibernationState DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() } From 310ceb59b4094ec321580b25bfd3613642aeff3c Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 16 Mar 2023 11:28:48 +0100 Subject: [PATCH 130/137] reverse changes --- .../Localization/de.lproj/Localizable.strings | 2 +- .../Scenes/Home/HomeTableViewController.swift | 14 ++++++++++++++ .../Source/Scenes/Home/HomeTableViewModel.swift | 3 ++- .../Home/__tests__/HomeTableViewModelTests.swift | 9 +++++---- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings index 841a6b18794..42ca3a1f790 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/de.lproj/Localizable.strings @@ -693,7 +693,7 @@ Bei ausgeschalteter Hintergrundaktualisierung müssen Sie die App täglich aufru "ExposureSubmissionQRInfo_QRCodeExpired_Alert_Title" = "QR-Code nicht mehr gültig"; -"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Ihr Test liegt länger als 2 Tage zurück und kann nicht mehr in der App registriert werden. Bitte stellen Sie bei zukünftigen Tests sicher, dass Sie den QR-Code scannen, sobald er Ihnen vorliegt."; +"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Ihr Test liegt länger als 21 Tage zurück und kann nicht mehr in der App registriert werden. Bitte stellen Sie bei zukünftigen Tests sicher, dass Sie den QR-Code scannen, sobald er Ihnen vorliegt."; "ExposureSubmission_RAT_QR_Invalid_Alert_Title" = "Fehler"; diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 87890c70c59..01c45f1d038 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -102,6 +102,20 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega ) } .store(in: &subscriptions) + + viewModel.cclService.shouldShowNoticeTile + .receive(on: DispatchQueue.OCombine(.main)) + .sink { [weak self] shouldShowNoticeTile in + self?.viewModel.shouldShowAppClosureNotice = shouldShowNoticeTile + self?.tableView.reloadSections( + [ + HomeTableViewModel.Section.appClosureNotice.rawValue + ], + with: .none + ) + } + .store(in: &subscriptions) + } @available(*, unavailable) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift index 5a2b0286be1..283455d1f1d 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewModel.swift @@ -94,6 +94,7 @@ class HomeTableViewModel { let familyMemberCoronaTestService: FamilyMemberCoronaTestServiceProviding let cclService: CCLServable var isUpdating: Bool = false + var shouldShowAppClosureNotice: Bool = false var isHibernationState: Bool = false @OpenCombine.Published var testResultLoadingError: Error? @@ -365,7 +366,7 @@ class HomeTableViewModel { return 1 } #endif - if !isHibernationState { + if shouldShowAppClosureNotice, !isHibernationState { return 1 } else { return 0 diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift index 89169a4e774..d13973ddb1e 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/__tests__/HomeTableViewModelTests.swift @@ -10,7 +10,7 @@ import HealthCertificateToolkit // swiftlint:disable type_body_length class HomeTableViewModelTests: CWATestCase { - func testNumberOfSections_isHibernation_true() throws { + func testNumberOfSections_isHibernation_true_showAppClosureNotice_false() throws { // GIVEN let store = MockTestStore() @@ -42,6 +42,7 @@ class HomeTableViewModelTests: CWATestCase { // Is hibernation and should not show app closure notice sut.isHibernationState = true + sut.shouldShowAppClosureNotice = false // THEN @@ -59,7 +60,7 @@ class HomeTableViewModelTests: CWATestCase { XCTAssertEqual(sut.numberOfRows(in: 7), 1) // moreInfo visible } - func testNumberOfSections_isHibernation_false() throws { + func testNumberOfSections_isHibernation_true_showAppClosureNotice_true() throws { // GIVEN let store = MockTestStore() @@ -90,8 +91,8 @@ class HomeTableViewModelTests: CWATestCase { // WHEN // Is hibernation and should show app closure notice - sut.isHibernationState = false - + sut.isHibernationState = true + sut.shouldShowAppClosureNotice = true // THEN // Number of Sections From 99bdb3b716f1409653cd40b9308ee849c4b7088d Mon Sep 17 00:00:00 2001 From: service-tip-git Date: Thu, 16 Mar 2023 11:37:16 +0000 Subject: [PATCH 131/137] [INTERNAL] Translation delivery: commit by LX Lab Change-Id: Ice0e366e4c3ca6b59bcdef69c0fc839fc19fee3f --- .../Resources/Localization/bg.lproj/Localizable.strings | 8 +++++--- .../Resources/Localization/en.lproj/Localizable.strings | 8 +++++--- .../Resources/Localization/pl.lproj/Localizable.strings | 8 +++++--- .../Resources/Localization/ro.lproj/Localizable.strings | 8 +++++--- .../Resources/Localization/tr.lproj/Localizable.strings | 8 +++++--- .../Resources/Localization/uk.lproj/Localizable.strings | 8 +++++--- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.strings index 03f0c1ccf48..2459a7c576e 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/bg.lproj/Localizable.strings @@ -677,7 +677,7 @@ "ExposureSubmissionQRInfo_QRCodeExpired_Alert_Title" = "QR кодът вече не е валиден"; -"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Вашият тест е направен преди повече от 21 дни и вече не може да бъде регистриран в приложението. Ако в бъдеще си правите нов тест, моля сканирайте QR кода в момента, в който го получите."; +"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Вашият тест е направен преди повече от 2 дни и вече не може да бъде регистриран в приложението. Ако в бъдеще си правите нов тест, моля сканирайте QR кода в момента, в който го получите."; "ExposureSubmission_RAT_QR_Invalid_Alert_Title" = "Грешка"; @@ -714,6 +714,8 @@ "ExposureSubmissionSuccess_RAT_listItem3" = "От службата за обществено здравеопазване (Gesundheitsamt) може да се свържат с Вас през следващите няколко дни."; +"ExposureSubmissionSuccess_RAT_listItem4" = "Споделете своите случайни ИД кодове, за да предупредите останалите потребители."; + "ExposureSubmissionSuccess_SRS_listItem0" = "Има голяма вероятност да сте носител на заразата. Изолирайте се от другите хора."; "ExposureSubmissionSuccess_SRS_listItem1" = "Вашето предупреждение ще бъде добавено и във Вашия дневник на контактите."; @@ -1480,9 +1482,9 @@ /* Home End of Life Thank you Card */ "Home_EndOfLifeThankYouTile_Title" = "Благодарим Ви!"; -"Home_EndOfLifeThankYouTile_description" = "Благодарим Ви, че използвате приложението Corona-Warn-App. По време на пандемията, потребителите на това приложение са споделили диагнозата си COVID-19 около 9 милиона пъти. Благодарение на това споделяне на положителни резултати от тестове, хората бързо бяха предупреждавани за повишен риск от заразяване, за който иначе не биха били осведомени. Много от предупредените впоследствие сами са били диагностицирани с COVID-19. С ваша помощ приложението Corona-Warn-App изпълни предназначението си на система за ранно предупреждение и помогна за прекъсване на веригите на заразяване.\n\nРазработването на приложението Corona-Warn-App ще бъде преустановено на 1 юни 2023. Все още ще имате достъп до сертификатите, които вече сте запазили в CWA, както и до Вашия дневник на контактите. Другите функции вече няма да бъдат достъпни.\n\nЗа повече информация относно приключване на оперирането с приложението вижте %@."; +"Home_EndOfLifeThankYouTile_description" = "Благодарим Ви, че използвате приложението Corona-Warn-App. По време на пандемията, потребителите на това приложение са споделили диагнозата си COVID-19 около 9 милиона пъти. Благодарение на това споделяне на положителни резултати от тестове, хората бързо бяха предупреждавани за повишен риск от заразяване, за който иначе не биха били осведомени. Много от предупредените впоследствие сами са били диагностицирани с COVID-19. С ваша помощ приложението Corona-Warn-App изпълни предназначението си на система за ранно предупреждение и помогна за прекъсване на веригите на заразяване.\n\nРазработването на приложението Corona-Warn-App ще бъде преустановено на 1 юни 2023. Все още ще имате достъп до сертификатите, които сте си запазили в него, както и до Вашия дневник на контактите. Другите функции вече няма да бъдат достъпни."; -"Home_EndOfLifeThankYouTile_faq" = "ЧЗВ"; +"Home_EndOfLifeThankYouTile_faq" = "За повече информация вижте страницата „ЧЗВ“."; /* Home Test Registration Card */ "Home_TestRegistration_Title" = "Управлявайте тестовете си и предупреждавайте другите"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.strings index 1aca22c441d..10995bb567f 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/en.lproj/Localizable.strings @@ -677,7 +677,7 @@ "ExposureSubmissionQRInfo_QRCodeExpired_Alert_Title" = "QR code no longer valid"; -"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Your test is more than 21 days old and can no longer be registered in the app. If you are tested again in future, please make sure to scan the QR code as soon as you get it."; +"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Your test is more than 2 days old and can no longer be registered in the app. If you are tested again in future, please make sure to scan the QR code as soon as you get it."; "ExposureSubmission_RAT_QR_Invalid_Alert_Title" = "Error"; @@ -714,6 +714,8 @@ "ExposureSubmissionSuccess_RAT_listItem3" = "The public health authority may contact you within the next few days."; +"ExposureSubmissionSuccess_RAT_listItem4" = "Share your random IDs so that others can be warned."; + "ExposureSubmissionSuccess_SRS_listItem0" = "There is a high probability that you are infectious. Isolate yourself from other people."; "ExposureSubmissionSuccess_SRS_listItem1" = "Your warning will be added to your contact journal."; @@ -1480,9 +1482,9 @@ /* Home End of Life Thank you Card */ "Home_EndOfLifeThankYouTile_Title" = "Thank you!"; -"Home_EndOfLifeThankYouTile_description" = "Thank you for using the Corona-Warn-App. During the pandemic, users of the Corona-Warn-App shared their COVID-19 diagnoses around 9 million times. Thanks to this sharing of positive test results, people could be warned quickly of an increased risk of infection, which they would otherwise have remained unaware of. Many of those warned were subsequently diagnosed with COVID-19 themselves. With your support, the Corona-Warn-App fulfilled its purpose as an early-warning system and helped to break chains of infection.\n\nFurther development of the Corona-Warn-App will stop as of June 1, 2023. You will still be able to access the certificates you have already saved in the CWA, as well as your contact journal. The other functions will no longer be available.\n\nFor more information about the end of app operations, refer to the %@."; +"Home_EndOfLifeThankYouTile_description" = "Thank you for using the Corona-Warn-App. During the pandemic, users of the Corona-Warn-App shared their COVID-19 diagnoses around 9 million times. Thanks to this sharing of positive test results, people could be warned quickly of an increased risk of infection, which they would otherwise have remained unaware of. Many of those warned were subsequently diagnosed with COVID-19 themselves. With your support, the Corona-Warn-App fulfilled its purpose as an early-warning system and helped to break chains of infection.\n\nDevelopment of the Corona-Warn-App will be discontinued as of June 1, 2023. You will still be able to access the certificates you have already saved in the app, as well as your contact journal. The other functions will no longer be available."; -"Home_EndOfLifeThankYouTile_faq" = "FAQ"; +"Home_EndOfLifeThankYouTile_faq" = "For further information, please see our FAQ page."; /* Home Test Registration Card */ "Home_TestRegistration_Title" = "Manage Your Tests and Warn Others"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.strings index ca835f50867..c657184aab2 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/pl.lproj/Localizable.strings @@ -677,7 +677,7 @@ "ExposureSubmissionQRInfo_QRCodeExpired_Alert_Title" = "Kod QR stracił ważność"; -"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Twój test ma więcej niż 21 dni i nie można go już zarejestrować w aplikacji. Jeśli w przyszłości będziesz ponownie poddawać się testowi, zeskanuj kod QR, gdy tylko go otrzymasz."; +"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Twój test ma więcej niż 2 dni i nie można go już zarejestrować w aplikacji. Jeśli w przyszłości będziesz ponownie poddawać się testowi, zeskanuj kod QR, gdy tylko go otrzymasz."; "ExposureSubmission_RAT_QR_Invalid_Alert_Title" = "Błąd"; @@ -714,6 +714,8 @@ "ExposureSubmissionSuccess_RAT_listItem3" = "Organ ds. zdrowia publicznego może skontaktować się z Tobą w ciągu kilku najbliższych dni."; +"ExposureSubmissionSuccess_RAT_listItem4" = "Udostępnij swoje losowe identyfikatory, aby umożliwić ostrzeganie innych osób."; + "ExposureSubmissionSuccess_SRS_listItem0" = "Istnieje duże prawdopodobieństwo, że możesz zakażać. Odizoluj się od innych ludzi."; "ExposureSubmissionSuccess_SRS_listItem1" = "Twoje ostrzeżenie zostanie dodane do dziennika kontaktów."; @@ -1480,9 +1482,9 @@ /* Home End of Life Thank you Card */ "Home_EndOfLifeThankYouTile_Title" = "Dziękujemy!"; -"Home_EndOfLifeThankYouTile_description" = "Dziękujemy za korzystanie z aplikacji Corona-Warn-App. Podczas pandemii użytkownicy aplikacji Corona-Warn-App udostępniali swoje diagnozy COVID-19 około 9 milionów razy. Udostępnianie pozytywnych wyników testów umożliwiło szybkie ostrzeganie osób przed zwiększonym ryzykiem zakażenia, którego w przeciwnym razie nie byliby nieświadomi. U wielu z ostrzeżonych osób zdiagnozowano później COVID-19. Dzięki Waszemu wsparciu aplikacja Corona-Warn-App spełniła swoje zadanie jako system wczesnego ostrzegania i pomogła przerwać łańcuchy infekcji.\n\nDalszy rozwój aplikacji Corona-Warn-App zostanie wstrzymany z dniem 1 czerwca 2023 r. Nadal będziesz mieć dostęp do certyfikatów zapisanych w CWA, a także do dziennika kontaktów. Pozostałe funkcje nie będą już dostępne.\n\nAby uzyskać więcej informacji na temat zakończenia działania aplikacji, zapoznaj się z %@."; +"Home_EndOfLifeThankYouTile_description" = "Dziękujemy za korzystanie z aplikacji Corona-Warn-App. Podczas pandemii użytkownicy aplikacji Corona-Warn-App udostępniali swoje diagnozy COVID-19 około 9 milionów razy. Udostępnianie pozytywnych wyników testów umożliwiło szybkie ostrzeganie osób przed zwiększonym ryzykiem zakażenia, którego w przeciwnym razie nie byliby nieświadomi. U wielu z ostrzeżonych osób zdiagnozowano później COVID-19. Dzięki Waszemu wsparciu aplikacja Corona-Warn-App spełniła swoje zadanie jako system wczesnego ostrzegania i pomogła przerwać łańcuchy infekcji.\n\nRozwój aplikacji Corona-Warn-App zostanie wstrzymany z dniem 1 czerwca 2023 r. Nadal będziesz mieć dostęp do certyfikatów zapisanych w aplikacji, a także do dziennika kontaktów. Pozostałe funkcje nie będą już dostępne."; -"Home_EndOfLifeThankYouTile_faq" = "Często zadawane pytania"; +"Home_EndOfLifeThankYouTile_faq" = "Więcej informacji znajduje się na naszej stronie „Często zadawane pytania”."; /* Home Test Registration Card */ "Home_TestRegistration_Title" = "Zarządzaj swoimi testami i ostrzegaj innych"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.strings index 43c6685c1e5..404a9896457 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/ro.lproj/Localizable.strings @@ -677,7 +677,7 @@ "ExposureSubmissionQRInfo_QRCodeExpired_Alert_Title" = "Codul QR nu mai este valabil"; -"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Testul dvs. are o vechime de peste 21 de zile și nu mai poate fi înregistrat în aplicație. Dacă sunteți testat din nou în viitor, nu uitați să scanați codul QR imediat ce îl primiți."; +"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Testul dvs. are o vechime de peste 2 de zile și nu mai poate fi înregistrat în aplicație. Dacă sunteți testat din nou în viitor, nu uitați să scanați codul QR imediat ce îl primiți."; "ExposureSubmission_RAT_QR_Invalid_Alert_Title" = "Eroare"; @@ -714,6 +714,8 @@ "ExposureSubmissionSuccess_RAT_listItem3" = "Autoritatea de sănătate publică vă poate contacta în următoarele zile."; +"ExposureSubmissionSuccess_RAT_listItem4" = "Trimiteți ID-ul dvs. aleatoriu pentru a-i avertiza și pe alții."; + "ExposureSubmissionSuccess_SRS_listItem0" = "Există o probabilitate mare să fiți contagios. Izolați-vă de alte persoane."; "ExposureSubmissionSuccess_SRS_listItem1" = "Avertizarea va fi adăugată la jurnalul dvs. de contacte."; @@ -1480,9 +1482,9 @@ /* Home End of Life Thank you Card */ "Home_EndOfLifeThankYouTile_Title" = "Vă mulțumim!"; -"Home_EndOfLifeThankYouTile_description" = "Vă mulțumim că ați utilizat aplicația Corona-Warn. În timpul pandemiei, utilizatorii aplicației Corona-Warn și-au partajat diagnosticul de COVID-19 în jur de 9 milioane de ori. Datorită partajării rezultatelor de test pozitive, oamenii au putut fi avertizați rapid de existența unui risc crescut de infectare, de care altfel nu ar fi știut. Multe dintre persoanele avertizate au fost ulterior diagnosticate chiar ele cu COVID-19. Cu susținerea dvs., aplicația Corona-Warn și-a îndeplinit scopul de sistem de avertizare timpurie și a ajutat la întreruperea lanțurilor de infectare.\n\nDezvoltarea suplimentară a aplicației Corona-Warn va înceta de la 1 iunie 2023. Veți putea accesa în continuare certificatele pe care le-ați salvat deja în aplicație, precum și jurnalul de contacte. Celelalte funcții nu vor mai fi disponibile.\n\nPentru mai multe informații despre sfârșitul operațiunilor aplicației, consultați secțiunea %@."; +"Home_EndOfLifeThankYouTile_description" = "Vă mulțumim că ați utilizat aplicația Corona-Warn. În timpul pandemiei, utilizatorii aplicației Corona-Warn și-au partajat diagnosticul de COVID-19 în jur de 9 milioane de ori. Datorită partajării rezultatelor de test pozitive, oamenii au putut fi avertizați rapid de existența unui risc crescut de infectare, de care altfel nu ar fi știut. Multe dintre persoanele avertizate au fost ulterior diagnosticate chiar ele cu COVID-19. Cu susținerea dvs., aplicația Corona-Warn și-a îndeplinit scopul de sistem de avertizare timpurie și a ajutat la întreruperea lanțurilor de infectare.\n\nDezvoltarea aplicației Corona-Warn va înceta de la 1 iunie 2023. Veți putea accesa în continuare certificatele pe care le-ați salvat deja în aplicație, precum și jurnalul de contacte. Celelalte funcții nu vor mai fi disponibile."; -"Home_EndOfLifeThankYouTile_faq" = "Întrebări frecvente"; +"Home_EndOfLifeThankYouTile_faq" = "Pentru mai multe informații, consultați pagina noastră de întrebări frecvente."; /* Home Test Registration Card */ "Home_TestRegistration_Title" = "Gestionarea testelor dvs. și avertizarea celorlalți"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.strings index 8dcae8ce1d0..2a3b910f018 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/tr.lproj/Localizable.strings @@ -677,7 +677,7 @@ "ExposureSubmissionQRInfo_QRCodeExpired_Alert_Title" = "QR kod artık geçerli değil"; -"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Testiniz 21 günden eski ve artık uygulamaya kaydedilemez. İlerleyen zamanlarda yeniden test yaptırırsanız lütfen QR kodu alır almaz tarayın."; +"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Testiniz 2 günden eski ve artık uygulamaya kaydedilemez. İlerleyen zamanlarda yeniden test yaptırırsanız lütfen QR kodu alır almaz tarayın."; "ExposureSubmission_RAT_QR_Invalid_Alert_Title" = "Hata"; @@ -714,6 +714,8 @@ "ExposureSubmissionSuccess_RAT_listItem3" = "Kamu sağlığı yetkiliniz önümüzdeki birkaç gün içinde size ulaşabilir."; +"ExposureSubmissionSuccess_RAT_listItem4" = "Diğer kullanıcıların uyarılabilmesi için rastgele kimliklerinizi paylaşın."; + "ExposureSubmissionSuccess_SRS_listItem0" = "Yüksek bir olasılıkla enfekte oldunuz. Kendinizi diğer insanlardan izole edin."; "ExposureSubmissionSuccess_SRS_listItem1" = "Uyarınız temas güncenize eklenecektir."; @@ -1480,9 +1482,9 @@ /* Home End of Life Thank you Card */ "Home_EndOfLifeThankYouTile_Title" = "Teşekkür ederiz!"; -"Home_EndOfLifeThankYouTile_description" = "Corona-Warn-App'i kullandığınız için teşekkür ederiz. Pandemi sırasında Corona-Warn-App kullanıcıları yaklaşık 9 milyon kez COVID-19 tanılarını paylaştı. Bu pozitif test sonuçlarının paylaşılması sayesinde kullanıcılar, aksi takdirde haberdar olamayacakları yüksek enfeksiyon riski hakkında hızlıca uyarıldı. Uyarılan kullanıcıların çoğuna da daha sonra COVID-19 tanısı kondu. Desteğiniz sayesinde Corona-Warn-App bir erken uyarı sistemi olarak amacını yerine getirdi ve enfeksiyon zincirlerinin kırılmasına yardımcı oldu.\n\nCorona-Warn-App'in geliştirilmesi 1 Haziran 2023 tarihi itibarıyla durdurulacak. Temas güncenizin yanı sıra CWA'ya zaten kaydettiğiniz sertifikalara erişmeye devam edebilirsiniz. Diğer işlevler artık kullanılmayacaktır.\n\nUygulama işlemlerinin sona ermesiyle ilgili daha fazla bilgi için bkz. %@."; +"Home_EndOfLifeThankYouTile_description" = "Corona-Warn-App'i kullandığınız için teşekkür ederiz. Pandemi sırasında Corona-Warn-App kullanıcıları yaklaşık 9 milyon kez COVID-19 tanılarını paylaştı. Bu pozitif test sonuçlarının paylaşılması sayesinde kullanıcılar, aksi takdirde haberdar olamayacakları yüksek enfeksiyon riski hakkında hızlıca uyarıldı. Uyarılan kullanıcıların çoğuna da daha sonra COVID-19 tanısı kondu. Desteğiniz sayesinde Corona-Warn-App bir erken uyarı sistemi olarak amacını yerine getirdi ve enfeksiyon zincirlerinin kırılmasına yardımcı oldu.\n\nCorona-Warn-App'in geliştirilmesi 1 Haziran 2023 tarihi itibarıyla durdurulacak. Temas güncenizin yanı sıra uygulamada zaten kaydettiğiniz sertifikalara erişmeye devam edebilirsiniz. Diğer işlevler artık kullanılmayacaktır."; -"Home_EndOfLifeThankYouTile_faq" = "SSS"; +"Home_EndOfLifeThankYouTile_faq" = "Daha fazla bilgi için lütfen SSS sayfamıza bakın."; /* Home Test Registration Card */ "Home_TestRegistration_Title" = "Testlerinizi Yönetin ve Diğer Kullanıcıları Uyarın"; diff --git a/src/xcode/ENA/ENA/Resources/Localization/uk.lproj/Localizable.strings b/src/xcode/ENA/ENA/Resources/Localization/uk.lproj/Localizable.strings index a30b81efb63..403a15d560d 100644 --- a/src/xcode/ENA/ENA/Resources/Localization/uk.lproj/Localizable.strings +++ b/src/xcode/ENA/ENA/Resources/Localization/uk.lproj/Localizable.strings @@ -677,7 +677,7 @@ "ExposureSubmissionQRInfo_QRCodeExpired_Alert_Title" = "QR-код більше не дійсний"; -"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Вашому тесту більше 21 дня, і його більше не можна зареєструвати в застосунку. Якщо в майбутньому ви знову проходите тестування, не забудьте відсканувати QR-код, як тільки ви його отримаєте."; +"ExposureSubmissionQRInfo_QRCodeExpired_Alert_Text" = "Вашому тесту більше 2 дня, і його більше не можна зареєструвати в застосунку. Якщо в майбутньому ви знову проходите тестування, не забудьте відсканувати QR-код, як тільки ви його отримаєте."; "ExposureSubmission_RAT_QR_Invalid_Alert_Title" = "Помилка"; @@ -714,6 +714,8 @@ "ExposureSubmissionSuccess_RAT_listItem3" = "Державний орган охорони здоров’я може зв’язатися з вами протягом наступних декількох днів."; +"ExposureSubmissionSuccess_RAT_listItem4" = "Поділіться своїми випадковими ідентифікаторами, щоб інші могли бути попереджені."; + "ExposureSubmissionSuccess_SRS_listItem0" = "Велика ймовірність того, що ви заразні. Ізолюйте себе від інших людей."; "ExposureSubmissionSuccess_SRS_listItem1" = "Ваше попередження буде додано до вашого журналу контактів."; @@ -1480,9 +1482,9 @@ /* Home End of Life Thank you Card */ "Home_EndOfLifeThankYouTile_Title" = "Дякуємо!"; -"Home_EndOfLifeThankYouTile_description" = "Дякуємо за використання застосунку Corona-Warn-App. Протягом пандемії користувачі застосунку Corona-Warn-App поділилися своїми діагнозами COVID-19 приблизно 9 мільйонів разів. Завдяки такому обміну позитивними результатами тестів людей можна було швидко попередити про підвищений ризик зараження, про який вони в іншому разі не знали б. У багатьох із попереджених згодом у самих діагностували COVID-19. Завдяки вашій підтримці застосунок Corona-Warn-App виконав своє призначення як система завчасного попередження та допоміг розірвати ланцюги зараження.\n\nПодальшу розробку застосунку Corona-Warn-App буде припинено 1 червня 2023 року. Ви все одно матимете доступ до сертифікатів, які вже зберегли в CWA, а також до свого журналу контактів. Інші функції більше не будуть доступні.\n\nЩоб отримати докладнішу інформацію про завершення роботи застосунку, див. %@."; +"Home_EndOfLifeThankYouTile_description" = "Дякуємо за використання застосунку Corona-Warn-App. Протягом пандемії користувачі застосунку Corona-Warn-App поділилися своїми діагнозами COVID-19 приблизно 9 мільйонів разів. Завдяки такому обміну позитивними результатами тестів людей можна було швидко попередити про підвищений ризик зараження, про який вони в іншому разі не знали б. У багатьох із попереджених згодом у самих діагностували COVID-19. Завдяки вашій підтримці застосунок Corona-Warn-App виконав своє призначення як система завчасного попередження та допоміг розірвати ланцюги зараження.\n\nРозробку застосунку Corona-Warn-App буде припинено 1 червня 2023 року. Ви все одно матимете доступ до сертифікатів, які вже зберегли в застосунку, а також до свого журналу контактів. Інші функції більше не будуть доступні."; -"Home_EndOfLifeThankYouTile_faq" = "ЗіВ"; +"Home_EndOfLifeThankYouTile_faq" = "Щоб отримати додаткову інформацію, див. нашу сторінку ЗіВ."; /* Home Test Registration Card */ "Home_TestRegistration_Title" = "Керуйте своїми тестами та попереджайте інших"; From 5b71c521c4074462353e12787e8284afe7827f9a Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 16 Mar 2023 13:51:17 +0100 Subject: [PATCH 132/137] fix condition --- .../Source/AppDelegate & Globals/CWAHibernationProvider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift index 0dd459cd6f9..475e51c1ec3 100644 --- a/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift +++ b/src/xcode/ENA/ENA/Source/AppDelegate & Globals/CWAHibernationProvider.swift @@ -33,7 +33,7 @@ class CWAHibernationProvider: RequiresAppDependencies { return LaunchArguments.endOfLife.isHibernationStateEnabled.boolValue } // check if we are using unit testing environment then we return an expected value true or false based on the unit test - if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil { + if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil && customStore == nil { return UserDefaults.standard.bool(forKey: CWAHibernationProvider.isHibernationInUnitTest) } #endif From a1341913893b2c315d5181900ed8a83a38825408 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Thu, 16 Mar 2023 17:54:17 +0500 Subject: [PATCH 133/137] fixing UI tests --- .../ENAUITests_02_AppInformation.swift | 14 +++++++------- src/xcode/ENA/ENAUITests/AppStore/ENAUITests.swift | 4 ++-- .../ENAUITests_07_ContactJournalUITests.swift | 2 +- .../ENAUITests_04b_ExposureDetection.swift | 2 +- .../ENAUITests_04a_ExposureSubmission.swift | 2 +- .../ENA/ENAUITests/Home/ENAUITests_01a_Home.swift | 6 +++--- .../Onboarding/ENAUITests_00_Onboarding.swift | 8 ++++---- .../RecycleBin/ENAUITests_18_RecycleBin.swift | 4 ++-- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/xcode/ENA/ENAUITests/AppInformation/ENAUITests_02_AppInformation.swift b/src/xcode/ENA/ENAUITests/AppInformation/ENAUITests_02_AppInformation.swift index 59548b02617..fbcbf8db907 100644 --- a/src/xcode/ENA/ENAUITests/AppInformation/ENAUITests_02_AppInformation.swift +++ b/src/xcode/ENA/ENAUITests/AppInformation/ENAUITests_02_AppInformation.swift @@ -20,7 +20,7 @@ class ENAUITests_02_AppInformation: CWATestCase { func test_0020_AppInformationFlow() throws { app.launch() // only run if onboarding screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) // assert cells let moreCell = app.cells[AccessibilityIdentifiers.Home.MoreInfoCell.moreCell] @@ -39,7 +39,7 @@ class ENAUITests_02_AppInformation: CWATestCase { app.launch() // only run if onboarding screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) // assert cells let moreCell = app.cells[AccessibilityIdentifiers.Home.MoreInfoCell.moreCell] @@ -55,7 +55,7 @@ class ENAUITests_02_AppInformation: CWATestCase { app.launch() // only run if onboarding screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) // assert cells let moreCell = app.cells[AccessibilityIdentifiers.Home.MoreInfoCell.moreCell] @@ -71,7 +71,7 @@ class ENAUITests_02_AppInformation: CWATestCase { app.launch() // only run if onboarding screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .long)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .long)) // assert cells let moreCell = app.cells[AccessibilityIdentifiers.Home.MoreInfoCell.moreCell] @@ -92,7 +92,7 @@ class ENAUITests_02_AppInformation: CWATestCase { app.launch() // only run if onboarding screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) // assert cells let moreCell = app.cells[AccessibilityIdentifiers.Home.MoreInfoCell.moreCell] @@ -166,7 +166,7 @@ class ENAUITests_02_AppInformation: CWATestCase { func test_0028_AppInformationFlow_PrivacyScreen() throws { app.setLaunchArgument(LaunchArguments.errorReport.elsLogActive, to: false) app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .long)) navigateToErrorReporting() XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.ErrorReport.topBody].waitForExistence(timeout: .short)) @@ -179,7 +179,7 @@ class ENAUITests_02_AppInformation: CWATestCase { app.launch() // only run if onboarding screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) // assert cells let moreCell = app.cells[AccessibilityIdentifiers.Home.MoreInfoCell.moreCell] diff --git a/src/xcode/ENA/ENAUITests/AppStore/ENAUITests.swift b/src/xcode/ENA/ENAUITests/AppStore/ENAUITests.swift index 072eead6ab5..a414761be41 100644 --- a/src/xcode/ENA/ENAUITests/AppStore/ENAUITests.swift +++ b/src/xcode/ENA/ENAUITests/AppStore/ENAUITests.swift @@ -44,7 +44,7 @@ class ENAUITests: CWATestCase { // ScreenShot_0002: Homescreen (low risk) try navigateThroughOnboarding() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) if snapshotsActive { snapshot("AppStore_0002") } // ScreenShot_0003: Risk view (low risk) @@ -54,7 +54,7 @@ class ENAUITests: CWATestCase { // ScreenShot_0004: Settings > Risk exposure app.buttons["AppStrings.AccessibilityLabel.close"].waitAndTap() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) app.swipeUp(velocity: .slow) // ScreenShot_0004: Settings > Risk exposure app.swipeUp() // the home screen got longer and for some reason we have to scroll to `tap()` diff --git a/src/xcode/ENA/ENAUITests/ContactJournal/ENAUITests_07_ContactJournalUITests.swift b/src/xcode/ENA/ENAUITests/ContactJournal/ENAUITests_07_ContactJournalUITests.swift index 8670c2b68d9..9e2a0b0d7fa 100644 --- a/src/xcode/ENA/ENAUITests/ContactJournal/ENAUITests_07_ContactJournalUITests.swift +++ b/src/xcode/ENA/ENAUITests/ContactJournal/ENAUITests_07_ContactJournalUITests.swift @@ -717,7 +717,7 @@ class ENAUITests_07_ContactJournal: CWATestCase { private func launch() { app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .long)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .long)) } /// we will search for the given identifier inside a scrollable element diff --git a/src/xcode/ENA/ENAUITests/ExposureDetection/ENAUITests_04b_ExposureDetection.swift b/src/xcode/ENA/ENAUITests/ExposureDetection/ENAUITests_04b_ExposureDetection.swift index eab7ee4674d..177d2104607 100644 --- a/src/xcode/ENA/ENAUITests/ExposureDetection/ENAUITests_04b_ExposureDetection.swift +++ b/src/xcode/ENA/ENAUITests/ExposureDetection/ENAUITests_04b_ExposureDetection.swift @@ -55,7 +55,7 @@ class ENAUITests_04b_ExposureDetection: CWATestCase { private func launch() { app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .long)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .long)) } } diff --git a/src/xcode/ENA/ENAUITests/ExposureSubmission/ENAUITests_04a_ExposureSubmission.swift b/src/xcode/ENA/ENAUITests/ExposureSubmission/ENAUITests_04a_ExposureSubmission.swift index 100d7b9e8e0..eeaa4e49e7f 100644 --- a/src/xcode/ENA/ENAUITests/ExposureSubmission/ENAUITests_04a_ExposureSubmission.swift +++ b/src/xcode/ENA/ENAUITests/ExposureSubmission/ENAUITests_04a_ExposureSubmission.swift @@ -885,7 +885,7 @@ extension ENAUITests_04a_ExposureSubmission { /// Launch and wait until the app is ready. private func launch() { app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .long)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .long)) // "COVID-19-Begegnungsmitteilungen aktivieren …" popup guard app.alerts.firstMatch.buttons["Aktivieren"].waitForExistence(timeout: 2) else { return diff --git a/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift b/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift index 9d1f8761f4d..f2d33af9b0f 100644 --- a/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift +++ b/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift @@ -25,7 +25,7 @@ class ENAUITests_01a_Home: CWATestCase { app.launch() // only run if home screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) app.swipeUp() // assert cells @@ -52,7 +52,7 @@ class ENAUITests_01a_Home: CWATestCase { app.launch() // only run if home screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) app.swipeUp() // assert cells @@ -79,7 +79,7 @@ class ENAUITests_01a_Home: CWATestCase { app.launch() // only run if home screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) app.swipeUp() app.swipeUp() diff --git a/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift b/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift index 40dcb4c3ed6..36522e896a6 100644 --- a/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift +++ b/src/xcode/ENA/ENAUITests/Onboarding/ENAUITests_00_Onboarding.swift @@ -94,8 +94,8 @@ class ENAUITests_00_Onboarding: CWATestCase { XCTAssertTrue(app.buttons[AccessibilityIdentifiers.General.primaryFooterButton].waitForExistence(timeout: 5.0)) app.buttons[AccessibilityIdentifiers.General.secondaryFooterButton].waitAndTap() - // check that the homescreen element AppStrings.home.activateTitle is visible onscreen - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: 5.0)) + // check that the homescreen element AccessibilityIdentifiers.Home.AppClosureNoticeCell is visible onscreen + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: 5.0)) } func test_0001_OnboardingFlow_EnablePermissions_normal_XS() throws { @@ -153,8 +153,8 @@ class ENAUITests_00_Onboarding: CWATestCase { XCTAssertTrue(app.buttons[AccessibilityIdentifiers.General.primaryFooterButton].waitForExistence(timeout: 5.0)) app.buttons[AccessibilityIdentifiers.General.secondaryFooterButton].waitAndTap() - // check that the homescreen element AppStrings.home.activateTitle is visible onscreen - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: 5.0)) + // check that the homescreen element AccessibilityIdentifiers.Home.AppClosureNoticeCell is visible onscreen + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: 5.0)) } diff --git a/src/xcode/ENA/ENAUITests/RecycleBin/ENAUITests_18_RecycleBin.swift b/src/xcode/ENA/ENAUITests/RecycleBin/ENAUITests_18_RecycleBin.swift index a5345d2eb83..1b0f553dabf 100644 --- a/src/xcode/ENA/ENAUITests/RecycleBin/ENAUITests_18_RecycleBin.swift +++ b/src/xcode/ENA/ENAUITests/RecycleBin/ENAUITests_18_RecycleBin.swift @@ -23,7 +23,7 @@ class ENAUITests_18_RecycleBin: CWATestCase { app.launch() /// Wait until Home Screen is ready - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) /// Open Recycling Bin screen let moreCell = app.cells[AccessibilityIdentifiers.Home.MoreInfoCell.moreCell] @@ -81,7 +81,7 @@ class ENAUITests_18_RecycleBin: CWATestCase { app.launch() /// Wait until Home Screen is ready - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .medium)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) /// Open recycle bin screen let moreCell = app.cells[AccessibilityIdentifiers.Home.MoreInfoCell.moreCell] From f25d94a1446a1544d7b2fb6e47eeb99e3946a164 Mon Sep 17 00:00:00 2001 From: Naveed Khalid Date: Thu, 16 Mar 2023 18:47:38 +0500 Subject: [PATCH 134/137] fixing more UI tests --- .../ENAUITests_02_AppInformation.swift | 10 +++++----- .../ENAUITests_04c_ExposureLogging.swift | 4 ++-- .../ENA/ENAUITests/Home/ENAUITests_01a_Home.swift | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/xcode/ENA/ENAUITests/AppInformation/ENAUITests_02_AppInformation.swift b/src/xcode/ENA/ENAUITests/AppInformation/ENAUITests_02_AppInformation.swift index fbcbf8db907..8e0af1f7f0f 100644 --- a/src/xcode/ENA/ENAUITests/AppInformation/ENAUITests_02_AppInformation.swift +++ b/src/xcode/ENA/ENAUITests/AppInformation/ENAUITests_02_AppInformation.swift @@ -106,7 +106,7 @@ class ENAUITests_02_AppInformation: CWATestCase { func test_0026a_AppInformationFlow_ErrorReportsShouldBeActiveForDebugAsDefault() throws { app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) navigateToErrorReporting() XCTAssertTrue(app.buttons[AccessibilityIdentifiers.ErrorReport.stopAndDeleteButton].exists) @@ -115,7 +115,7 @@ class ENAUITests_02_AppInformation: CWATestCase { func test_0026_AppInformationFlow_ErrorReports() throws { app.setLaunchArgument(LaunchArguments.errorReport.elsLogActive, to: false) app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) navigateToErrorReporting() XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.ErrorReport.topBody].waitForExistence(timeout: .short)) @@ -135,7 +135,7 @@ class ENAUITests_02_AppInformation: CWATestCase { func test_0027_AppInformationFlow_ErrorReportsStart() throws { app.setLaunchArgument(LaunchArguments.errorReport.elsLogActive, to: false) app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) navigateToErrorReporting() XCTAssertTrue(app.staticTexts[AccessibilityIdentifiers.ErrorReport.topBody].waitForExistence(timeout: .short)) @@ -196,7 +196,7 @@ class ENAUITests_02_AppInformation: CWATestCase { func test_0030_AppInformationFlow_ConfirmationScreen_ErrorReportDetailScreen() throws { app.setLaunchArgument(LaunchArguments.errorReport.elsLogActive, to: false) app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) navigateToErrorReporting() app.buttons[AccessibilityIdentifiers.ErrorReport.startButton].waitAndTap() @@ -213,7 +213,7 @@ class ENAUITests_02_AppInformation: CWATestCase { app.setLaunchArgument(LaunchArguments.errorReport.elsLogActive, to: false) app.setLaunchArgument(LaunchArguments.errorReport.elsCreateFakeHistory, to: true) app.launch() - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) navigateToErrorReporting() // Test Navigation to History diff --git a/src/xcode/ENA/ENAUITests/ExposureLogging/ENAUITests_04c_ExposureLogging.swift b/src/xcode/ENA/ENAUITests/ExposureLogging/ENAUITests_04c_ExposureLogging.swift index a35ff782af2..00a7b7dad32 100644 --- a/src/xcode/ENA/ENAUITests/ExposureLogging/ENAUITests_04c_ExposureLogging.swift +++ b/src/xcode/ENA/ENAUITests/ExposureLogging/ENAUITests_04c_ExposureLogging.swift @@ -26,7 +26,7 @@ class ENAUITests_04c_ExposureLogging: CWATestCase { app.launch() // only run if home screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: 5.0)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) app.cells["AppStrings.Home.activateCardOnTitle"].waitAndTap() } @@ -38,7 +38,7 @@ class ENAUITests_04c_ExposureLogging: CWATestCase { app.launch() // only run if home screen is present - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: 5.0)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) app.cells["AppStrings.Home.activateCardOffTitle"].waitAndTap() } diff --git a/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift b/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift index f2d33af9b0f..8f42232c30b 100644 --- a/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift +++ b/src/xcode/ENA/ENAUITests/Home/ENAUITests_01a_Home.swift @@ -144,7 +144,7 @@ class ENAUITests_01a_Home: CWATestCase { let highRiskTitle = String(format: AccessibilityLabels.localized(AppStrings.Home.riskCardHighNumberContactsItemTitle), 4) XCTAssertTrue(app.otherElements[highRiskTitle].waitForExistence(timeout: .medium)) - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) } func test_homescreen_riskCardLow_riskMultipleDays() throws { @@ -167,7 +167,7 @@ class ENAUITests_01a_Home: CWATestCase { let lowRiskTitle = String(format: AccessibilityLabels.localized(AppStrings.Home.riskCardLowNumberContactsItemTitle), 4) XCTAssertTrue(app.otherElements[lowRiskTitle].waitForExistence(timeout: .short)) - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) } func test_homescreen_riskCardLow_Ndays() throws { @@ -213,7 +213,7 @@ class ENAUITests_01a_Home: CWATestCase { // Inactive risk card title "Risiko-Ermittlung gestoppt" XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.RiskTableViewCell.topContainer].waitForExistence(timeout: .short)) - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) } @@ -377,7 +377,7 @@ class ENAUITests_01a_Home: CWATestCase { let highRiskTitle = String(format: AccessibilityLabels.localized(AppStrings.Home.riskCardHighNumberContactsItemTitle), 1) XCTAssertTrue(app.otherElements[highRiskTitle].waitForExistence(timeout: .short)) - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) snapshot("homescreenrisk_level_\(riskLevel)_risk_one_day_\(String(format: "%04d", (screenshotCounter.inc() )))") } @@ -401,7 +401,7 @@ class ENAUITests_01a_Home: CWATestCase { let lowRiskTitle = String(format: AccessibilityLabels.localized(AppStrings.Home.riskCardLowNumberContactsItemTitle), numberOfDaysWithLowRisk) XCTAssertTrue(app.otherElements[lowRiskTitle].waitForExistence(timeout: .long)) - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) snapshot("homescreenrisk_level_\(riskLevel)_risk_no_days_\(String(format: "%04d", (screenshotCounter.inc() )))") } @@ -426,7 +426,7 @@ class ENAUITests_01a_Home: CWATestCase { let lowRiskTitle = String(format: AccessibilityLabels.localized(AppStrings.Home.riskCardLowNumberContactsItemTitle), 1) XCTAssertTrue(app.otherElements[lowRiskTitle].waitForExistence(timeout: .short)) - XCTAssertTrue(app.buttons[AccessibilityIdentifiers.Home.rightBarButtonDescription].waitForExistence(timeout: .short)) + XCTAssertTrue(app.cells[AccessibilityIdentifiers.Home.AppClosureNoticeCell.container].waitForExistence(timeout: .medium)) snapshot("homescreenrisk_level_\(riskLevel)_risk_one_day_\(String(format: "%04d", (screenshotCounter.inc() )))") } From 0d86df6c3157cd39522221edbad3535e76d760ea Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Thu, 16 Mar 2023 17:40:26 +0100 Subject: [PATCH 135/137] bump version to 3.2.0 6 --- src/xcode/ENA/ENA.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj index 42bbdbbbf6f..801689340e3 100644 --- a/src/xcode/ENA/ENA.xcodeproj/project.pbxproj +++ b/src/xcode/ENA/ENA.xcodeproj/project.pbxproj @@ -13181,7 +13181,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENACommunity.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = $IPHONE_APP_DEV_TEAM; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13336,7 +13336,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13515,7 +13515,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info_Testflight.plist; @@ -13757,7 +13757,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENATest.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = 523TP53AQF; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -13797,7 +13797,7 @@ CODE_SIGN_ENTITLEMENTS = "${PROJECT}/Resources/ENA.entitlements"; CODE_SIGN_IDENTITY = $IPHONE_APP_CODE_SIGN_IDENTITY; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; GCC_PREPROCESSOR_DEFINITIONS = "SQLITE_HAS_CODEC=1"; INFOPLIST_FILE = ENA/Resources/Info.plist; IPHONE_APP_CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -13940,7 +13940,7 @@ CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -13984,7 +13984,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -14027,7 +14027,7 @@ CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; From 61703c4ed35088efd17e1c69f82b0ce854240602 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Fri, 17 Mar 2023 08:12:08 +0100 Subject: [PATCH 136/137] fix for the wierd store crash --- .../HealthCertificateNotificationService.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift index c6936ecb405..814ee04c16d 100644 --- a/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift +++ b/src/xcode/ENA/ENA/Source/Services/HealthCertificate/HealthCertificateNotificationService.swift @@ -17,12 +17,12 @@ class HealthCertificateNotificationService { } // MARK: - Internal - + func createNotifications( for healthCertificate: HealthCertificate, completion: @escaping () -> Void ) { - guard !isHibernationState else { + guard !CWAHibernationProvider.shared.isHibernationState else { completion() return } @@ -104,7 +104,7 @@ class HealthCertificateNotificationService { previousBoosterNotificationIdentifier: String?, completion: @escaping () -> Void ) { - guard !isHibernationState else { + guard !CWAHibernationProvider.shared.isHibernationState else { completion() return } @@ -138,7 +138,7 @@ class HealthCertificateNotificationService { previousCertificateReissuance: DCCCertificateReissuance?, completion: @escaping () -> Void ) { - guard !isHibernationState else { + guard !CWAHibernationProvider.shared.isHibernationState else { completion() return } @@ -173,7 +173,7 @@ class HealthCertificateNotificationService { previousAdmissionStateIdentifier: String?, completion: @escaping () -> Void ) { - guard !isHibernationState else { + guard !CWAHibernationProvider.shared.isHibernationState else { completion() return } @@ -370,6 +370,5 @@ class HealthCertificateNotificationService { } } - private let isHibernationState = CWAHibernationProvider.shared.isHibernationState } From ea1aa1bb970c9a90b70fe1614297a95b0aae71bb Mon Sep 17 00:00:00 2001 From: Omar Ahmed Date: Fri, 17 Mar 2023 09:03:07 +0100 Subject: [PATCH 137/137] fix missed case --- .../ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift index 3fc532fa341..4d8cce14720 100644 --- a/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift +++ b/src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift @@ -136,6 +136,8 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega setupLeftBarButtonItem() setupTableView() + /// call onDidBecomeActiveNotification() one time at app start to check for Hibernation state as it will not be called unless the app moves from background to foreground + onDidBecomeActiveNotification() navigationItem.largeTitleDisplayMode = .automatic tableView.backgroundColor = .enaColor(for: .darkBackground)