266 lines
12 KiB
Swift
266 lines
12 KiB
Swift
//
|
|
// AlertSimulatorViewController.swift
|
|
// Earthquake Network
|
|
//
|
|
// Created by Busi Andrea on 14/11/2020.
|
|
// Copyright © 2020 Earthquake Network. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import MapKit
|
|
import Shogun
|
|
|
|
class AlertSimulatorViewController: UIViewController, MKMapViewDelegate {
|
|
|
|
struct MapCircle {
|
|
let identifier: String
|
|
let distance: CLLocationDistance
|
|
let color: UIColor
|
|
}
|
|
|
|
// MARK: - Internal
|
|
|
|
private let mapCircles = [
|
|
MapCircle(identifier: "circle_internal", distance: 50_000, color: AppTheme.Colors.red),
|
|
MapCircle(identifier: "circle_external", distance: 750_000, color: AppTheme.Colors.green)
|
|
]
|
|
|
|
private lazy var viewfinderView: UIView = {
|
|
let view = UIView()
|
|
view.translatesAutoresizingMaskIntoConstraints = false
|
|
view.backgroundColor = .clear
|
|
view.isUserInteractionEnabled = false
|
|
|
|
// add central vertiacl and horizontal lines
|
|
let viewfinderVertical = UIView()
|
|
view.addSubview(viewfinderVertical)
|
|
viewfinderVertical.translatesAutoresizingMaskIntoConstraints = false
|
|
viewfinderVertical.backgroundColor = AppTheme.Colors.lightBlue
|
|
viewfinderVertical.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
|
|
viewfinderVertical.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
|
viewfinderVertical.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
|
|
viewfinderVertical.widthAnchor.constraint(equalToConstant: 2.0).isActive = true
|
|
|
|
let viewfinderHorizontal = UIView()
|
|
view.addSubview(viewfinderHorizontal)
|
|
viewfinderHorizontal.translatesAutoresizingMaskIntoConstraints = false
|
|
viewfinderHorizontal.backgroundColor = AppTheme.Colors.lightBlue
|
|
viewfinderHorizontal.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
|
viewfinderHorizontal.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
|
viewfinderHorizontal.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
|
|
viewfinderHorizontal.heightAnchor.constraint(equalToConstant: 2.0).isActive = true
|
|
|
|
return view
|
|
}()
|
|
|
|
private lazy var closeButton: EQNBlurredCloseButton = {
|
|
let button = EQNBlurredCloseButton()
|
|
button.translatesAutoresizingMaskIntoConstraints = false
|
|
button.addTarget(self, action: #selector(closeTapped(_:)), for: .touchUpInside)
|
|
button.setTitleColor(.darkGray, for: .normal)
|
|
return button
|
|
}()
|
|
|
|
private lazy var mapView: MKMapView = {
|
|
let map = MKMapView()
|
|
map.translatesAutoresizingMaskIntoConstraints = false
|
|
map.showsUserLocation = true
|
|
map.delegate = self
|
|
return map
|
|
}()
|
|
|
|
private lazy var calculateButton: UIButton = {
|
|
let button = EQNRoundedButton(type: .custom)
|
|
button.backgroundColor = .lightGray
|
|
button.setTitleColor(AppTheme.Colors.darkGray, for: .normal)
|
|
button.translatesAutoresizingMaskIntoConstraints = false
|
|
button.setTitle(NSLocalizedString("globe_simulation_button", comment: "").uppercased(), for: .normal)
|
|
button.addTarget(self, action: #selector(calculateTapped(_:)), for: .touchUpInside)
|
|
return button
|
|
}()
|
|
|
|
// MARK: - View Lifecycle
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
let closeButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(closeTapped(_:)))
|
|
navigationItem.rightBarButtonItem = closeButton
|
|
|
|
setupUI()
|
|
configureMap()
|
|
}
|
|
|
|
override func viewWillAppear(_ animated: Bool) {
|
|
super.viewWillAppear(animated)
|
|
|
|
// show an alert view functionality details
|
|
let alert = UIAlertController(title: NSLocalizedString("main_simulator", comment: ""), message: NSLocalizedString("globe_simulation", comment: ""), preferredStyle: .alert)
|
|
alert.addAction(UIAlertAction(title: NSLocalizedString("main_understood", comment: ""), style: .default))
|
|
present(alert, animated: true)
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func setupUI() {
|
|
view.addSubview(mapView)
|
|
view.addSubview(closeButton)
|
|
view.addSubview(viewfinderView)
|
|
view.addSubview(calculateButton)
|
|
|
|
mapView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
|
|
mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
|
mapView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
|
|
mapView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
|
|
|
|
closeButton.addDefaultConstraint(to: view)
|
|
|
|
viewfinderView.topAnchor.constraint(equalTo: mapView.topAnchor).isActive = true
|
|
viewfinderView.bottomAnchor.constraint(equalTo: mapView.bottomAnchor).isActive = true
|
|
viewfinderView.leftAnchor.constraint(equalTo: mapView.leftAnchor).isActive = true
|
|
viewfinderView.rightAnchor.constraint(equalTo: mapView.rightAnchor).isActive = true
|
|
|
|
calculateButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0).isActive = true
|
|
calculateButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0).isActive = true
|
|
calculateButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10.0).isActive = true
|
|
calculateButton.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
|
|
}
|
|
|
|
private func configureMap() {
|
|
guard let lastPosition = EQNUser.default().lastPosition else { return }
|
|
|
|
let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
|
|
let region = MKCoordinateRegion(center: lastPosition.coordinate, span: span)
|
|
mapView.setCenter(lastPosition.coordinate, animated: false)
|
|
mapView.setRegion(region, animated: true)
|
|
|
|
mapCircles.forEach { (mapCircle) in
|
|
addCircle(location: lastPosition, radius: mapCircle.distance, id: mapCircle.identifier)
|
|
}
|
|
}
|
|
|
|
private func addCircle(location: CLLocation, radius: CLLocationDistance, id: String) {
|
|
let circle = MKCircle(center: location.coordinate, radius: radius)
|
|
circle.title = id
|
|
mapView.addOverlay(circle)
|
|
}
|
|
|
|
// MARK: - Actions
|
|
|
|
@objc func closeTapped(_ sender: Any) {
|
|
dismiss(animated: true)
|
|
}
|
|
|
|
@objc func calculateTapped(_ sender: Any) {
|
|
guard let lastPosition = EQNUser.default().lastPosition,
|
|
let circleMin = mapCircles.sorted(by: { $0.distance < $1.distance }).first,
|
|
let circleMax = mapCircles.sorted(by: { $0.distance > $1.distance }).first else { return }
|
|
|
|
let location = CLLocation(latitude: mapView.centerCoordinate.latitude, longitude: mapView.centerCoordinate.longitude)
|
|
let distance = lastPosition.distance(from: location)
|
|
|
|
// check for a valid point selected by the user
|
|
if distance < circleMin.distance || distance > circleMax.distance {
|
|
let message = distance < circleMin.distance ? "globe_simulation_outside" : "globe_simulation_inside"
|
|
|
|
let alert = UIAlertController(title: NSLocalizedString("attention", comment: ""), message: NSLocalizedString(message, comment: ""), preferredStyle: .alert)
|
|
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: ""), style: .cancel, handler: nil))
|
|
present(alert, animated: true)
|
|
return
|
|
}
|
|
|
|
|
|
let url = EQNGeneratoreURLServer.urlAlertSimulator()
|
|
ServerRequest.default().inviaInformazioniAlServer(with: url, richiesta: .alertSimulator) { (result) in
|
|
if let result = result as? String {
|
|
DispatchQueue.main.async {
|
|
self.elaborateServerResponse(result, distance: distance)
|
|
}
|
|
}
|
|
} failure: { (error) in
|
|
DispatchQueue.main.async {
|
|
let alert = UIAlertController(title: NSLocalizedString("attention", comment: ""), message: error?.localizedDescription, preferredStyle: .alert)
|
|
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: ""), style: .cancel, handler: nil))
|
|
self.present(alert, animated: true)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
private func elaborateServerResponse(_ response: String, distance: CLLocationDistance) {
|
|
let isTop10k = EQNPurchaseUtility.isTop10kEnabled()
|
|
let isTop100k = EQNPurchaseUtility.isTop100kEnabled()
|
|
|
|
// server response (like '3411#12')
|
|
let split = response.split(separator: "#")
|
|
|
|
let people: Int
|
|
let popleTop10k: Int
|
|
if split.count > 1 {
|
|
//caso top10k=0 e top100k=0
|
|
people = Int(split[0]) ?? 0
|
|
popleTop10k = Int(split[1]) ?? 0
|
|
} else {
|
|
//caso top10k=1 oppure top100k=1
|
|
people = Int(split[0]) ?? 0
|
|
popleTop10k = 0
|
|
}
|
|
|
|
let distanceKm = distance / 1000
|
|
let delay = round(Double(people) / 1000.0 * 0.15) //calcolo il ritardo di allerta dovuto alla coda di utenti
|
|
let leadTime = round(Double(distanceKm) / 8.0 - 3.0) //calcolo il tempo di allerta teorico nel caso di 0 utenti in coda
|
|
let actualTime = leadTime - delay //calcolo il tempo di allerta per l'utente
|
|
|
|
//il messaggio mostrato all'utente cambia in base al fatto di possedere un abbonamento ed al tempo di allerta calcolato
|
|
//il messaggio include tag html perché cambio il colore di parte delle stringa, non so se si fa così anche in iOS
|
|
var message = ""
|
|
if (isTop10k) {
|
|
if (people == 0) {
|
|
message = String(format: NSLocalizedString("globe_simulation_message6", comment: ""), "TOP 10K", leadTime)
|
|
} else {
|
|
message = String(format: NSLocalizedString("globe_simulation_message4", comment: ""), "TOP 10K", leadTime, Double(people))
|
|
}
|
|
} else if (isTop100k) {
|
|
message = String(format: NSLocalizedString("globe_simulation_message5", comment: ""), "TOP 100K", leadTime, Double(people), "TOP 10K")
|
|
} else {
|
|
if (leadTime / actualTime < 1.4) {
|
|
message = String(format: NSLocalizedString("globe_simulation_message3", comment: ""), leadTime, Double(people), Double(popleTop10k))
|
|
} else {
|
|
if (actualTime > 0) {
|
|
message = String(format: NSLocalizedString("globe_simulation_message1", comment: ""), leadTime, Double(people), actualTime, Double(popleTop10k))
|
|
} else {
|
|
let updatedActualTime = actualTime * -1;
|
|
message = String(format: NSLocalizedString("globe_simulation_message2", comment: ""), leadTime, Double(people), updatedActualTime, Double(popleTop10k))
|
|
}
|
|
}
|
|
}
|
|
|
|
let alert = UIAlertController(title: NSLocalizedString("main_simulator", comment: ""), message: message, preferredStyle: .alert)
|
|
alert.addAction(UIAlertAction(title: NSLocalizedString("globe_simulation_priority", comment: ""), style: .default) { (action) in
|
|
self.navigateToSubscriptions()
|
|
})
|
|
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: ""), style: .cancel, handler: nil))
|
|
present(alert, animated: true)
|
|
}
|
|
|
|
private func navigateToSubscriptions() {
|
|
let controller = SubscriptionsViewController()
|
|
let navigationController = UINavigationController(rootViewController: controller)
|
|
present(navigationController, animated: true)
|
|
}
|
|
|
|
// MARK: MKMapViewDelegate
|
|
|
|
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
|
|
if let overlay = overlay as? MKCircle, let mapCircle = mapCircles.first(where: { $0.identifier == overlay.title }) {
|
|
let circle = MKCircleRenderer(overlay: overlay)
|
|
circle.strokeColor = mapCircle.color
|
|
circle.fillColor = AppTheme.Colors.green.withAlphaComponent(0.1)
|
|
circle.lineWidth = 2.0
|
|
return circle
|
|
}
|
|
|
|
return MKOverlayRenderer(overlay: overlay)
|
|
}
|
|
}
|