Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

Fix/6551 error messages and other bugs #2488

Merged
merged 21 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cd9fd84
Update home screen with correct state by switching to the main thread
nickguendling Apr 20, 2021
0fc69c8
Add back localized error messages
nickguendling Apr 20, 2021
3a6df65
Load test results separately to get appropriate error handling
nickguendling Apr 20, 2021
7b4ad80
Set test result to pending after loading in case the loading failed
nickguendling Apr 20, 2021
8ce89ee
Put setup un separate func
nickguendling Apr 20, 2021
42e89e8
Fix warn others reminder logic
nickguendling Apr 20, 2021
62d021e
Reset checkins when entering checkin selection screen
nickguendling Apr 20, 2021
1c2c3e1
Correctly update home screen without dispatching to the main queue
nickguendling Apr 20, 2021
8b50911
Merge branch 'release/2.1.x' into fix/6551-error-messages
marcussc Apr 20, 2021
6cd1450
Adjust expected onUpdate count
nickguendling Apr 20, 2021
020791a
Merge branch 'fix/6551-error-messages' of github.com:corona-warn-app/…
nickguendling Apr 20, 2021
153a731
Merge branch 'release/2.1.x' into fix/6551-error-messages
nickguendling Apr 20, 2021
d109bf3
Fix background color on home screen
nickguendling Apr 20, 2021
345b592
Remove warn others view controller initialization duplication
nickguendling Apr 20, 2021
7c27ab1
Fix test
nickguendling Apr 20, 2021
edb9242
Merge branch 'release/2.1.x' into fix/6551-error-messages
nickguendling Apr 20, 2021
bb6928e
Merge branch 'release/2.1.x' into fix/6551-error-messages
nickguendling Apr 20, 2021
933971a
Remove newline
nickguendling Apr 20, 2021
63e42da
Merge branch 'fix/6551-error-messages' of github.com:corona-warn-app/…
nickguendling Apr 20, 2021
9357794
Use previous supported countries handling
nickguendling Apr 21, 2021
ff7acdc
Merge branch 'release/2.1.x' into fix/6551-error-messages
nickguendling Apr 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,31 @@ extension URLSession.Response {

typealias Completion = (Result<URLSession.Response, Failure>) -> Void
}

extension URLSession.Response.Failure: LocalizedError {
var errorDescription: String? {
switch self {
case let .serverError(code):
return "\(AppStrings.ExposureSubmissionError.other)\(code)\(AppStrings.ExposureSubmissionError.otherend)"
case let .httpError(desc, _):
return "\(AppStrings.ExposureSubmissionError.httpError)\n\(desc)"
case .invalidResponse:
return AppStrings.ExposureSubmissionError.invalidResponse
case .noResponse:
return AppStrings.ExposureSubmissionError.noResponse
case .noNetworkConnection:
return AppStrings.ExposureSubmissionError.noNetworkConnection
case .qrAlreadyUsed:
return AppStrings.ExposureSubmissionError.qrAlreadyUsed
case .qrDoesNotExist:
return AppStrings.ExposureSubmissionError.qrNotExist
case .teleTanAlreadyUsed:
return AppStrings.ExposureSubmissionError.teleTanAlreadyUsed
case .regTokenNotExist:
return AppStrings.ExposureSubmissionError.regTokenNotExist
default:
Log.error("\(self)", log: .api)
return AppStrings.ExposureSubmissionError.defaultError
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class ExposureSubmissionCoordinator: NSObject, RequiresAppDependencies {

func start(with coronaTestType: CoronaTestType? = nil) {
model.coronaTestType = coronaTestType
start(with: getInitialViewController())

start(with: self.getInitialViewController())
}

func start(with testInformationResult: Result<CoronaTestQRCodeInformation, QRCodeError>) {
Expand Down Expand Up @@ -119,7 +120,7 @@ class ExposureSubmissionCoordinator: NSObject, RequiresAppDependencies {
if !coronaTest.positiveTestResultWasShown {
return createTestResultAvailableViewController()
} else {
return createWarnOthersViewController()
return createWarnOthersViewController(supportedCountries: model.exposureSubmissionService.supportedCountries)
}
} else {
return createTestResultViewController()
Expand Down Expand Up @@ -327,12 +328,13 @@ class ExposureSubmissionCoordinator: NSObject, RequiresAppDependencies {
return topBottomContainerViewController
}

private func createWarnOthersViewController() -> UIViewController {
private func createWarnOthersViewController(supportedCountries: [Country]) -> UIViewController {
Analytics.collect(.keySubmissionMetadata(.lastSubmissionFlowScreen(.submissionFlowScreenWarnOthers)))

let vc = ExposureSubmissionWarnOthersViewController(
viewModel: ExposureSubmissionWarnOthersViewModel(
supportedCountries: model.exposureSubmissionService.supportedCountries) { [weak self] in
supportedCountries: supportedCountries
) { [weak self] in
self?.showTestResultAvailableCloseAlert()
},
onPrimaryButtonTap: { [weak self] isLoading in
Expand Down Expand Up @@ -557,6 +559,9 @@ class ExposureSubmissionCoordinator: NSObject, RequiresAppDependencies {
showNextScreen()
return
}

/// Reset checkins when entering the screen in case the user skips, cancels or stays on the screen during background submission
model.exposureSubmissionService.checkins = []

let footerViewModel = FooterViewModel(
primaryButtonName: AppStrings.ExposureSubmissionCheckins.continueButton,
Expand All @@ -572,13 +577,11 @@ class ExposureSubmissionCoordinator: NSObject, RequiresAppDependencies {
showNextScreen()
},
onSkip: { [weak self] in
self?.model.exposureSubmissionService.checkins = []
self?.showSkipCheckinsAlert(dontShareHandler: {
showNextScreen()
})
},
onDismiss: { [weak self] in
self?.model.exposureSubmissionService.checkins = []
if self?.model.coronaTest?.positiveTestResultWasShown == true {
self?.showSkipCheckinsAlert(dontShareHandler: {
Analytics.collect(.keySubmissionMetadata(.submittedAfterCancel(true)))
Expand All @@ -603,52 +606,8 @@ class ExposureSubmissionCoordinator: NSObject, RequiresAppDependencies {
// MARK: Late consent

private func showWarnOthersScreen(supportedCountries: [Country]) {
Analytics.collect(.keySubmissionMetadata(.lastSubmissionFlowScreen(.submissionFlowScreenWarnOthers)))
let viewModel = ExposureSubmissionWarnOthersViewModel(supportedCountries: supportedCountries) { [weak self] in
self?.showTestResultAvailableCloseAlert()
}
let vc = ExposureSubmissionWarnOthersViewController(
viewModel: viewModel,
onPrimaryButtonTap: { [weak self] isLoading in
self?.model.setSubmissionConsentGiven(true)
self?.model.exposureSubmissionService.getTemporaryExposureKeys { error in
isLoading(false)

guard let error = error else {
self?.showCheckinsScreen()
return
}

self?.model.setSubmissionConsentGiven(false)

// User selected "Don't Share" / "Nicht teilen"
if error == .notAuthorized {
Log.info("OS submission authorization was declined.")
} else {
Log.error("\(#function) error", log: .ui, error: error)
self?.showErrorAlert(for: error)
}
}
},
dismiss: { [weak self] in self?.dismiss() }
)

let footerViewController = FooterViewController(
FooterViewModel(
primaryButtonName: AppStrings.ExposureSubmissionQRInfo.primaryButtonTitle,
primaryIdentifier: AccessibilityIdentifiers.ExposureSubmission.primaryButton,
secondaryIdentifier: AccessibilityIdentifiers.ExposureSubmission.secondaryButton,
isSecondaryButtonEnabled: false,
isSecondaryButtonHidden: true
)
)

let topBottomContainerViewController = TopBottomContainerViewController(
topController: vc,
bottomController: footerViewController
)

push(topBottomContainerViewController)
let vc = createWarnOthersViewController(supportedCountries: supportedCountries)
push(vc)
}

private func showThankYouScreen() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,36 @@ class HomeTestResultCellModel {
) {
self.coronaTestType = coronaTestType
self.coronaTestService = coronaTestService
self.onUpdate = onUpdate

setup()
}

// MARK: - Internal

@OpenCombine.Published var title: String! = ""
@OpenCombine.Published var subtitle: String?
naveeddotio marked this conversation as resolved.
Show resolved Hide resolved
@OpenCombine.Published var description: String! = ""
@OpenCombine.Published var footnote: String?
naveeddotio marked this conversation as resolved.
Show resolved Hide resolved
@OpenCombine.Published var buttonTitle: String! = ""
@OpenCombine.Published var image: UIImage?
@OpenCombine.Published var isDisclosureIndicatorHidden: Bool = false
@OpenCombine.Published var isNegativeDiagnosisHidden: Bool = true
@OpenCombine.Published var isActivityIndicatorHidden: Bool = false
@OpenCombine.Published var isUserInteractionEnabled: Bool = false
@OpenCombine.Published var isCellTappable: Bool = true
@OpenCombine.Published var accessibilityIdentifier: String! = AccessibilityIdentifiers.Home.submitCardButton

// MARK: - Private

private let coronaTestType: CoronaTestType
private let coronaTestService: CoronaTestService
private let onUpdate: () -> Void

private var subscriptions = Set<AnyCancellable>()

// swiftlint:disable:next cyclomatic_complexity
private func setup() {
switch coronaTestType {
case .pcr:
title = AppStrings.Home.TestResult.pcrTitle
Expand All @@ -30,16 +59,20 @@ class HomeTestResultCellModel {
}

self?.configure(for: pcrTest.testResult)
onUpdate()
self?.onUpdate()
}
.store(in: &subscriptions)

coronaTestService.$pcrTestResultIsLoading
.receive(on: DispatchQueue.OCombine(.main))
.sink { [weak self] testResultIsLoading in
if testResultIsLoading && self?.coronaTestService.pcrTest?.finalTestResultReceivedDate == nil {
self?.configureLoading()
onUpdate()
if self?.coronaTestService.pcrTest?.finalTestResultReceivedDate == nil {
if testResultIsLoading {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isTestResultLoading ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way it makes a correct english sentence: "If test result is loading [do x]" I admit being inconsistent with this, but would like to keep it that way.

Copy link
Contributor

@naveeddotio naveeddotio Apr 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more of a personal style and how you prefer, actually I saw isActivityIndicatorHidden in the next line, so in that context, I found it to be little inconsistent. Anyhow, you have my vote :)

self?.configureLoading()
} else if self?.isActivityIndicatorHidden == false {
self?.configureTestResultPending()
}
self?.onUpdate()
}
}
.store(in: &subscriptions)
Expand All @@ -58,16 +91,20 @@ class HomeTestResultCellModel {
}

self.configure(for: antigenTest.testResult)
onUpdate()
self.onUpdate()
}
.store(in: &subscriptions)

coronaTestService.$antigenTestResultIsLoading
.receive(on: DispatchQueue.OCombine(.main))
.sink { [weak self] testResultIsLoading in
if testResultIsLoading && self?.coronaTestService.antigenTest?.finalTestResultReceivedDate == nil {
self?.configureLoading()
onUpdate()
if self?.coronaTestService.antigenTest?.finalTestResultReceivedDate == nil {
if testResultIsLoading {
self?.configureLoading()
} else if self?.isActivityIndicatorHidden == false {
self?.configureTestResultPending()
}
self?.onUpdate()
}
}
.store(in: &subscriptions)
Expand All @@ -80,33 +117,12 @@ class HomeTestResultCellModel {
}

self?.configureTestResultOutdated()
onUpdate()
self?.onUpdate()
}
.store(in: &subscriptions)
}
}

// MARK: - Internal

@OpenCombine.Published var title: String! = ""
@OpenCombine.Published var subtitle: String?
@OpenCombine.Published var description: String! = ""
@OpenCombine.Published var footnote: String?
@OpenCombine.Published var buttonTitle: String! = ""
@OpenCombine.Published var image: UIImage?
@OpenCombine.Published var isDisclosureIndicatorHidden: Bool = false
@OpenCombine.Published var isNegativeDiagnosisHidden: Bool = true
@OpenCombine.Published var isActivityIndicatorHidden: Bool = false
@OpenCombine.Published var isUserInteractionEnabled: Bool = false
@OpenCombine.Published var isCellTappable: Bool = true
@OpenCombine.Published var accessibilityIdentifier: String! = AccessibilityIdentifiers.Home.submitCardButton

// MARK: - Private

private let coronaTestType: CoronaTestType
private let coronaTestService: CoronaTestService
private var subscriptions = Set<AnyCancellable>()

private func configure(for testResult: TestResult) {
#if DEBUG
if isUITesting {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class HomeTestResultCellModelTests: XCTestCase {
expectationIndicatorVisibility.expectedFulfillmentCount = indicatorVisibilityArray.count
expectationUserInteraction.expectedFulfillmentCount = userInteractionArray.count
expectationAccessibilityIdentifiers.expectedFulfillmentCount = accessibilityIdentifiersArray.count
expectationOnUpdate.expectedFulfillmentCount = accessibilityIdentifiersArray.count
expectationOnUpdate.expectedFulfillmentCount = 7

let coronaTestService = CoronaTestService(
client: ClientMock(),
Expand Down
38 changes: 35 additions & 3 deletions src/xcode/ENA/ENA/Source/Scenes/Home/HomeTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega
setupTableView()

navigationItem.largeTitleDisplayMode = .automatic
tableView.backgroundColor = .enaColor(for: .separator)
tableView.backgroundColor = .enaColor(for: .darkBackground)

NotificationCenter.default.addObserver(self, selector: #selector(refreshUIAfterResumingFromBackground), name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(refreshUI), name: NSNotification.Name.NSCalendarDayChanged, object: nil)
Expand Down Expand Up @@ -181,15 +181,47 @@ class HomeTableViewController: UITableViewController, NavigationBarOpacityDelega
}

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
UIView()
guard HomeTableViewModel.Section(rawValue: section) == .settings else {
return UIView()
}

let headerView = UIView()
headerView.backgroundColor = .enaColor(for: .separator)

return headerView
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return viewModel.heightForHeader(in: section)
}

override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
UIView()
if HomeTableViewModel.Section(rawValue: section) == .infos {
let footerView = UIView()
footerView.backgroundColor = .enaColor(for: .separator)

return footerView
} else if HomeTableViewModel.Section(rawValue: section) == .settings {
let footerView = UIView()

let colorView = UIView()
colorView.backgroundColor = .enaColor(for: .separator)

footerView.addSubview(colorView)
colorView.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
colorView.leadingAnchor.constraint(equalTo: footerView.leadingAnchor),
colorView.topAnchor.constraint(equalTo: footerView.topAnchor),
colorView.trailingAnchor.constraint(equalTo: footerView.trailingAnchor),
// Extend the last footer view so the color is shown even when rubber banding the scroll view
colorView.bottomAnchor.constraint(equalTo: footerView.bottomAnchor, constant: UIScreen.main.bounds.height)
])

return footerView
} else {
return UIView()
}
}

override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
Expand Down
Loading