feat: New beautifult layout for seismic cards

This commit is contained in:
Andrea Busi
2020-09-23 07:04:28 +02:00
parent 0eb0880b0e
commit 39a10b2cbc
25 changed files with 1727 additions and 694 deletions
@@ -92,7 +92,10 @@
DC08803F24F5A89000186D97 /* SettingEnableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC08803E24F5A89000186D97 /* SettingEnableTableViewCell.swift */; };
DC08804124F5B41400186D97 /* SettingSliderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC08804024F5B41400186D97 /* SettingSliderTableViewCell.swift */; };
DC0E551324F8063300D54270 /* SettingSegmentedTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC0E551224F8063300D54270 /* SettingSegmentedTableViewCell.swift */; };
DC105641251E7ECE002579BB /* UIFont+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC105640251E7ECE002579BB /* UIFont+Extensions.swift */; };
DC27EB2F24F6EBE000ACBFE0 /* SettingsSeismicNetworksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC27EB2E24F6EBE000ACBFE0 /* SettingsSeismicNetworksViewController.swift */; };
DC2814302519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC28142F2519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift */; };
DC2814382519C56100C1AFF7 /* SeismicNetworksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC2814372519C56100C1AFF7 /* SeismicNetworksViewController.swift */; };
DC3ADD3924CB2F3D00737919 /* alert_star_trek.wav in Resources */ = {isa = PBXBuildFile; fileRef = 8CF12CC721DE43A400613AC5 /* alert_star_trek.wav */; };
DC3BA11124D1A9C90062EE7F /* SubscriptionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3BA11024D1A9C90062EE7F /* SubscriptionsViewController.swift */; };
DC3CE50A250EB7A8005A7DD5 /* EQNGenericPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3CE509250EB7A8005A7DD5 /* EQNGenericPickerViewController.swift */; };
@@ -296,7 +299,10 @@
DC08803E24F5A89000186D97 /* SettingEnableTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingEnableTableViewCell.swift; sourceTree = "<group>"; };
DC08804024F5B41400186D97 /* SettingSliderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingSliderTableViewCell.swift; sourceTree = "<group>"; };
DC0E551224F8063300D54270 /* SettingSegmentedTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingSegmentedTableViewCell.swift; sourceTree = "<group>"; };
DC105640251E7ECE002579BB /* UIFont+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Extensions.swift"; sourceTree = "<group>"; };
DC27EB2E24F6EBE000ACBFE0 /* SettingsSeismicNetworksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSeismicNetworksViewController.swift; sourceTree = "<group>"; };
DC28142F2519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkTableViewCell.swift; sourceTree = "<group>"; };
DC2814372519C56100C1AFF7 /* SeismicNetworksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworksViewController.swift; sourceTree = "<group>"; };
DC3BA11024D1A9C90062EE7F /* SubscriptionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsViewController.swift; sourceTree = "<group>"; };
DC3CE509250EB7A8005A7DD5 /* EQNGenericPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNGenericPickerViewController.swift; sourceTree = "<group>"; };
DC414C0024CDA09A008D9AE4 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = "<group>"; };
@@ -577,16 +583,34 @@
name = Pods;
sourceTree = "<group>";
};
DC10563F251E7EC0002579BB /* Extensions */ = {
isa = PBXGroup;
children = (
DC105640251E7ECE002579BB /* UIFont+Extensions.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
DC141968250E769B0059E060 /* Seismic Networks */ = {
isa = PBXGroup;
children = (
DC28142E2519C21400C1AFF7 /* Cells */,
DC974AFE251748B300A139EC /* SeismicFiltersViewController.swift */,
DCB45BC7250E86E100DB2D0C /* SeismicSettingsViewController.swift */,
DC65B390250F243E00251693 /* SeismicSettingsNetworksViewController.swift */,
DC2814372519C56100C1AFF7 /* SeismicNetworksViewController.swift */,
);
path = "Seismic Networks";
sourceTree = "<group>";
};
DC28142E2519C21400C1AFF7 /* Cells */ = {
isa = PBXGroup;
children = (
DC28142F2519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift */,
);
path = Cells;
sourceTree = "<group>";
};
DC3ADD2A24CB1E6600737919 /* Supporting Files */ = {
isa = PBXGroup;
children = (
@@ -625,6 +649,7 @@
DC3ADD2F24CB1EFB00737919 /* Libs */ = {
isa = PBXGroup;
children = (
DC10563F251E7EC0002579BB /* Extensions */,
8CF66054214C566A009F4314 /* Reachability.h */,
8CF66056214C566A009F4314 /* Reachability.m */,
8C7A3B65225A5EA40045B266 /* NSDictionary+BVJSONString.h */,
@@ -1045,6 +1070,7 @@
DCC23DEF24D28F58003A2404 /* EQNEdgeInsetLabel.swift in Sources */,
8CCE165121E7BAEC00173CD9 /* EQNNotificheReteSismiche.m in Sources */,
DC52B8A224FC145500ABEBA6 /* SettingsBaseViewController.m in Sources */,
DC2814382519C56100C1AFF7 /* SeismicNetworksViewController.swift in Sources */,
8CF4F4DB216D44930057110B /* EQNPastquakes.m in Sources */,
8CCE165821EB1E0000173CD9 /* SettingsSeismicNetworkAlertsViewController.m in Sources */,
8CCE165521EA378800173CD9 /* SettingsUserReportAlertsViewController.m in Sources */,
@@ -1058,6 +1084,7 @@
8C4E343F215012FA008B0D2A /* EQNManager.m in Sources */,
DCAA913F24F68A1D00145A3D /* SettingMultivaluesTableViewCell.swift in Sources */,
DCF9E14F24F6EA07002B6B1D /* EQNSeismicNetwork.swift in Sources */,
DC2814302519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift in Sources */,
8C14113721EE502800A59729 /* EQNAllertaSismica.m in Sources */,
8C483CBC21FDACE500259FD2 /* VersioneProProducts.swift in Sources */,
8C483CB821FDACD300259FD2 /* IAPHelper.swift in Sources */,
@@ -1111,6 +1138,7 @@
8C4E34452152B707008B0D2A /* EQMAccelerometroManager.m in Sources */,
8CBD3DC72149B9AD0070C963 /* AppDelegate.m in Sources */,
DC974AFF251748B300A139EC /* SeismicFiltersViewController.swift in Sources */,
DC105641251E7ECE002579BB /* UIFont+Extensions.swift in Sources */,
8CA46BA12194532E00C63C16 /* SismaAnnotation.m in Sources */,
DCB28CEE24FB8400001F557E /* SettingsViewController.swift in Sources */,
DC3CE50A250EB7A8005A7DD5 /* EQNGenericPickerViewController.swift in Sources */,
@@ -0,0 +1,710 @@
//
// SeismicNetworkTableViewCell.swift
// Earthquake Network
//
// Created by Busi Andrea on 22/09/2020.
// Copyright © 2020 Earthquake Network. All rights reserved.
//
import UIKit
import MapKit
import CoreLocation
protocol SeismicNetworkTableViewCellDelegate: class {
func seismicNetworkCellDidTapShare(_ cell: SeismicNetworkTableViewCell)
func seismicNetworkCellDidTapMap(_ cell: SeismicNetworkTableViewCell)
func seismicNetworkCellDidTapWeather(_ cell: SeismicNetworkTableViewCell)
func seismicNetworkCellDidTapCalendar(_ cell: SeismicNetworkTableViewCell)
func seismicNetworkCellDidTapSettings(_ cell: SeismicNetworkTableViewCell)
func seismicNetworkCellDidTapClose(_ cell: SeismicNetworkTableViewCell)
}
class SeismicNetworkTableViewCell: UITableViewCell {
static let Identifier = "SeismicNetworkTableViewCell"
typealias MagnitudeColors = (textColor: UIColor, startColor: UIColor, endColor: UIColor)
/// Available informations to display inside the cell
enum InformationType: Int {
case preliminary
case time
case distance
case coordinate
case population
case realtimeSmartphones
case reportUsers
}
/// Available cell type
enum DisplayType {
/// Compact view
case normal
/// Cell with map visible
case mapExpanded
/// Cell with weather info visible
case weatherExpanded
}
/// Delegate
weak var delegate: SeismicNetworkTableViewCellDelegate?
// MARK: - Internal
private static let DefaultVerticalSpacing: CGFloat = 6.0
private static let DefaultBodyFont = UIFont.preferredFont(forTextStyle: .body)
private static let DefaultBodyFontLight = UIFont.preferredFont(for: .body, weight: .light)
private static var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss d-MMM"
return formatter
}()
/// Seismic to show
private var seismic: EQNSisma?
private(set) var displayType = DisplayType.normal
private var informationTypes = [InformationType]()
private var colors: MagnitudeColors?
// MARK: - UI Components
private lazy var containerView: UIView = {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = AppTheme.shared.borderCornerRadius
view.layer.masksToBounds = true
return view
}()
private lazy var titleImageView: UIImageView = {
let imageView = UIImageView(frame: .zero)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
private lazy var placeLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.preferredFont(for: .title2, weight: .semibold)
label.numberOfLines = 2
return label
}()
private lazy var networkLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = UIColor.white.withAlphaComponent(0.5)
label.textAlignment = .center
return label
}()
private lazy var magnitudeLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.preferredFont(forTextStyle: .largeTitle)
label.textColor = .red
return label
}()
private lazy var depthLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = Self.DefaultBodyFontLight
return label
}()
private lazy var timeLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = Self.DefaultBodyFontLight
return label
}()
private lazy var distanceLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = Self.DefaultBodyFontLight
return label
}()
private lazy var coordinateLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = Self.DefaultBodyFontLight
return label
}()
private lazy var populationLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = Self.DefaultBodyFontLight
return label
}()
private lazy var smartphonesLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.font = Self.DefaultBodyFont
label.textAlignment = .center
return label
}()
private lazy var alertsLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.font = Self.DefaultBodyFont
label.textAlignment = .center
return label
}()
private lazy var mapView: MKMapView = {
let mapView = MKMapView(frame: .zero)
mapView.translatesAutoresizingMaskIntoConstraints = false
mapView.isScrollEnabled = false
mapView.isZoomEnabled = false
mapView.layer.cornerRadius = AppTheme.shared.borderCornerRadius
mapView.layer.masksToBounds = true
return mapView
}()
private lazy var weatherImageView: UIImageView = {
let imageView = UIImageView(frame: .zero)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
private lazy var weatherInfoLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.font = Self.DefaultBodyFontLight
return label
}()
// MARK: - Init
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUI()
}
// MARK: - Setup
private func setupUI() {
selectionStyle = .default
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .clear
// container view
contentView.addSubview(containerView)
containerView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5.0).isActive = true
containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10.0).isActive = true
containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10.0).isActive = true
containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5.0).isActive = true
// this variable is used to keep track of the previous view, in order to attach proper constraints
var previousView: UIView = containerView
// preliminary banner on top of the cell
if informationTypes.contains(.preliminary) {
let preliminaryLabel = UILabel()
preliminaryLabel.translatesAutoresizingMaskIntoConstraints = false
preliminaryLabel.text = NSLocalizedString("official_prelimiary", comment: "").uppercased()
preliminaryLabel.textAlignment = .center
preliminaryLabel.backgroundColor = .red
preliminaryLabel.textColor = .yellow
containerView.addSubview(preliminaryLabel)
preliminaryLabel.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
preliminaryLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
preliminaryLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
preliminaryLabel.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
previousView = preliminaryLabel
}
// title (bell icon, place label, seismic network and share button)
let titleComponentsHeight: CGFloat = 30.0
let stackViewTitle = UIStackView()
stackViewTitle.translatesAutoresizingMaskIntoConstraints = false
stackViewTitle.axis = .horizontal
stackViewTitle.distribution = .fill
stackViewTitle.alignment = .center
stackViewTitle.spacing = 4
let shareButton = UIButton(type: .custom)
shareButton.setImage(UIImage(named: "share_icon"), for: .normal)
shareButton.addTarget(self, action: #selector(shareTapped(_:)), for: .touchUpInside)
stackViewTitle.addArrangedSubview(titleImageView)
stackViewTitle.addArrangedSubview(placeLabel)
stackViewTitle.addArrangedSubview(networkLabel)
stackViewTitle.addArrangedSubview(shareButton)
titleImageView.heightAnchor.constraint(equalToConstant: titleComponentsHeight).isActive = true
titleImageView.widthAnchor.constraint(equalTo: titleImageView.heightAnchor).isActive = true
networkLabel.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
networkLabel.widthAnchor.constraint(equalToConstant: 60.0).isActive = true
shareButton.widthAnchor.constraint(equalToConstant: titleComponentsHeight).isActive = true
shareButton.widthAnchor.constraint(equalTo: shareButton.heightAnchor).isActive = true
let titleTopAnchor = previousView == containerView ? containerView.layoutMarginsGuide.topAnchor : previousView.bottomAnchor
containerView.addSubview(stackViewTitle)
stackViewTitle.topAnchor.constraint(equalTo: titleTopAnchor).isActive = true
stackViewTitle.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
stackViewTitle.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
let separator1 = addSeparator(constraintTo: stackViewTitle.bottomAnchor)
let informationsLeadingAnchor = separator1.leadingAnchor
let informationsTrailingAnchor = separator1.trailingAnchor
// magnitude information
containerView.addSubview(magnitudeLabel)
magnitudeLabel.topAnchor.constraint(equalTo: separator1.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
magnitudeLabel.leadingAnchor.constraint(equalTo: informationsLeadingAnchor, constant: 14).isActive = true
if !informationTypes.contains(.preliminary) {
containerView.addSubview(depthLabel)
depthLabel.lastBaselineAnchor.constraint(equalTo: magnitudeLabel.lastBaselineAnchor).isActive = true
depthLabel.leadingAnchor.constraint(equalTo: magnitudeLabel.trailingAnchor, constant: 16).isActive = true
}
// informations
let stackViewInformations = UIStackView()
stackViewInformations.translatesAutoresizingMaskIntoConstraints = false
stackViewInformations.axis = .vertical
stackViewInformations.distribution = .equalSpacing
stackViewInformations.spacing = 4
if informationTypes.contains(.time) {
stackViewInformations.addArrangedSubview(timeLabel)
}
if informationTypes.contains(.distance) {
stackViewInformations.addArrangedSubview(distanceLabel)
}
if informationTypes.contains(.coordinate) {
stackViewInformations.addArrangedSubview(coordinateLabel)
}
if informationTypes.contains(.population) {
stackViewInformations.addArrangedSubview(populationLabel)
}
containerView.addSubview(stackViewInformations)
stackViewInformations.topAnchor.constraint(equalTo: magnitudeLabel.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
stackViewInformations.leadingAnchor.constraint(equalTo: informationsLeadingAnchor, constant: 14).isActive = true
stackViewInformations.trailingAnchor.constraint(equalTo: informationsTrailingAnchor, constant: -14).isActive = true
previousView = stackViewInformations
if informationTypes.contains(.realtimeSmartphones) || informationTypes.contains(.reportUsers) {
let separator2 = addSeparator(constraintTo: stackViewInformations.bottomAnchor)
let stackViewReports = UIStackView()
stackViewReports.translatesAutoresizingMaskIntoConstraints = false
stackViewReports.axis = .vertical
stackViewReports.distribution = .equalSpacing
stackViewReports.alignment = .center
stackViewReports.spacing = Self.DefaultVerticalSpacing
if informationTypes.contains(.realtimeSmartphones) {
stackViewReports.addArrangedSubview(smartphonesLabel)
}
if informationTypes.contains(.reportUsers) {
stackViewReports.addArrangedSubview(alertsLabel)
}
containerView.addSubview(stackViewReports)
stackViewReports.topAnchor.constraint(equalTo: separator2.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
stackViewReports.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor, constant: 20.0).isActive = true
stackViewReports.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor, constant: -20.0).isActive = true
let separator3 = addSeparator(constraintTo: stackViewReports.bottomAnchor)
previousView = separator3
}
// buttons
let stackViewButtons = UIStackView()
stackViewButtons.translatesAutoresizingMaskIntoConstraints = false
stackViewButtons.axis = .horizontal
stackViewButtons.distribution = .fillEqually
stackViewButtons.spacing = 4
let buttonMap = createRoundedButton(title: "🗺", action: #selector(mapTapped(_:)))
stackViewButtons.addArrangedSubview(buttonMap)
let buttonWeather = createRoundedButton(title: "🌤", action: #selector(weatherTapped(_:)))
stackViewButtons.addArrangedSubview(buttonWeather)
let buttonCalendar = createRoundedButton(title: "📆", action: #selector(calendarTapped(_:)))
stackViewButtons.addArrangedSubview(buttonCalendar)
let buttonSettings = createRoundedButton(title: "🔧", action: #selector(settingsTapped(_:)))
stackViewButtons.addArrangedSubview(buttonSettings)
containerView.addSubview(stackViewButtons)
stackViewButtons.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
stackViewButtons.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
stackViewButtons.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
stackViewButtons.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
previousView = stackViewButtons
if displayType == .mapExpanded {
containerView.addSubview(mapView)
mapView.heightAnchor.constraint(equalToConstant: 140.0).isActive = true
mapView.topAnchor.constraint(equalTo: stackViewButtons.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
mapView.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
mapView.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
previousView = mapView
} else if displayType == .weatherExpanded {
let weatherTitleLabel = UILabel()
weatherTitleLabel.translatesAutoresizingMaskIntoConstraints = false
weatherTitleLabel.text = NSLocalizedString("weather_weather", comment: "")
weatherTitleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
containerView.addSubview(weatherTitleLabel)
weatherTitleLabel.topAnchor.constraint(equalTo: stackViewButtons.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
weatherTitleLabel.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
weatherTitleLabel.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
containerView.addSubview(weatherInfoLabel)
containerView.addSubview(weatherImageView)
weatherImageView.heightAnchor.constraint(equalToConstant: 60.0).isActive = true
weatherImageView.widthAnchor.constraint(equalTo: weatherImageView.heightAnchor).isActive = true
weatherImageView.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
weatherImageView.trailingAnchor.constraint(equalTo: weatherInfoLabel.leadingAnchor, constant: -8.0).isActive = true
weatherImageView.centerYAnchor.constraint(equalTo: weatherInfoLabel.centerYAnchor).isActive = true
weatherInfoLabel.topAnchor.constraint(equalTo: weatherTitleLabel.bottomAnchor, constant: 4.0).isActive = true
weatherInfoLabel.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
previousView = weatherInfoLabel
}
if (displayType == .mapExpanded || displayType == .weatherExpanded) {
let buttonClose = createRoundedButton(title: NSLocalizedString("CHIUDI", comment: ""), action: #selector(closeTapped(_:)))
containerView.addSubview(buttonClose)
buttonClose.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
buttonClose.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
buttonClose.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
buttonClose.bottomAnchor.constraint(equalTo: containerView.layoutMarginsGuide.bottomAnchor).isActive = true
}
else {
stackViewButtons.bottomAnchor.constraint(equalTo: containerView.layoutMarginsGuide.bottomAnchor).isActive = true
}
}
private func recreateUI() {
// remove all subviews and recreate the required components
containerView.subviews.forEach({ $0.removeFromSuperview() })
setupUI()
}
private func updateUI() {
guard let seismic = seismic else { return }
containerView.backgroundColor = colors?.startColor
let notified = couldBeNotified(for: seismic)
titleImageView.image = notified ? UIImage(named: "bell") : UIImage(named: "bell_disabled")
// update seismic data
placeLabel.text = seismic.place
networkLabel.text = seismic.provider
magnitudeLabel.textColor = colors?.textColor
if informationTypes.contains(.preliminary) {
let lowerValue = seismic.magnitude.doubleValue - seismic.magnitudeRange.doubleValue/2.0
let upperValue = seismic.magnitude.doubleValue + seismic.magnitudeRange.doubleValue/2.0
magnitudeLabel.text = String(format: "%.1f-%.1fM", lowerValue, upperValue)
depthLabel.text = ""
} else {
magnitudeLabel.text = "\(seismic.magnitude)ML"
depthLabel.text = "\(NSLocalizedString("Profondità", comment: "")): \(seismic.depth) km"
}
let formattedDate = Self.dateFormatter.string(from: seismic.date)
let timeSuffix = seismic.timeDifference > 60 ? NSLocalizedString("ore fa", comment: "") : NSLocalizedString("minuti fa", comment: "")
let timeRounded = seismic.timeDifference > 60 ? Int(round(seismic.timeDifference / 60)) : Int(seismic.timeDifference)
timeLabel.text = "🕗 \(formattedDate) - \(timeRounded) \(timeSuffix)"
let distanceRounded = Int(round(seismic.userDistance))
distanceLabel.text = "📐 \(distanceRounded) km \(NSLocalizedString("dalla tua posizione", comment: ""))"
let coordinateText = coordinateString(coordinate: seismic.coordinate.coordinate)
coordinateLabel.text = "🌍 \(coordinateText)"
// evaluate population string
let populationIsRed = seismic.population100km >= 1_000_000 || seismic.userDistance <= 250
let population = formatPopulation(seismic.population100km)
populationLabel.text = "👨‍👩‍👦 \(population) \(NSLocalizedString("share_radius100", comment: ""))"
populationLabel.textColor = populationIsRed ? AppTheme.Colors.red : .black
if seismic.smartphoneNumber.intValue > 0 || true {
smartphonesLabel.text = String(format: NSLocalizedString("report_smartphones", comment: ""), seismic.smartphoneNumber)
}
if seismic.userNumber.intValue > 0 || true {
alertsLabel.text = String(format: NSLocalizedString("report_users", comment: ""), seismic.userNumber)
}
if displayType == .mapExpanded {
// zoom based on population involved
let zoom = mapZoomFor(population: seismic.population100km)
let span = MKCoordinateSpan(latitudeDelta: zoom, longitudeDelta: zoom)
let region = MKCoordinateRegion(center: seismic.coordinate.coordinate, span: span)
mapView.setCenter(seismic.coordinate.coordinate, animated: false)
mapView.setRegion(region, animated: false)
// add a pin on the center
let annotation = MKPointAnnotation()
annotation.coordinate = seismic.coordinate.coordinate
annotation.title = ""
mapView.addAnnotation(annotation)
} else if displayType == .weatherExpanded {
weatherInfoLabel.text = ""
+ String(format: NSLocalizedString("weather_temperature", comment: ""), seismic.weatherTemperature.doubleValue - EQNMathKelvin) + "\n"
+ String(format: NSLocalizedString("weather_pressure", comment: ""), seismic.weatherPressure) + "\n"
+ String(format: NSLocalizedString("weather_windspeed", comment: ""), seismic.weatherWindSpeed) + "\n"
+ String(format: NSLocalizedString("weather_humidity", comment: ""), seismic.weatherHumidity) + "\n"
+ String(format: NSLocalizedString("weather_clouds", comment: ""), seismic.weatherCloud)
weatherImageView.image = UIImage(named: "weather_\(seismic.weatherIcon).png")
}
}
// MARK: - Public
/// Configure the cell to display a seismic
/// - Parameters:
/// - seismic: Seismic to display
/// - type: Type of cell
/// - informations: Informations to show
public func configure(with seismic: EQNSisma, type: DisplayType, informations: [InformationType]) {
self.seismic = seismic
self.colors = calculateColors(for: seismic.magnitude.doubleValue)
self.displayType = type
self.informationTypes = informations
if !informations.contains(.time) {
self.informationTypes += [.time]
}
if seismic.preliminary.intValue > 0 && !informations.contains(.preliminary) {
self.informationTypes += [.preliminary]
}
if seismic.smartphoneNumber.intValue > 0 && !informations.contains(.realtimeSmartphones) {
self.informationTypes += [.realtimeSmartphones]
}
if seismic.userNumber.intValue > 0 && !informations.contains(.reportUsers) {
self.informationTypes += [.reportUsers]
}
recreateUI()
updateUI()
setNeedsLayout()
layoutIfNeeded()
}
/// Creates a snapshot of the current cell
/// - Returns: Image with the snapshot of the cell
public func createSnapshot() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: contentView.bounds.size)
let image = renderer.image { ctx in
contentView.drawHierarchy(in: contentView.bounds, afterScreenUpdates: true)
}
return image
}
// MARK: - Actions
@objc func shareTapped(_ sender: UIButton) {
delegate?.seismicNetworkCellDidTapShare(self)
}
@objc func mapTapped(_ sender: UIButton) {
if displayType != .mapExpanded {
delegate?.seismicNetworkCellDidTapMap(self)
}
}
@objc func weatherTapped(_ sender: UIButton) {
if displayType != .weatherExpanded {
delegate?.seismicNetworkCellDidTapWeather(self)
}
}
@objc func calendarTapped(_ sender: UIButton) {
delegate?.seismicNetworkCellDidTapCalendar(self)
}
@objc func settingsTapped(_ sender: UIButton) {
delegate?.seismicNetworkCellDidTapSettings(self)
}
@objc func closeTapped(_ sender: UIButton) {
delegate?.seismicNetworkCellDidTapClose(self)
}
// MARK: - Helpers
@discardableResult
private func addSeparator(constraintTo: NSLayoutYAxisAnchor, constanst: CGFloat = 8.0) -> UIView {
let separator = UIView()
separator.translatesAutoresizingMaskIntoConstraints = false
separator.backgroundColor = .lightGray
containerView.addSubview(separator)
separator.topAnchor.constraint(equalTo: constraintTo, constant: constanst).isActive = true
separator.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
separator.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
separator.heightAnchor.constraint(equalToConstant: 1.0).isActive = true
return separator
}
private func createRoundedButton(title: String, action: Selector) -> EQNRoundedButton {
let button = EQNRoundedButton(frame: .zero)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: action, for: .touchUpInside)
button.setTitle(title, for: .normal)
button.setTitleColor(AppTheme.Colors.darkGray, for: .normal)
button.backgroundColor = UIColor.white.withAlphaComponent(0.5)
return button
}
/// Check if the user could be received a notification for this seismic
private func couldBeNotified(for seismic: EQNSisma) -> Bool {
let settings = EQNNotificheReteSismiche.shared()
if !settings.isAbilitato {
return false
}
if !settings.listaEnti.contains(seismic.provider) {
return false
}
var notified = true
if let radius = Double(settings.distanzaPosizione), seismic.userDistance > radius {
notified = false
}
if let magnitude = Double(settings.energiaSisma), seismic.magnitude.doubleValue < magnitude {
notified = false
}
if settings.isAbilitaVicini, seismic.userDistance < 50 {
notified = true
}
if settings.isTerremortiForti, let strongMagnitude = Double(settings.energiaTerremotiForti), seismic.magnitude.doubleValue >= strongMagnitude {
notified = true
}
return notified
}
/// Convert coordinates in degrees
private func coordinateString(coordinate: CLLocationCoordinate2D) -> String {
var latSeconds = Int(coordinate.latitude * 3600)
let latDegrees = latSeconds / 3600
latSeconds = abs(latSeconds % 3600)
let latMinutes = latSeconds / 60
latSeconds %= 60
var longSeconds = Int(coordinate.longitude * 3600)
let longDegrees = longSeconds / 3600
longSeconds = abs(longSeconds % 3600)
let longMinutes = longSeconds / 60
longSeconds %= 60
return String(format:"%d°%d'%d\"%@ lat %d°%d'%d\"%@ lon",
abs(latDegrees),
latMinutes,
latSeconds, latDegrees >= 0 ? "N" : "S",
abs(longDegrees),
longMinutes,
longSeconds,
longDegrees >= 0 ? "E" : "W" )
}
/// Determines the zoom for the map, based on the involved population
private func mapZoomFor(population: Double) -> CLLocationDegrees {
var zoom: CLLocationDegrees = 1
if population > 1_000_000 {
zoom = 7
} else if population < 500 {
zoom = 3
} else {
zoom = 5
}
return zoom
}
/// Format population value (ex. 1.5M, 2.4k)
private func formatPopulation(_ population: Double) -> String {
var populationString = ""
if population > 999_999 {
let roundedPopulation = round(population / 100_000) / 10
populationString = "\(roundedPopulation)M"
} else if population > 999 {
let roundedPopulation = round(population / 100) / 10
populationString = "\(roundedPopulation)K"
} else {
let roundedPopulation = round(population)
populationString = "\(roundedPopulation)"
}
return populationString
}
/// Calculate colors to use for text and background of the cell
private func calculateColors(for magnitude: Double) -> MagnitudeColors {
var textColor = UIColor.black
var r = 0, g = 0, b = 0
if (magnitude < 2.0) {
let fraction: Double = 1 - (magnitude - 0.0) / (2.0 - 0.0)
r = Int(round(200.0 + (255.0 - 200.0) * fraction))
g = Int(round(226.0 + (255.0 - 226.0) * fraction))
b = Int(round(196.0 + (255.0 - 196.0) * fraction))
textColor = UIColor(red: 12.0 / 255.0, green: 115.0 / 255.0, blue: 16.0 / 255.0, alpha: 1.0)
}
if (magnitude >= 2.0 && magnitude < 3.5) {
let fraction: Double = 1 - (magnitude - 2) / (3.5 - 2)
r = Int(round(136.0 + (200.0 - 136.0) * fraction))
g = Int(round(175.0 + (226.0 - 175.0) * fraction))
b = Int(round(131.0 + (196.0 - 131.0) * fraction))
textColor = UIColor(red: 12.0 / 255.0, green: 160.0 / 255.0, blue: 35.0 / 255.0, alpha: 1.0)
}
if (magnitude >= 3.5 && magnitude < 4.5) {
let fraction: Double = 1 - (magnitude - 3.5) / (4.5 - 3.5)
r = 252
g = Int(round(233.0 + (253.0 - 233.0) * fraction))
b = Int(round(179.0 + (209.0 - 179.0) * fraction))
textColor = UIColor(red: 244.0 / 255.0, green: 195.0 / 255.0, blue: 0.0 / 255.0, alpha: 1.0)
}
if (magnitude >= 4.5 && magnitude < 5.5) {
let fraction: Double = 1 - (magnitude - 4.5) / (5.5 - 4.5)
r = 252
g = Int(round(159.0 + (197.0 - 159.0) * fraction))
b = Int(round(161.0 + (197.0 - 161.0) * fraction))
textColor = UIColor(red: 255.0 / 255.0, green: 0.0 / 255.0, blue: 0.0 / 255.0, alpha: 1.0)
}
if (magnitude >= 5.5) {
let fraction: Double = 1 - (magnitude - 5.5) / (10 - 5.5)
r = Int(round(190.0 + (254.0 - 190.0) * fraction))
g = Int(round(124.0 + (219.0 - 124.0) * fraction))
b = 255
textColor = UIColor(red: 183.0 / 255.0, green: 60.0 / 255.0, blue: 252.0 / 255.0, alpha: 1.0)
}
let r2 = min(r + 30, 255)
let g2 = min(g + 30, 255)
let b2 = min(b + 30, 255)
let startColor = UIColor(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: 1.0)
let endColor = UIColor(red: CGFloat(r2) / 255.0, green: CGFloat(g2) / 255.0, blue: CGFloat(b2) / 255.0, alpha: 1.0)
return (textColor: textColor, startColor: startColor, endColor: endColor)
}
}
@@ -0,0 +1,156 @@
//
// SeismicNetworksViewController.swift
// Earthquake Network
//
// Created by Busi Andrea on 22/09/2020.
// Copyright © 2020 Earthquake Network. All rights reserved.
//
import UIKit
class SeismicNetworksViewController: EQNBaseViewController, UITableViewDelegate, UITableViewDataSource {
private static let SegueIdentifierFilters = "FiltriEntiSismici"
private static let SegueIdentifierSettings = "impostazioniEntiSismi"
private static let SegueIdentifierSeismicNetworks = "elencoRetiSismiche"
// MARK: - Internal
@IBOutlet private weak var tableView: UITableView?
private var seismics = [EQNSisma]()
/// Index path of row with map expanded
private var openMapIndexPath: IndexPath?
/// Index path of row with weather expanded
private var openWeatherIndexPath: IndexPath?
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(didReceiveDownloadCompletedNotification(_:)),
name: NSNotification.Name(rawValue: NOTIFICA_DOWNLOAD_TERMINATO),
object: nil)
setupUI()
refreshUI()
}
private func setupUI() {
title = NSLocalizedString("tab_official", comment: "")
tableView?.estimatedRowHeight = 300.0;
tableView?.rowHeight = UITableView.automaticDimension
tableView?.register(SeismicNetworkTableViewCell.self, forCellReuseIdentifier: SeismicNetworkTableViewCell.Identifier)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// todo
}
// MARK: - Notification
@objc func didReceiveDownloadCompletedNotification(_ notification: NSNotification) {
DispatchQueue.main.async {
self.refreshUI()
}
}
// MARK: - Private
override func refreshUI() {
super.refreshUI()
let allSeismics = EQNManager.manager().retiSismiche
seismics = EQNSeismic.shared.filterSeismicList(allSeismics ?? [])
tableView?.reloadData()
}
// MARK: - Actions
@IBAction func refreshDataTapped(_ sender: Any) {
EQNManager.manager().sincronizza()
}
@IBAction func openFilterTapped(_ sender: Any) {
performSegue(withIdentifier: Self.SegueIdentifierFilters, sender: nil)
}
@IBAction func openSettingsTapped(_ sender: Any) {
performSegue(withIdentifier: Self.SegueIdentifierSettings, sender: nil)
}
// MARK: - Table view delegate and data source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
seismics.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: SeismicNetworkTableViewCell.Identifier, for: indexPath) as! SeismicNetworkTableViewCell
let seismic = seismics[indexPath.row]
var type = SeismicNetworkTableViewCell.DisplayType.normal
if openMapIndexPath == indexPath {
type = .mapExpanded
} else if openWeatherIndexPath == indexPath {
type = .weatherExpanded
}
cell.configure(with: seismic, type: type, informations: [ .time, .distance, .location, .population ])
cell.delegate = self
return cell
}
}
extension SeismicNetworksViewController: SeismicNetworkTableViewCellDelegate {
func seismicNetworkCellDidTapShare(_ cell: SeismicNetworkTableViewCell) {
// create a snapshot of the cell and share with default share sheet
let snapshot = cell.createSnapshot()
let controller = UIActivityViewController(activityItems: [snapshot], applicationActivities: [])
present(controller, animated: true)
}
func seismicNetworkCellDidTapWeather(_ cell: SeismicNetworkTableViewCell) {
guard let index = tableView?.indexPath(for: cell) else { return }
let indexToReloads = [openMapIndexPath, openWeatherIndexPath, index].compactMap { $0 }
openWeatherIndexPath = index
openMapIndexPath = nil
tableView?.reloadRows(at: indexToReloads, with: .automatic)
}
func seismicNetworkCellDidTapMap(_ cell: SeismicNetworkTableViewCell) {
guard let index = tableView?.indexPath(for: cell) else { return }
let indexToReloads = [openMapIndexPath, openWeatherIndexPath, index].compactMap { $0 }
openMapIndexPath = index
openWeatherIndexPath = nil
tableView?.reloadRows(at: indexToReloads, with: .automatic)
}
func seismicNetworkCellDidTapCalendar(_ cell: SeismicNetworkTableViewCell) {
// todo
}
func seismicNetworkCellDidTapSettings(_ cell: SeismicNetworkTableViewCell) {
// todo
}
func seismicNetworkCellDidTapClose(_ cell: SeismicNetworkTableViewCell) {
guard let index = tableView?.indexPath(for: cell) else { return }
let indexToReloads = [openMapIndexPath, openWeatherIndexPath, index].compactMap { $0 }
openMapIndexPath = nil
openWeatherIndexPath = nil
tableView?.reloadRows(at: indexToReloads, with: .automatic)
}
}
@@ -8,3 +8,4 @@
#import "EQNManager.h"
#import "EQNNotificheReteSismiche.h"
#import "EQNSisma.h"
#import "EQNBaseViewController.h"
+2
View File
@@ -42,6 +42,8 @@
<string> Ci occorre la tua posizione per inviare messaggi precisi in caso di terremoto</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string> Ci occorre la tua posizione per inviare messaggi precisi in caso di terremoto</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>L&apos;accesso alla libreria è richiesto per poter salvare le immagini generate dall&apos;app</string>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
@@ -0,0 +1,19 @@
//
// UIFont+Extensions.swift
// Earthquake Network
//
// Created by Busi Andrea on 25/09/2020.
// Copyright © 2020 Earthquake Network. All rights reserved.
//
import Foundation
extension UIFont {
static func preferredFont(for style: TextStyle, weight: Weight) -> UIFont {
let metrics = UIFontMetrics(forTextStyle: style)
let desc = UIFontDescriptor.preferredFontDescriptor(withTextStyle: style)
let font = UIFont.systemFont(ofSize: desc.pointSize, weight: weight)
return metrics.scaledFont(for: font)
}
}
@@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "bell.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "bell@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "bell@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "bell_disabled.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "bell_disabled@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "bell_disabled@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "share_icon.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
}
}
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,5 @@
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Change to 'Always allow' so we can alert you in real time when an earthquake occurs nearby.";
"NSLocationAlwaysUsageDescription" = "Change to 'Always allow' so we can alert you in real time when an earthquake occurs nearby.";
"NSLocationWhenInUseUsageDescription" = "We need your location to send you real time seismic alerts.";
"NSPhotoLibraryAddUsageDescription" = "Access to the library is required in order to save the images generated by the app";
"CFBundleDisplayName" = "Earthquake Network";
@@ -111,9 +111,6 @@
/* No comment provided by engineer. */
"Copertura" = "Coverage";
/* No comment provided by engineer. */
"Copertura nuvolosa : " = "Cloud cover : ";
/* No comment provided by engineer. */
"Costa Rica" = "Costa Rica";
@@ -327,9 +324,6 @@
/* No comment provided by engineer. */
"METEO" = "WEATHER";
/* No comment provided by engineer. */
"Meteo al momento del sisma" = "Weather at the time of the earthquake";
/* No comment provided by engineer. */
"minuti fa" = "minutes ago";
@@ -434,9 +428,6 @@
/* No comment provided by engineer. */
"Perù" = "Per";
/* No comment provided by engineer. */
"Pressione:" = "Pressure:";
/* No comment provided by engineer. */
"Privacy: http://wp.earthquakenetwork.it/privacy/\n\nTermini e condizioni: http://wp.earthquakenetwork.it/it/terms-conditions/" = "Privacy: http://wp.earthquakenetwork.it/privacy/\n\nTerms and conditions: http://wp.earthquakenetwork.it/it/terms-conditions/";
@@ -558,9 +549,6 @@
/* voce elenco messaggio tsunami */
"Supplemento di valutazione" = "Evaluation supplement";
/* No comment provided by engineer. */
"Temperatura: " = "Temperature: ";
/* voce menu */
"Terremoti forti" = "Strong earthquakes";
@@ -601,9 +589,6 @@
/* No comment provided by engineer. */
"Ultimo mese" = "Last month";
/* No comment provided by engineer. */
"Umidità : " = "Humidity : ";
/* No comment provided by engineer. */
"Un anno" = "One year";
@@ -637,9 +622,6 @@
/* titolo pulsante notifica rete smartphone */
"VEDI IN TWITTER" = "SEE ON TWITTER";
/* No comment provided by engineer. */
"Velocità vento: " = "Wind speed: ";
/* No comment provided by engineer. */
"Venezuela" = "Venezuela";
@@ -769,3 +751,13 @@
"Modifica le impostazioni di notifica dei sismi in accordo con i filtri" = "Change the earthquake notification settings according to the filters";
"main_understood" = "Understood";
"options_low_magnitude" = "Beware that not all seismic networks provide earthquake data below magnitude 2.0. Moreover, you significantly increase the data transfer and the battery usage due to notifications. Unless your device is recently manufactured, you will also notice a general slowdown.";
"share_radius100" = "in a radius of 100km";
"report_smartphones" = "🚨 Sisma rilevato in tempo reale da %@ smartphones. Allerta inviata."; // missing
"report_users" = "⚠️ Segnalato da %@ utenti"; // missing
"weather_weather" = "Weather at the time of the earthquake";
"weather_temperature" = "Temperature: %.02f°C";
"weather_pressure" = "Pressure: %@mb";
"weather_windspeed" = "Wind speed: %@m/s";
"weather_humidity" = "Humidity: %@%%";
"weather_clouds" = "Cloud cover: %@%%";
"official_prelimiary" = "Preliminary";
@@ -1,4 +1,5 @@
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Cambiar a 'Permitir siempre' para que podamos alertarte en tiempo real cuando se produce un sismo cercano.";
"NSLocationAlwaysUsageDescription" = "Cambiar a 'Permitir siempre' para que podamos alertarte en tiempo real cuando se produce un sismo cercano.";
"NSLocationWhenInUseUsageDescription" = "Necesitamos tu ubicación para enviarte alertas sísmicas en tiempo real";
"NSPhotoLibraryAddUsageDescription" = "Se requiere acceso a la biblioteca para guardar las imágenes generadas por la aplicación";
"CFBundleDisplayName" = "Sismos Detector";
@@ -104,9 +104,6 @@
/* No comment provided by engineer. */
"Copertura" = "Cobertura";
/* No comment provided by engineer. */
"Copertura nuvolosa : " = "Cubierta de nubes: ";
/* No comment provided by engineer. */
"Costa Rica" = "Costa Rica";
@@ -322,9 +319,6 @@
/* No comment provided by engineer. */
"METEO" = "TIEMPO";
/* No comment provided by engineer. */
"Meteo al momento del sisma" = "Tiempo en el momento del terremoto";
/* No comment provided by engineer. */
"minuti fa" = "minutos";
@@ -429,9 +423,6 @@
/* No comment provided by engineer. */
"Perù" = "Peru";
/* No comment provided by engineer. */
"Pressione:" = "Presión:";
/* No comment provided by engineer. */
"Privacy: http://wp.earthquakenetwork.it/privacy/\n\nTermini e condizioni: http://wp.earthquakenetwork.it/it/terms-conditions/" = "Privacidad: http://wp.earthquakenetwork.it/privacy/\n\nTérminos y condiciones: http://wp.earthquakenetwork.it/it/terms-conditions/";
@@ -553,9 +544,6 @@
/* voce elenco messaggio tsunami */
"Supplemento di valutazione" = "Suplemento de evaluación";
/* No comment provided by engineer. */
"Temperatura: " = "Temperaturas: ";
/* voce menu */
"Terremoti forti" = "Sismos fuertes";
@@ -596,9 +584,6 @@
/* No comment provided by engineer. */
"Ultimo mese" = "Ultimo mes";
/* No comment provided by engineer. */
"Umidità : " = "Humedad: ";
/* No comment provided by engineer. */
"Un anno" = "Un año";
@@ -759,3 +744,13 @@
"Modifica le impostazioni di notifica dei sismi in accordo con i filtri" = "Cambia las notificaciones de sismo de acuerdo a los filtros";
"main_understood" = "Entendido";
"options_low_magnitude" = "Tenga en cuenta que no todas las redes sísmicas proporcionan datos para sismos de magnitud inferior a 2.0. Además, aumenta significativamente la transferencia de datos con el servidor y el uso de la batería debido a la mayor cantidad de notificaciones. Si tu dispositivo no se ha fabricado recientemente, también notará una desaceleración general de la aplicación.";
"share_radius100" = "en un radio de 100km";
"report_smartphones" = "🚨 Sisma rilevato in tempo reale da %@ smartphones. Allerta inviata."; // missing
"report_users" = "⚠️ Segnalato da %@ utenti"; // missing
"weather_weather" = "Tiempo en el momento del terremoto";
"weather_temperature" = "Temperaturas: %.02f°C";
"weather_pressure" = "Presión: %@mb";
"weather_windspeed" = "Velocidad viento: %@m/s";
"weather_humidity" = "Humedad: %@%%";
"weather_clouds" = "Cubierta de nubes: %@%%";
"official_prelimiary" = "Preliminar";
@@ -1,4 +1,5 @@
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Passa a 'Consenti sempre' in modo che possiamo allertarti in tempo reale quando accade un sisma nelle tue vicinanze.";
"NSLocationAlwaysUsageDescription" = "Passa a 'Consenti sempre' in modo che possiamo allertarti in tempo reale quando accade un sisma nelle tue vicinanze.";
"NSLocationWhenInUseUsageDescription" = "La tua posizione è necessaria per ricevere le allerte sismiche in tempo reale.";
"NSPhotoLibraryAddUsageDescription" = "L'accesso alla libreria è richiesto per poter salvare le immagini generate dall'app";
"CFBundleDisplayName" = "Rilevatore Terremoto";
@@ -104,9 +104,6 @@
/* No comment provided by engineer. */
"Copertura" = "Copertura";
/* No comment provided by engineer. */
"Copertura nuvolosa : " = "Copertura nuvolosa : ";
/* No comment provided by engineer. */
"Costa Rica" = "Costa Rica";
@@ -320,9 +317,6 @@
/* No comment provided by engineer. */
"METEO" = "METEO";
/* No comment provided by engineer. */
"Meteo al momento del sisma" = "Meteo al momento del sisma";
/* No comment provided by engineer. */
"minuti fa" = "minuti fa";
@@ -427,9 +421,6 @@
/* No comment provided by engineer. */
"Perù" = "Perù";
/* No comment provided by engineer. */
"Pressione:" = "Pressione:";
/* No comment provided by engineer. */
"Privacy: http://wp.earthquakenetwork.it/privacy/\n\nTermini e condizioni: http://wp.earthquakenetwork.it/it/terms-conditions/" = "Privacy: http://wp.earthquakenetwork.it/privacy/\n\nTermini e condizioni: http://wp.earthquakenetwork.it/it/terms-conditions/";
@@ -551,9 +542,6 @@
/* voce elenco messaggio tsunami */
"Supplemento di valutazione" = "Supplemento di valutazione";
/* No comment provided by engineer. */
"Temperatura: " = "Temperatura: ";
/* voce menu */
"Terremoti forti" = "Sismi forti";
@@ -595,9 +583,6 @@
/* No comment provided by engineer. */
"Ultimo mese" = "Ultimo mese";
/* No comment provided by engineer. */
"Umidità : " = "Umidità : ";
/* No comment provided by engineer. */
"Un anno" = "Un anno";
@@ -631,9 +616,6 @@
/* titolo pulsante notifica rete smartphone */
"VEDI IN TWITTER" = "VEDI IN TWITTER";
/* No comment provided by engineer. */
"Velocità vento: " = "Velocità vento: ";
/* No comment provided by engineer. */
"Venezuela" = "Venezuela";
@@ -755,3 +737,13 @@
"Modifica le impostazioni di notifica dei sismi in accordo con i filtri" = "Modifica le impostazioni di notifica dei sismi in accordo con i filtri";
"main_understood" = "Ho capito";
"options_low_magnitude" = "Considera che non tutte le reti sismiche forniscono dati per sismi sotto magnitudo 2.0. Inoltre, incrementi significativamente il trasferimento dati con il server e l'utilizzo batteria dovuto al maggior numero di notifiche. Se il tuo dispositivo non è di recente fabbricazione, noterai anche un generale rallentamento dell'app.";
"report_smartphones" = "🚨 Sisma rilevato in tempo reale da %@ smartphones. Allerta inviata."; // missing
"report_users" = "⚠️ Segnalato da %@ utenti"; // missing
"share_radius100" = "in un raggio di 100km";
"weather_weather" = "Meteo al momento del sisma";
"weather_temperature" = "Temperatura: %.02f°C";
"weather_pressure" = "Pressione: %@mb";
"weather_windspeed" = "Velocità vento: %@m/s";
"weather_humidity" = "Umidità: %@%%";
"weather_clouds" = "Copertura nuvolosa: %@%%";
"official_prelimiary" = "Preliminare";
@@ -10,6 +10,8 @@
#import "EQNReteSmartphone.h"
#import "EQNAreaCheck.h"
@class EQNSisma;
@interface EQNManager : NSObject
@property (nonatomic, assign) BOOL isBackground;
@@ -18,7 +20,7 @@
@property (nonatomic, strong, nullable) NSArray *datiGraficoUtente;
@property (nonatomic, strong, nullable) NSArray *datiPastQuakes;
@property (nonatomic, strong, nullable) NSArray *elencoSelagnazioniManuali;
@property (nonatomic, strong, nullable) NSArray *retiSismiche;
@property (nonatomic, strong, nullable) NSArray<EQNSisma *> *retiSismiche;
+ (nonnull instancetype)defaultManager NS_SWIFT_NAME(manager());