mobile-ios/CovidSafe/HomeViewController.swift
2020-05-15 18:24:06 +10:00

347 lines
15 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import UIKit
import Lottie
import SafariServices
class HomeViewController: UIViewController {
private var observer: NSObjectProtocol?
@IBOutlet weak var screenStack: UIStackView!
@IBOutlet weak var bluetoothStatusOffView: UIView!
@IBOutlet weak var bluetoothStatusOnView: UIView!
@IBOutlet weak var bluetoothPermissionOffView: UIView!
@IBOutlet weak var bluetoothPermissionOnView: UIView!
@IBOutlet weak var homeHeaderView: UIView!
@IBOutlet weak var homeHeaderInfoText: UILabel!
@IBOutlet weak var homeHeaderPermissionsOffImage: UIImageView!
@IBOutlet weak var shareView: UIView!
@IBOutlet weak var thanksForTheHelp: UIView!
@IBOutlet weak var appPermissionsLabel: UIView!
@IBOutlet weak var animatedBluetoothHeader: UIView!
@IBOutlet weak var versionNumberLabel: UILabel!
@IBOutlet weak var versionView: UIView!
@IBOutlet weak var uploadView: UIView!
@IBOutlet weak var helpButton: UIButton!
@IBOutlet weak var seeOurFAQ: UIButton!
@IBOutlet weak var pushNotificationStatusTitle: UILabel!
@IBOutlet weak var pushNotificationStatusIcon: UIImageView!
@IBOutlet weak var pushNotificationStatusLabel: UILabel!
var lottieBluetoothView: AnimationView!
var allPermissionOn = true
var bluetoothStatusOn = true
var bluetoothPermissionOn = true
var pushNotificationOn = true
var didUploadData: Bool {
let uploadTimestamp = UserDefaults.standard.double(forKey: "uploadDataDate")
let lastUpload = Date(timeIntervalSince1970: uploadTimestamp)
return Date().timeIntervalSince(lastUpload) < 86400 * 21
}
var shouldShowEndOfIsolationScreen: Bool {
let uploadTimestamp = UserDefaults.standard.double(forKey: "firstUploadDataDate")
if(uploadTimestamp > 0){
let lastUpload = Date(timeIntervalSince1970: uploadTimestamp)
return Date().timeIntervalSince(lastUpload) >= 86400 * 21
}
return false
}
var _preferredScreenEdgesDeferringSystemGestures: UIRectEdge = []
override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {
return _preferredScreenEdgesDeferringSystemGestures
}
override func viewDidLoad() {
super.viewDidLoad()
observer = NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { [unowned self] notification in
self.toggleViews()
}
updateAnimationViewWithAnimationName(name: "Spinner_home")
NotificationCenter.default.addObserver(self, selector: #selector(enableDeferringSystemGestures(_:)), name: .enableDeferringSystemGestures, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(disableDeferringSystemGestures(_:)), name: .disableDeferringSystemGestures, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(disableUserInteraction(_:)), name: .disableUserInteraction, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(enableUserInteraction(_:)), name: .enableUserInteraction, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appWillResignActive(_:)), name: UIApplication.willResignActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
if let versionNumber = Bundle.main.versionShort, let buildNumber = Bundle.main.version {
self.versionNumberLabel.text = "Version number: \(versionNumber) Build: \(buildNumber)"
} else {
toggleViewVisibility(view: versionView, isVisible: false)
}
}
deinit {
if let observer = observer {
NotificationCenter.default.removeObserver(observer)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.toggleViews()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.lottieBluetoothView?.play()
self.becomeFirstResponder()
if(shouldShowEndOfIsolationScreen){
self.performSegue(withIdentifier: "IsolationSuccessSegue", sender: self)
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.lottieBluetoothView?.stop()
}
override var canBecomeFirstResponder: Bool {
return true
}
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
#if DEBUG
guard let allowDebug = PlistHelper.getBoolFromInfoPlist(withKey: "Allow_Debug", plistName: "CovidSafe-config") else {
return
}
if allowDebug == true && event?.subtype == .motionShake {
guard let debugVC = UIStoryboard(name: "Debug", bundle: nil).instantiateInitialViewController() else {
return
}
debugVC.modalTransitionStyle = .coverVertical
debugVC.modalPresentationStyle = .fullScreen
present(debugVC, animated: true, completion: nil)
}
#endif
}
fileprivate func toggleViews() {
DispatchQueue.main.async {
UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { [weak self] settings in
DispatchQueue.main.async {
self?.readPermissions(notificationSettings: settings)
self?.togglePushNotificationsStatusView()
self?.toggleBluetoothStatusView()
self?.toggleBluetoothPermissionStatusView()
self?.toggleHeaderView()
self?.toggleUploadView()
}
})
}
}
fileprivate func readPermissions(notificationSettings: UNNotificationSettings) {
self.bluetoothStatusOn = BluetraceManager.shared.isBluetoothOn()
self.bluetoothPermissionOn = BluetraceManager.shared.isBluetoothAuthorized()
self.pushNotificationOn = notificationSettings.authorizationStatus == .authorized
self.allPermissionOn = self.bluetoothStatusOn && self.bluetoothPermissionOn
}
fileprivate func toggleViewVisibility(view: UIView, isVisible: Bool) {
view.isHidden = !isVisible
}
func updateAnimationViewWithAnimationName(name: String) {
let bluetoothAnimation = AnimationView(name: name)
bluetoothAnimation.loopMode = .loop
bluetoothAnimation.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: self.animatedBluetoothHeader.frame.size)
if lottieBluetoothView != nil {
lottieBluetoothView.stop()
lottieBluetoothView.removeFromSuperview()
}
self.animatedBluetoothHeader.addSubview(bluetoothAnimation)
lottieBluetoothView = bluetoothAnimation
lottieBluetoothView.play()
}
fileprivate func toggleUploadView() {
toggleViewVisibility(view: self.uploadView, isVisible: !self.didUploadData)
}
fileprivate func toggleHeaderView() {
self.allPermissionOn ? self.lottieBluetoothView?.play() : self.lottieBluetoothView?.stop()
toggleViewVisibility(view: appPermissionsLabel, isVisible: !self.allPermissionOn)
toggleViewVisibility(view: thanksForTheHelp, isVisible: self.allPermissionOn && self.didUploadData)
toggleViewVisibility(view: homeHeaderPermissionsOffImage, isVisible: !self.allPermissionOn)
toggleViewVisibility(view: lottieBluetoothView, isVisible: self.allPermissionOn)
if (self.allPermissionOn && self.didUploadData) {
self.homeHeaderInfoText.textColor = UIColor.white
} else {
self.homeHeaderInfoText.textColor = UIColor(0x131313)
}
self.helpButton.setImage(UIImage(named: "ic-help-selected"), for: .normal)
self.helpButton.setTitleColor(UIColor.black, for: .normal)
self.homeHeaderInfoText.font = UIFont.systemFont(ofSize: 18, weight: .regular)
self.homeHeaderInfoText.text = "COVIDSafe is active.\nNo further action is required."
if (!self.allPermissionOn) {
self.homeHeaderInfoText.text = "COVIDSafe is not active.\nCheck your permissions."
self.homeHeaderView.backgroundColor = UIColor.covidHomePermissionErrorColor
} else if (self.didUploadData) {
self.helpButton.setImage(UIImage(named: "ic-help"), for: .normal)
self.helpButton.setTitleColor(UIColor.white, for: .normal)
self.homeHeaderInfoText.font = UIFont.systemFont(ofSize: 18, weight: .bold)
self.homeHeaderView.backgroundColor = UIColor.covidSafeButtonDarkerColor
updateAnimationViewWithAnimationName(name: "Spinner_home_upload_complete")
} else {
self.homeHeaderView.backgroundColor = UIColor.covidHomeActiveColor
updateAnimationViewWithAnimationName(name: "Spinner_home")
}
}
fileprivate func toggleBluetoothStatusView() {
toggleViewVisibility(view: bluetoothStatusOnView, isVisible: !self.allPermissionOn && self.bluetoothStatusOn)
toggleViewVisibility(view: bluetoothStatusOffView, isVisible: !self.allPermissionOn && !self.bluetoothStatusOn)
}
fileprivate func toggleBluetoothPermissionStatusView() {
toggleViewVisibility(view: bluetoothPermissionOnView, isVisible: !self.allPermissionOn && self.bluetoothPermissionOn)
toggleViewVisibility(view: bluetoothPermissionOffView, isVisible: !self.allPermissionOn && !self.bluetoothPermissionOn)
}
fileprivate func togglePushNotificationsStatusView() {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 4
switch self.pushNotificationOn {
case true:
pushNotificationStatusIcon.isHighlighted = false
pushNotificationStatusTitle.text = "Notifications are enabled"
let newAttributedLabel = NSMutableAttributedString(string: "You will receive a notification if COVIDSafe is not active. Change notification settings")
//set some attributes
guard let linkRange = newAttributedLabel.string.range(of: "Change notification settings") else { return }
let nsRange = NSRange(linkRange, in: newAttributedLabel.string)
newAttributedLabel.addAttribute(.foregroundColor,
value: UIColor.covidSafeColor,
range: nsRange)
newAttributedLabel.addAttribute(.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, newAttributedLabel.length))
pushNotificationStatusLabel.attributedText = newAttributedLabel
default:
pushNotificationStatusIcon.isHighlighted = true
pushNotificationStatusTitle.text = "Notifications are disabled"
let newAttributedLabel = NSMutableAttributedString(string: "You will not receive a notification if COVIDSafe is not active. Change notification settings")
//set some attributes
guard let linkRange = newAttributedLabel.string.range(of: "Change notification settings") else { return }
let nsRange = NSRange(linkRange, in: newAttributedLabel.string)
newAttributedLabel.addAttribute(.foregroundColor,
value: UIColor.covidSafeColor,
range: nsRange)
newAttributedLabel.addAttribute(.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, newAttributedLabel.length))
pushNotificationStatusLabel.attributedText = newAttributedLabel
}
}
@IBAction func onSettingsTapped(_ sender: UITapGestureRecognizer) {
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
return
}
UIApplication.shared.open(settingsURL)
}
@IBAction func onShareTapped(_ sender: UITapGestureRecognizer) {
let shareText = TracerRemoteConfig.defaultShareText
let activity = UIActivityViewController(activityItems: [shareText], applicationActivities: nil)
activity.popoverPresentationController?.sourceView = shareView
present(activity, animated: true, completion: nil)
}
@IBAction func onLatestNewsTapped(_ sender: UITapGestureRecognizer) {
// open in safari https://www.australia.gov.au
guard let url = URL(string: "https://www.australia.gov.au") else {
return
}
let safariVC = SFSafariViewController(url: url)
present(safariVC, animated: true, completion: nil)
}
@IBAction func getCoronaVirusApp(_ sender: UITapGestureRecognizer) {
guard let url = URL(string: "https://www.health.gov.au/resources/apps-and-tools/coronavirus-australia-app") else {
return
}
let safariVC = SFSafariViewController(url: url)
present(safariVC, animated: true, completion: nil)
}
@IBAction func onPositiveButtonTapped(_ sender: UITapGestureRecognizer) {
guard let helpVC = UIStoryboard(name: "UploadData", bundle: nil).instantiateInitialViewController() else {
return
}
let nav = UploadDataNavigationController(rootViewController: helpVC)
nav.modalTransitionStyle = .coverVertical
nav.modalPresentationStyle = .fullScreen
present(nav, animated: true, completion: nil)
}
@IBAction func onHelpButtonTapped(_ sender: Any) {
let nav = HelpNavController()
nav.modalTransitionStyle = .coverVertical
nav.modalPresentationStyle = .fullScreen
present(nav, animated: true, completion: nil)
}
@IBAction func onPowerSaverButtonTapped(_ sender: Any) {
}
@objc
func appWillResignActive(_ notification: Notification) {
self.lottieBluetoothView?.stop()
}
@objc
func appWillEnterForeground(_ notification: Notification) {
self.lottieBluetoothView?.play()
}
@objc
func enableUserInteraction(_ notification: Notification) {
self.view.isUserInteractionEnabled = true
lottieBluetoothView?.play()
}
@objc
func disableUserInteraction(_ notification: Notification) {
self.view.isUserInteractionEnabled = false
lottieBluetoothView?.stop()
}
@objc
func enableDeferringSystemGestures(_ notification: Notification) {
if #available(iOS 11.0, *) {
_preferredScreenEdgesDeferringSystemGestures = .bottom
setNeedsUpdateOfScreenEdgesDeferringSystemGestures()
}
}
@objc
func disableDeferringSystemGestures(_ notification: Notification) {
if #available(iOS 11.0, *) {
_preferredScreenEdgesDeferringSystemGestures = []
setNeedsUpdateOfScreenEdgesDeferringSystemGestures()
}
}
}
struct TracerRemoteConfig {
static let defaultShareText = """
Join me in stopping the spread of COVID-19! Download COVIDSafe, an app from the Australian Government. #COVID19
#coronavirusaustralia #stayhomesavelives https://covidsafe.gov.au
"""
}