From 913070c16ce52e8147dd3bedab5c8f5664a4a660 Mon Sep 17 00:00:00 2001 From: Yannick Spreen Date: Wed, 5 May 2021 14:56:51 +0200 Subject: [PATCH] Add settings screen. (#48) --- DGCAVerifier.xcodeproj/project.pbxproj | 10 ++ DGCAVerifier/Services/GatewayConnection.swift | 11 +- .../Storyboards/CertificateViewer.storyboard | 18 +-- DGCAVerifier/Storyboards/Settings.storyboard | 118 ++++++++++++++++++ DGCAVerifier/ViewControllers/Scan.swift | 26 +++- DGCAVerifier/ViewControllers/Settings.swift | 73 +++++++++++ 6 files changed, 236 insertions(+), 20 deletions(-) create mode 100644 DGCAVerifier/Storyboards/Settings.storyboard create mode 100644 DGCAVerifier/ViewControllers/Settings.swift diff --git a/DGCAVerifier.xcodeproj/project.pbxproj b/DGCAVerifier.xcodeproj/project.pbxproj index 4d52aa2..c254b41 100644 --- a/DGCAVerifier.xcodeproj/project.pbxproj +++ b/DGCAVerifier.xcodeproj/project.pbxproj @@ -16,6 +16,8 @@ CE1F155C2639F9E700736D48 /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = CE1F155B2639F9E700736D48 /* SwiftyJSON */; }; CE37B643263867D700DEE13D /* SecureBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE37B642263867D700DEE13D /* SecureBackground.swift */; }; CE56B5052639F48E00FB31B1 /* SwiftDGC in Frameworks */ = {isa = PBXBuildFile; productRef = CE56B5042639F48E00FB31B1 /* SwiftDGC */; }; + CE59D1B426428782004EBDD6 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE59D1B326428782004EBDD6 /* Settings.storyboard */; }; + CE59D1B626428D78004EBDD6 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE59D1B526428D78004EBDD6 /* Settings.swift */; }; CE8096D9263B07BB00A65AD6 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8096D8263B07BB00A65AD6 /* UIColor.swift */; }; CE81533C263FF8FE0030D777 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = CE81533B263FF8FE0030D777 /* README.md */; }; CE8912F52634C60E00CB92AF /* GatewayConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8912F42634C60E00CB92AF /* GatewayConnection.swift */; }; @@ -60,6 +62,8 @@ CE13CF22262DDF810070C80E /* RoundedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedButton.swift; sourceTree = ""; }; CE1D1EF5263597A2004C8919 /* LocalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalData.swift; sourceTree = ""; }; CE37B642263867D700DEE13D /* SecureBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackground.swift; sourceTree = ""; }; + CE59D1B326428782004EBDD6 /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; + CE59D1B526428D78004EBDD6 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; CE8096D8263B07BB00A65AD6 /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; CE81533B263FF8FE0030D777 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; CE8912F42634C60E00CB92AF /* GatewayConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GatewayConnection.swift; sourceTree = ""; }; @@ -122,6 +126,7 @@ CEA6D6F6261F8D2900715333 /* LaunchScreen.storyboard */, CEA6D6F1261F8D2700715333 /* Main.storyboard */, CE13CF04262DCDCD0070C80E /* CertificateViewer.storyboard */, + CE59D1B326428782004EBDD6 /* Settings.storyboard */, ); path = Storyboards; sourceTree = ""; @@ -150,6 +155,7 @@ CE13CF09262DCDDA0070C80E /* CertificateViewer.swift */, CEA6D6EF261F8D2700715333 /* Scan.swift */, CE891304263581D900CB92AF /* Home.swift */, + CE59D1B526428D78004EBDD6 /* Settings.swift */, ); path = ViewControllers; sourceTree = ""; @@ -376,6 +382,9 @@ CE81533C263FF8FE0030D777 /* README.md in Resources */, CEA6D6F5261F8D2900715333 /* Assets.xcassets in Resources */, CEA6D6F3261F8D2700715333 /* Main.storyboard in Resources */, + CE9D1FF32641CE9E00803242 /* lets-encrypt-r3.der in Resources */, + CE59D1B426428782004EBDD6 /* Settings.storyboard in Resources */, + CE9D1FF22641CE9E00803242 /* lets-encrypt-e1.der in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -412,6 +421,7 @@ CE13CF23262DDF810070C80E /* RoundedButton.swift in Sources */, CEA6D6EC261F8D2700715333 /* AppDelegate.swift in Sources */, CE891305263581D900CB92AF /* Home.swift in Sources */, + CE59D1B626428D78004EBDD6 /* Settings.swift in Sources */, CEA15563262F6DAB0024B7AC /* CertViewerDelegate.swift in Sources */, CEA15570262F79DE0024B7AC /* InfoCell.swift in Sources */, CEA6D6EE261F8D2700715333 /* SceneDelegate.swift in Sources */, diff --git a/DGCAVerifier/Services/GatewayConnection.swift b/DGCAVerifier/Services/GatewayConnection.swift index 7431045..ccaee97 100644 --- a/DGCAVerifier/Services/GatewayConnection.swift +++ b/DGCAVerifier/Services/GatewayConnection.swift @@ -99,20 +99,19 @@ struct GatewayConnection { update() } - static func update() { + static func update(completion: (() -> Void)? = nil) { certUpdate(resume: LocalData.sharedInstance.resumeToken) { encodedCert, token in - LocalData.sharedInstance.lastFetch = Date() guard let encodedCert = encodedCert else { - status() + status(completion: completion) return } LocalData.sharedInstance.add(encodedPublicKey: encodedCert) LocalData.sharedInstance.resumeToken = token - update() + update(completion: completion) } } - static func status() { + static func status(completion: (() -> Void)? = nil) { certStatus { validKids in let invalid = LocalData.sharedInstance.encodedPublicKeys.keys.filter { !validKids.contains($0) @@ -120,7 +119,9 @@ struct GatewayConnection { for key in invalid { LocalData.sharedInstance.encodedPublicKeys.removeValue(forKey: key) } + LocalData.sharedInstance.lastFetch = Date() LocalData.sharedInstance.save() + completion?() } } } diff --git a/DGCAVerifier/Storyboards/CertificateViewer.storyboard b/DGCAVerifier/Storyboards/CertificateViewer.storyboard index e65c39a..04fe071 100644 --- a/DGCAVerifier/Storyboards/CertificateViewer.storyboard +++ b/DGCAVerifier/Storyboards/CertificateViewer.storyboard @@ -1,9 +1,9 @@ - + - + @@ -26,7 +26,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DGCAVerifier/ViewControllers/Scan.swift b/DGCAVerifier/ViewControllers/Scan.swift index 579ab46..adcf0b0 100644 --- a/DGCAVerifier/ViewControllers/Scan.swift +++ b/DGCAVerifier/ViewControllers/Scan.swift @@ -48,7 +48,7 @@ class ScanVC: SwiftDGC.ScanVC { ]) } - var presentingViewer: CertificateViewerVC? + var presentingViewer: UIViewController? func presentViewer(for certificate: HCert) { guard presentingViewer == nil, @@ -59,16 +59,20 @@ class ScanVC: SwiftDGC.ScanVC { return } + showFloatingPanel(for: viewer) + viewer.hCert = certificate + viewer.childDismissedDelegate = self + } + + func showFloatingPanel(for vc: UIViewController) { let fpc = FloatingPanelController() - fpc.set(contentViewController: viewer) + fpc.set(contentViewController: vc) fpc.isRemovalInteractionEnabled = true // Let it removable by a swipe-down fpc.layout = FullFloatingPanelLayout() fpc.surfaceView.layer.cornerRadius = 24.0 fpc.surfaceView.clipsToBounds = true fpc.delegate = self - viewer.hCert = certificate - viewer.childDismissedDelegate = self - presentingViewer = viewer + presentingViewer = vc present(fpc, animated: true, completion: nil) } @@ -83,7 +87,17 @@ extension ScanVC: ScanVCDelegate { extension ScanVC: CertViewerDelegate { @IBAction func openSettings() { - print("Open Settings") // TODO + guard + presentingViewer == nil, + let contentVC = UIStoryboard(name: "Settings", bundle: nil) + .instantiateInitialViewController(), + let viewer = contentVC as? SettingsVC + else { + return + } + + viewer.childDismissedDelegate = self + showFloatingPanel(for: viewer) } func childDismissed() { diff --git a/DGCAVerifier/ViewControllers/Settings.swift b/DGCAVerifier/ViewControllers/Settings.swift new file mode 100644 index 0000000..e29f8e8 --- /dev/null +++ b/DGCAVerifier/ViewControllers/Settings.swift @@ -0,0 +1,73 @@ +/*- + * ---license-start + * eu-digital-green-certificates / dgca-verifier-app-ios + * --- + * Copyright (C) 2021 T-Systems International GmbH and all other contributors + * --- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---license-end + */ +// +// CertificateViewer.swift +// DGCAVerifier +// +// Created by Yannick Spreen on 4/19/21. +// + +import Foundation +import UIKit +import FloatingPanel +import SwiftDGC + +class SettingsVC: UINavigationController { + var childDismissedDelegate: CertViewerDelegate? + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + childDismissedDelegate?.childDismissed() + } +} + +class SettingsTableVC: UITableViewController { + var loading = false + + override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { + [ + "Last Updated: \(LocalData.sharedInstance.lastFetch.dateTimeString)", + "", + ][section] + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = super.tableView(tableView, cellForRowAt: indexPath) + if indexPath.section == 1 { + cell.alpha = loading ? 1 : 0 + cell.contentView.alpha = loading ? 1 : 0 + } + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + loading = true + tableView.deselectRow(at: indexPath, animated: true) + tableView.reloadData() + + GatewayConnection.update() { + DispatchQueue.main.async { [weak self] in + self?.loading = false + self?.tableView.reloadData() + } + } + } +}