Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f85c60fdda | |||
| 5f2a083789 | |||
| 9e54f74847 | |||
| b6f9232f56 | |||
| dee14dea0f | |||
| db0bde2f59 | |||
| 79d0d27ec5 | |||
| 68012ec406 | |||
| 59feb7699b | |||
| 388f4e8b89 | |||
| ca3c9ebd83 | |||
| f23c19bce7 | |||
| 276fa2032a | |||
| 09f0d4d4d8 | |||
| 25f061ad5a | |||
| b9d9f7579c | |||
| 39f5ff0249 | |||
| af68d70be5 | |||
| dab999a78d | |||
| f5ede5c26d | |||
| 6d4c1eb979 |
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 5.11
|
||||||
|
- Numeri romani in etichette shakemaps
|
||||||
|
- Aggiunta barra di recap dei filtri in Lista Sismi
|
||||||
|
- Riscritta NotificationContent in Swift
|
||||||
|
- Aggiunta animazione onda sismica in NotificationContent (+ altre modifiche grafiche)
|
||||||
|
|
||||||
## 5.10
|
## 5.10
|
||||||
- Usato endpoint cache per distquake_download_areacheck
|
- Usato endpoint cache per distquake_download_areacheck
|
||||||
- Aggiunta impostazione per non riprodurre suono notifiche per simsi deboli
|
- Aggiunta impostazione per non riprodurre suono notifiche per simsi deboli
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="M4Y-Lb-cyx">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="M4Y-Lb-cyx">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -11,37 +11,45 @@
|
|||||||
<!--Notification View Controller-->
|
<!--Notification View Controller-->
|
||||||
<scene sceneID="cwh-vc-ff4">
|
<scene sceneID="cwh-vc-ff4">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController id="M4Y-Lb-cyx" userLabel="Notification View Controller" customClass="NotificationViewController" sceneMemberID="viewController">
|
<viewController id="M4Y-Lb-cyx" userLabel="Notification View Controller" customClass="NotificationContentViewController" customModule="EQNNotificationContent" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
<view key="view" contentMode="scaleToFill" simulatedAppContext="notificationCenter" id="S3S-Oj-5AN">
|
<view key="view" contentMode="scaleToFill" simulatedAppContext="notificationCenter" id="S3S-Oj-5AN">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="320" height="330"/>
|
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pCT-Wh-lut">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pCT-Wh-lut">
|
||||||
<rect key="frame" x="8" y="216" width="304" height="20.5"/>
|
<rect key="frame" x="8" y="350" width="304" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bT3-3m-qLh">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bT3-3m-qLh">
|
||||||
<rect key="frame" x="8" y="285" width="304" height="29"/>
|
<rect key="frame" x="8" y="417" width="304" height="53"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle2"/>
|
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
|
||||||
<color key="textColor" red="0.91764705879999997" green="0.46274509800000002" blue="0.0078431372550000003" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="textColor" red="0.91764705879999997" green="0.46274509800000002" blue="0.0078431372550000003" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="4ID-Zb-OQF">
|
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" showsUserLocation="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4ID-Zb-OQF">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="320" height="200"/>
|
<rect key="frame" x="0.0" y="20" width="320" height="320"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="200" id="Pgl-8e-ePq"/>
|
<constraint firstAttribute="width" secondItem="4ID-Zb-OQF" secondAttribute="height" multiplier="1:1" id="yXb-UG-FZY"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="delegate" destination="M4Y-Lb-cyx" id="Cs2-OY-eT2"/>
|
<outlet property="delegate" destination="M4Y-Lb-cyx" id="Cs2-OY-eT2"/>
|
||||||
</connections>
|
</connections>
|
||||||
</mapView>
|
</mapView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f3d-th-bgU">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f3d-th-bgU">
|
||||||
<rect key="frame" x="8" y="244.5" width="304" height="20.5"/>
|
<rect key="frame" x="8" y="380.5" width="304" height="26.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle2"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="s7c-ag-zBA" customClass="EQNBlurredCloseButton" customModule="EQNNotificationContent" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="103" y="26" width="114" height="35"/>
|
||||||
|
<state key="normal" title="Button"/>
|
||||||
|
<buttonConfiguration key="configuration" style="plain" title="Tap to open"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="openAppTapped:" destination="M4Y-Lb-cyx" eventType="touchUpInside" id="Sw3-xS-cXi"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<viewLayoutGuide key="safeArea" id="2BE-c3-nQJ"/>
|
<viewLayoutGuide key="safeArea" id="2BE-c3-nQJ"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
@@ -49,23 +57,26 @@
|
|||||||
<constraint firstItem="f3d-th-bgU" firstAttribute="leading" secondItem="pCT-Wh-lut" secondAttribute="leading" id="7qA-vV-ocI"/>
|
<constraint firstItem="f3d-th-bgU" firstAttribute="leading" secondItem="pCT-Wh-lut" secondAttribute="leading" id="7qA-vV-ocI"/>
|
||||||
<constraint firstItem="2BE-c3-nQJ" firstAttribute="trailing" secondItem="pCT-Wh-lut" secondAttribute="trailing" constant="8" id="CAC-UM-SaJ"/>
|
<constraint firstItem="2BE-c3-nQJ" firstAttribute="trailing" secondItem="pCT-Wh-lut" secondAttribute="trailing" constant="8" id="CAC-UM-SaJ"/>
|
||||||
<constraint firstItem="f3d-th-bgU" firstAttribute="trailing" secondItem="pCT-Wh-lut" secondAttribute="trailing" id="Dd7-BF-iOG"/>
|
<constraint firstItem="f3d-th-bgU" firstAttribute="trailing" secondItem="pCT-Wh-lut" secondAttribute="trailing" id="Dd7-BF-iOG"/>
|
||||||
<constraint firstItem="f3d-th-bgU" firstAttribute="top" secondItem="pCT-Wh-lut" secondAttribute="bottom" constant="8" id="FJ8-nn-ydU"/>
|
<constraint firstItem="f3d-th-bgU" firstAttribute="top" secondItem="pCT-Wh-lut" secondAttribute="bottom" constant="10" id="FJ8-nn-ydU"/>
|
||||||
<constraint firstItem="2BE-c3-nQJ" firstAttribute="bottom" secondItem="bT3-3m-qLh" secondAttribute="bottom" constant="16" id="I71-6U-jK3"/>
|
<constraint firstItem="s7c-ag-zBA" firstAttribute="top" secondItem="2BE-c3-nQJ" secondAttribute="top" constant="6" id="Gsp-ye-V4M"/>
|
||||||
<constraint firstItem="pCT-Wh-lut" firstAttribute="top" secondItem="4ID-Zb-OQF" secondAttribute="bottom" constant="16" id="It9-RA-906"/>
|
<constraint firstItem="2BE-c3-nQJ" firstAttribute="bottom" secondItem="bT3-3m-qLh" secondAttribute="bottom" constant="10" id="I71-6U-jK3"/>
|
||||||
|
<constraint firstItem="pCT-Wh-lut" firstAttribute="top" secondItem="4ID-Zb-OQF" secondAttribute="bottom" constant="10" id="It9-RA-906"/>
|
||||||
<constraint firstItem="bT3-3m-qLh" firstAttribute="trailing" secondItem="f3d-th-bgU" secondAttribute="trailing" id="KXf-x4-iZs"/>
|
<constraint firstItem="bT3-3m-qLh" firstAttribute="trailing" secondItem="f3d-th-bgU" secondAttribute="trailing" id="KXf-x4-iZs"/>
|
||||||
<constraint firstItem="bT3-3m-qLh" firstAttribute="leading" secondItem="f3d-th-bgU" secondAttribute="leading" id="QlJ-Vh-oi4"/>
|
<constraint firstItem="bT3-3m-qLh" firstAttribute="leading" secondItem="f3d-th-bgU" secondAttribute="leading" id="QlJ-Vh-oi4"/>
|
||||||
<constraint firstItem="bT3-3m-qLh" firstAttribute="top" secondItem="f3d-th-bgU" secondAttribute="bottom" constant="20" id="UUO-2F-eE7"/>
|
<constraint firstItem="bT3-3m-qLh" firstAttribute="top" secondItem="f3d-th-bgU" secondAttribute="bottom" constant="10" id="UUO-2F-eE7"/>
|
||||||
<constraint firstItem="4ID-Zb-OQF" firstAttribute="trailing" secondItem="2BE-c3-nQJ" secondAttribute="trailing" id="buf-BU-I5b"/>
|
<constraint firstItem="4ID-Zb-OQF" firstAttribute="trailing" secondItem="2BE-c3-nQJ" secondAttribute="trailing" id="buf-BU-I5b"/>
|
||||||
<constraint firstItem="4ID-Zb-OQF" firstAttribute="leading" secondItem="2BE-c3-nQJ" secondAttribute="leading" id="e8D-ji-t64"/>
|
<constraint firstItem="4ID-Zb-OQF" firstAttribute="leading" secondItem="2BE-c3-nQJ" secondAttribute="leading" id="e8D-ji-t64"/>
|
||||||
<constraint firstItem="4ID-Zb-OQF" firstAttribute="top" secondItem="2BE-c3-nQJ" secondAttribute="top" id="hL6-gc-S6i"/>
|
<constraint firstItem="4ID-Zb-OQF" firstAttribute="top" secondItem="2BE-c3-nQJ" secondAttribute="top" id="hL6-gc-S6i"/>
|
||||||
|
<constraint firstItem="s7c-ag-zBA" firstAttribute="centerX" secondItem="S3S-Oj-5AN" secondAttribute="centerX" id="mKj-2O-QDw"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<extendedEdge key="edgesForExtendedLayout"/>
|
<extendedEdge key="edgesForExtendedLayout"/>
|
||||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||||
<size key="freeformSize" width="320" height="330"/>
|
<size key="freeformSize" width="320" height="480"/>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="descriptionLabel" destination="f3d-th-bgU" id="Aym-KJ-DqY"/>
|
<outlet property="descriptionLabel" destination="f3d-th-bgU" id="Aym-KJ-DqY"/>
|
||||||
<outlet property="mapView" destination="4ID-Zb-OQF" id="x8o-nT-bL4"/>
|
<outlet property="mapView" destination="4ID-Zb-OQF" id="x8o-nT-bL4"/>
|
||||||
|
<outlet property="tapToOpenButton" destination="s7c-ag-zBA" id="4aZ-hT-1vc"/>
|
||||||
<outlet property="titleLabel" destination="pCT-Wh-lut" id="uIg-dn-Wms"/>
|
<outlet property="titleLabel" destination="pCT-Wh-lut" id="uIg-dn-Wms"/>
|
||||||
<outlet property="waveLabel" destination="bT3-3m-qLh" id="AkJ-nd-d2R"/>
|
<outlet property="waveLabel" destination="bT3-3m-qLh" id="AkJ-nd-d2R"/>
|
||||||
</connections>
|
</connections>
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
//
|
||||||
|
// NotificationContentViewController.swift
|
||||||
|
// EQNNotificationContent
|
||||||
|
//
|
||||||
|
// Created by Andrea Busi on 24/07/25.
|
||||||
|
// Copyright © 2025 Earthquake Network. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import MapKit
|
||||||
|
import UserNotifications
|
||||||
|
import UserNotificationsUI
|
||||||
|
|
||||||
|
class NotificationContentViewController: UIViewController {
|
||||||
|
|
||||||
|
// MARK: - UI
|
||||||
|
|
||||||
|
@IBOutlet private weak var titleLabel: UILabel!
|
||||||
|
@IBOutlet private weak var descriptionLabel: UILabel!
|
||||||
|
@IBOutlet private weak var waveLabel: UILabel!
|
||||||
|
@IBOutlet private weak var mapView: MKMapView!
|
||||||
|
@IBOutlet private weak var tapToOpenButton: UIButton!
|
||||||
|
|
||||||
|
private var animator: MapSeismicWaveAnimator?
|
||||||
|
|
||||||
|
// MARK: - View
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
let tapRecognizer = UITapGestureRecognizer(
|
||||||
|
target: self,
|
||||||
|
action: #selector(openAppTapped(_:))
|
||||||
|
)
|
||||||
|
view.addGestureRecognizer(tapRecognizer)
|
||||||
|
|
||||||
|
mapView
|
||||||
|
.register(
|
||||||
|
EQNCustomAnnotationView.self,
|
||||||
|
forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SingleLineIdentifier
|
||||||
|
)
|
||||||
|
mapView
|
||||||
|
.register(
|
||||||
|
EQNCustomAnnotationView.self,
|
||||||
|
forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SmallIdentifier
|
||||||
|
)
|
||||||
|
tapToOpenButton.setTitle("tap_to_open".localized, for: .normal)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillDisappear(_ animated: Bool) {
|
||||||
|
super.viewWillDisappear(animated)
|
||||||
|
|
||||||
|
animator?.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Actions
|
||||||
|
|
||||||
|
@IBAction private func openAppTapped(_ sender: Any) {
|
||||||
|
extensionContext?.performNotificationDefaultAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NotificationContentViewController: UNNotificationContentExtension {
|
||||||
|
|
||||||
|
func didReceive(_ notification: UNNotification) {
|
||||||
|
let content = notification.request.content
|
||||||
|
|
||||||
|
titleLabel.text = content.title
|
||||||
|
descriptionLabel.text = content.body
|
||||||
|
|
||||||
|
let notification = EQNRealtimePushNotification.from(
|
||||||
|
userInfo: content.userInfo,
|
||||||
|
title: "",
|
||||||
|
displayTitle: content.title,
|
||||||
|
displayBody: content.body
|
||||||
|
)
|
||||||
|
if let notification {
|
||||||
|
let coordinate = notification.coordinate.coordinate
|
||||||
|
let span = MKCoordinateSpan(latitudeDelta: 6, longitudeDelta: 6)
|
||||||
|
let region = MKCoordinateRegion(
|
||||||
|
center: coordinate,
|
||||||
|
span: span
|
||||||
|
)
|
||||||
|
mapView.setCenter(coordinate, animated: false)
|
||||||
|
mapView.setRegion(region, animated: true)
|
||||||
|
|
||||||
|
switch notification.type.lowercased() {
|
||||||
|
case "eqn":
|
||||||
|
let annotation = EQNMapAnnotationPastquake(
|
||||||
|
title: "",
|
||||||
|
coordinate: coordinate,
|
||||||
|
intensity: notification.intensity
|
||||||
|
)
|
||||||
|
mapView.addAnnotation(annotation)
|
||||||
|
case "manual":
|
||||||
|
let annotation = EQNMapAnnotationUserReport(
|
||||||
|
magnitude: notification.magnitude,
|
||||||
|
coordinate: coordinate
|
||||||
|
)
|
||||||
|
mapView.addAnnotation(annotation)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// create animator to manage wave animation and countdown
|
||||||
|
animator = MapSeismicWaveAnimator(
|
||||||
|
realtimeAlert: notification,
|
||||||
|
mapView: mapView,
|
||||||
|
waveTimeLabel: waveLabel
|
||||||
|
)
|
||||||
|
animator?.start()
|
||||||
|
// set color based on intensity
|
||||||
|
descriptionLabel.textColor = notification.relativeIntensityColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NotificationContentViewController: MKMapViewDelegate {
|
||||||
|
|
||||||
|
func mapView(_ mapView: MKMapView, viewFor annotation: any MKAnnotation) -> MKAnnotationView? {
|
||||||
|
switch annotation {
|
||||||
|
case let pastquake as EQNMapAnnotationPastquake:
|
||||||
|
let annotationView = mapView.dequeueReusableAnnotationView(
|
||||||
|
withIdentifier: EQNCustomAnnotationView.SingleLineIdentifier
|
||||||
|
) as! EQNCustomAnnotationView
|
||||||
|
annotationView.image = pastquake.image
|
||||||
|
annotationView.title = pastquake.title
|
||||||
|
return annotationView
|
||||||
|
case let report as EQNMapAnnotationUserReport:
|
||||||
|
let annotationView = mapView.dequeueReusableAnnotationView(
|
||||||
|
withIdentifier: EQNCustomAnnotationView.SmallIdentifier
|
||||||
|
) as! EQNCustomAnnotationView
|
||||||
|
annotationView.image = report.image(with: EQNCustomAnnotationView.SmallViewImageHeight)
|
||||||
|
annotationView.title = report.timeDifference
|
||||||
|
return annotationView
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
|
||||||
|
animator?.getOverlayRenderer(for: overlay) ?? MKOverlayRenderer(overlay: overlay)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
//
|
|
||||||
// NotificationViewController.h
|
|
||||||
// EQNNotificationContent
|
|
||||||
//
|
|
||||||
// Refactored by Andrea Busi on 14/10/2020.
|
|
||||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
@interface NotificationViewController : UIViewController
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
//
|
|
||||||
// NotificationViewController.m
|
|
||||||
// EQNNotificationContent
|
|
||||||
//
|
|
||||||
// Refactored by Andrea Busi on 14/10/2020.
|
|
||||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "NotificationViewController.h"
|
|
||||||
#import "EQNUtility.h"
|
|
||||||
#import "EQNNotificationContent-Swift.h"
|
|
||||||
|
|
||||||
@import UserNotifications;
|
|
||||||
@import UserNotificationsUI;
|
|
||||||
@import MapKit;
|
|
||||||
|
|
||||||
@interface NotificationViewController () <UNNotificationContentExtension, MKMapViewDelegate>
|
|
||||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
|
||||||
@property (weak, nonatomic) IBOutlet UILabel *descriptionLabel;
|
|
||||||
@property (weak, nonatomic) IBOutlet UILabel *waveLabel;
|
|
||||||
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
|
|
||||||
|
|
||||||
/// This will be calculated as seismic date + warning time
|
|
||||||
@property (strong, nonatomic) NSDate *userSeismicTimestamp;
|
|
||||||
@property (strong, nonatomic) NSTimer *countdownTimer;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation NotificationViewController
|
|
||||||
|
|
||||||
- (void)setMapView:(MKMapView *)mapView
|
|
||||||
{
|
|
||||||
_mapView = mapView;
|
|
||||||
_mapView.scrollEnabled = NO;
|
|
||||||
_mapView.zoomEnabled = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - View Lifecycle
|
|
||||||
|
|
||||||
- (void)viewDidLoad
|
|
||||||
{
|
|
||||||
[super viewDidLoad];
|
|
||||||
|
|
||||||
[self.mapView registerClass:[EQNCustomAnnotationView class] forAnnotationViewWithReuseIdentifier:EQNCustomAnnotationView.SingleLineIdentifier];
|
|
||||||
[self.mapView registerClass:[EQNCustomAnnotationView class] forAnnotationViewWithReuseIdentifier:EQNCustomAnnotationView.SmallIdentifier];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)didReceiveNotification:(UNNotification *)notification
|
|
||||||
{
|
|
||||||
UNNotificationContent *content = notification.request.content;
|
|
||||||
NSDictionary *userInfo = content.userInfo;
|
|
||||||
|
|
||||||
// set title and description
|
|
||||||
self.titleLabel.text = content.title;
|
|
||||||
self.descriptionLabel.text = content.body;
|
|
||||||
|
|
||||||
// add annotation onthe map
|
|
||||||
CLLocation *coordinate = [[CLLocation alloc] initWithLatitude:[userInfo[@"latitude"] doubleValue]
|
|
||||||
longitude:[userInfo[@"longitude"] doubleValue]];
|
|
||||||
MKCoordinateSpan span = MKCoordinateSpanMake(10.5, 10.5);
|
|
||||||
MKCoordinateRegion region = MKCoordinateRegionMake(coordinate.coordinate, span);
|
|
||||||
[self.mapView setCenterCoordinate:coordinate.coordinate animated:NO];
|
|
||||||
[self.mapView setRegion:region animated:YES];
|
|
||||||
|
|
||||||
if ([userInfo[@"type"] isEqualToString:@"eqn"]) {
|
|
||||||
EQNMapAnnotationPastquake *annotation = [[EQNMapAnnotationPastquake alloc] initWithTitle:@""
|
|
||||||
coordinate:coordinate.coordinate
|
|
||||||
intensity:[userInfo[@"intensity"] intValue]];
|
|
||||||
[self.mapView addAnnotation:annotation];
|
|
||||||
|
|
||||||
} else if ([userInfo[@"type"] isEqualToString:@"manual"]){
|
|
||||||
EQNMapAnnotationUserReport *annotation = [[EQNMapAnnotationUserReport alloc] initWithMagnitude:[userInfo[@"magnitude"] intValue]
|
|
||||||
coordinate:coordinate.coordinate];
|
|
||||||
[self.mapView addAnnotation:annotation];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
self.userSeismicTimestamp = [EQNUtility calculateUserSeismicTimestampFromUserInfo:userInfo];
|
|
||||||
if (self.userSeismicTimestamp) {
|
|
||||||
// start the countdown
|
|
||||||
self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
|
|
||||||
target:self
|
|
||||||
selector:@selector(countdownFired:)
|
|
||||||
userInfo:nil
|
|
||||||
repeats:YES];
|
|
||||||
[self.countdownTimer fire];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Private
|
|
||||||
|
|
||||||
- (void)countdownFired:(id)sender
|
|
||||||
{
|
|
||||||
NSDate *now = [NSDate date];
|
|
||||||
NSTimeInterval difference = MAX([self.userSeismicTimestamp timeIntervalSinceDate:now], 0);
|
|
||||||
NSInteger seconds = (int)lround(difference);
|
|
||||||
|
|
||||||
self.waveLabel.text = [NSString localizedStringWithFormat:NSLocalizedString(@"alert_wave", @""), seconds];
|
|
||||||
|
|
||||||
if (difference <= 0) {
|
|
||||||
// stop the countdown
|
|
||||||
[self.countdownTimer invalidate];
|
|
||||||
self.countdownTimer = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - MKMapViewDelegate
|
|
||||||
|
|
||||||
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
|
|
||||||
{
|
|
||||||
if ([annotation isKindOfClass:[EQNMapAnnotationPastquake class]]) {
|
|
||||||
EQNMapAnnotationPastquake *pastquake = (EQNMapAnnotationPastquake *)annotation;
|
|
||||||
|
|
||||||
EQNCustomAnnotationView *annotationView = (EQNCustomAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:EQNCustomAnnotationView.SingleLineIdentifier];
|
|
||||||
annotationView.image = pastquake.image;
|
|
||||||
annotationView.title = pastquake.title;
|
|
||||||
return annotationView;
|
|
||||||
|
|
||||||
} else if ([annotation isKindOfClass:[EQNMapAnnotationUserReport class]]) {
|
|
||||||
EQNMapAnnotationUserReport *report = (EQNMapAnnotationUserReport *)annotation;
|
|
||||||
|
|
||||||
EQNCustomAnnotationView *annotationView = (EQNCustomAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:EQNCustomAnnotationView.SmallIdentifier];
|
|
||||||
annotationView.image = [report imageWithHeight:EQNCustomAnnotationView.SmallViewImageHeight];
|
|
||||||
annotationView.title = report.timeDifference;
|
|
||||||
return annotationView;
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
652A3C6B2A8A757800719796 /* EQNBackgrounPositionDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652A3C6A2A8A757800719796 /* EQNBackgrounPositionDebugViewController.swift */; };
|
652A3C6B2A8A757800719796 /* EQNBackgrounPositionDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652A3C6A2A8A757800719796 /* EQNBackgrounPositionDebugViewController.swift */; };
|
||||||
65355FFF25F38D3300BB57D2 /* SegnalazioniMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65355FFE25F38D3300BB57D2 /* SegnalazioniMapViewController.swift */; };
|
65355FFF25F38D3300BB57D2 /* SegnalazioniMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65355FFE25F38D3300BB57D2 /* SegnalazioniMapViewController.swift */; };
|
||||||
653604E9262348FA00B2B651 /* EQNBaseMapFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653604E8262348FA00B2B651 /* EQNBaseMapFilter.swift */; };
|
653604E9262348FA00B2B651 /* EQNBaseMapFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653604E8262348FA00B2B651 /* EQNBaseMapFilter.swift */; };
|
||||||
|
653C5C2C2E295C5A00E25528 /* SeismicNetworkFilterRecapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653C5C2B2E295C5A00E25528 /* SeismicNetworkFilterRecapView.swift */; };
|
||||||
653C67E225F3CC2E00FE52AC /* EQNCustomAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */; };
|
653C67E225F3CC2E00FE52AC /* EQNCustomAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */; };
|
||||||
653C67E625F3CC8400FE52AC /* EQNCustomAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */; };
|
653C67E625F3CC8400FE52AC /* EQNCustomAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */; };
|
||||||
653C67FC25F3D63500FE52AC /* EQNMapAnnotationUserReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653C67FB25F3D63500FE52AC /* EQNMapAnnotationUserReport.swift */; };
|
653C67FC25F3D63500FE52AC /* EQNMapAnnotationUserReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653C67FB25F3D63500FE52AC /* EQNMapAnnotationUserReport.swift */; };
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
65583A05261B83BE00ECA9F9 /* UIKit+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65583A04261B83BE00ECA9F9 /* UIKit+Extensions.swift */; };
|
65583A05261B83BE00ECA9F9 /* UIKit+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65583A04261B83BE00ECA9F9 /* UIKit+Extensions.swift */; };
|
||||||
6562C80725FFA6B100C85273 /* SeismicNetworkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */; };
|
6562C80725FFA6B100C85273 /* SeismicNetworkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */; };
|
||||||
6563DAA42AAF515F0072D309 /* BackgroundTaskIdentifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6563DAA32AAF515F0072D309 /* BackgroundTaskIdentifiable.swift */; };
|
6563DAA42AAF515F0072D309 /* BackgroundTaskIdentifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6563DAA32AAF515F0072D309 /* BackgroundTaskIdentifiable.swift */; };
|
||||||
|
6568C2D42E2A930500402F16 /* EQNBlurredCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */; };
|
||||||
656D138F2C2225560094F597 /* SubscriptionDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656D138E2C2225560094F597 /* SubscriptionDetailsViewController.swift */; };
|
656D138F2C2225560094F597 /* SubscriptionDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656D138E2C2225560094F597 /* SubscriptionDetailsViewController.swift */; };
|
||||||
656D13912C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656D13902C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift */; };
|
656D13912C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656D13902C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift */; };
|
||||||
656E02162C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656E02152C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift */; };
|
656E02162C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656E02152C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift */; };
|
||||||
@@ -49,6 +51,11 @@
|
|||||||
657415E02D70B6F800F54890 /* EQNMapAnnotationShakemap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657415DE2D70B6F700F54890 /* EQNMapAnnotationShakemap.swift */; };
|
657415E02D70B6F800F54890 /* EQNMapAnnotationShakemap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657415DE2D70B6F700F54890 /* EQNMapAnnotationShakemap.swift */; };
|
||||||
657747FD2D4D12A200213830 /* SeismicNetworkData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657747FC2D4D12A200213830 /* SeismicNetworkData.swift */; };
|
657747FD2D4D12A200213830 /* SeismicNetworkData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657747FC2D4D12A200213830 /* SeismicNetworkData.swift */; };
|
||||||
657747FF2D4D2BA200213830 /* SeismicNetworkScrollIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657747FE2D4D2BA100213830 /* SeismicNetworkScrollIndicatorView.swift */; };
|
657747FF2D4D2BA200213830 /* SeismicNetworkScrollIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657747FE2D4D2BA100213830 /* SeismicNetworkScrollIndicatorView.swift */; };
|
||||||
|
657CCF082E323AF700E91715 /* NotificationContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657CCF072E323AF700E91715 /* NotificationContentViewController.swift */; };
|
||||||
|
657CCF092E323BE500E91715 /* EQNRealtimePushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65EA58812A60360D0038EE9D /* EQNRealtimePushNotification.swift */; };
|
||||||
|
657CCF0A2E323DC600E91715 /* Foundation+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650247142A618D7F001AC512 /* Foundation+Extensions.swift */; };
|
||||||
|
657CCF0C2E32711D00E91715 /* MapSeismicWaveAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657CCF0B2E32711D00E91715 /* MapSeismicWaveAnimator.swift */; };
|
||||||
|
657CCF0D2E32711D00E91715 /* MapSeismicWaveAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657CCF0B2E32711D00E91715 /* MapSeismicWaveAnimator.swift */; };
|
||||||
6586971125F44C26009C0182 /* EQNBlurredCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */; };
|
6586971125F44C26009C0182 /* EQNBlurredCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */; };
|
||||||
658BAB7B25FE67930015C454 /* EQNBaseMapRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BAB7A25FE67930015C454 /* EQNBaseMapRepresentable.swift */; };
|
658BAB7B25FE67930015C454 /* EQNBaseMapRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BAB7A25FE67930015C454 /* EQNBaseMapRepresentable.swift */; };
|
||||||
658BC0292859A456009EECAA /* RealtimeAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */; };
|
658BC0292859A456009EECAA /* RealtimeAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */; };
|
||||||
@@ -224,7 +231,6 @@
|
|||||||
8CF05B57218C93BA0055012B /* EQNUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF05B56218C93BA0055012B /* EQNUtility.m */; };
|
8CF05B57218C93BA0055012B /* EQNUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF05B56218C93BA0055012B /* EQNUtility.m */; };
|
||||||
8CF12CD321DE49B600613AC5 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CF12CD221DE49B600613AC5 /* UserNotifications.framework */; };
|
8CF12CD321DE49B600613AC5 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CF12CD221DE49B600613AC5 /* UserNotifications.framework */; };
|
||||||
8CF12CD521DE49B600613AC5 /* UserNotificationsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CF12CD421DE49B600613AC5 /* UserNotificationsUI.framework */; };
|
8CF12CD521DE49B600613AC5 /* UserNotificationsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CF12CD421DE49B600613AC5 /* UserNotificationsUI.framework */; };
|
||||||
8CF12CD921DE49B600613AC5 /* NotificationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF12CD821DE49B600613AC5 /* NotificationViewController.m */; };
|
|
||||||
8CF12CDC21DE49B600613AC5 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8CF12CDA21DE49B600613AC5 /* MainInterface.storyboard */; };
|
8CF12CDC21DE49B600613AC5 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8CF12CDA21DE49B600613AC5 /* MainInterface.storyboard */; };
|
||||||
8CF12CE021DE49B600613AC5 /* EQNNotificationContent.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 8CF12CD121DE49B600613AC5 /* EQNNotificationContent.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
8CF12CE021DE49B600613AC5 /* EQNNotificationContent.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 8CF12CD121DE49B600613AC5 /* EQNNotificationContent.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
8CF4F4D8216D3A110057110B /* EQNAreaCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF4F4D7216D3A110057110B /* EQNAreaCheck.m */; };
|
8CF4F4D8216D3A110057110B /* EQNAreaCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF4F4D7216D3A110057110B /* EQNAreaCheck.m */; };
|
||||||
@@ -329,6 +335,7 @@
|
|||||||
65355FFE25F38D3300BB57D2 /* SegnalazioniMapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegnalazioniMapViewController.swift; sourceTree = "<group>"; };
|
65355FFE25F38D3300BB57D2 /* SegnalazioniMapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegnalazioniMapViewController.swift; sourceTree = "<group>"; };
|
||||||
653604E8262348FA00B2B651 /* EQNBaseMapFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseMapFilter.swift; sourceTree = "<group>"; };
|
653604E8262348FA00B2B651 /* EQNBaseMapFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseMapFilter.swift; sourceTree = "<group>"; };
|
||||||
653B791F2934B6DA00E8FFFB /* EQNNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EQNNotificationService.entitlements; sourceTree = "<group>"; };
|
653B791F2934B6DA00E8FFFB /* EQNNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EQNNotificationService.entitlements; sourceTree = "<group>"; };
|
||||||
|
653C5C2B2E295C5A00E25528 /* SeismicNetworkFilterRecapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkFilterRecapView.swift; sourceTree = "<group>"; };
|
||||||
653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNCustomAnnotationView.swift; sourceTree = "<group>"; };
|
653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNCustomAnnotationView.swift; sourceTree = "<group>"; };
|
||||||
653C67FB25F3D63500FE52AC /* EQNMapAnnotationUserReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNMapAnnotationUserReport.swift; sourceTree = "<group>"; };
|
653C67FB25F3D63500FE52AC /* EQNMapAnnotationUserReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNMapAnnotationUserReport.swift; sourceTree = "<group>"; };
|
||||||
653C680325F3DF8A00FE52AC /* EQNBaseMapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseMapViewController.swift; sourceTree = "<group>"; };
|
653C680325F3DF8A00FE52AC /* EQNBaseMapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseMapViewController.swift; sourceTree = "<group>"; };
|
||||||
@@ -356,6 +363,8 @@
|
|||||||
657415DE2D70B6F700F54890 /* EQNMapAnnotationShakemap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNMapAnnotationShakemap.swift; sourceTree = "<group>"; };
|
657415DE2D70B6F700F54890 /* EQNMapAnnotationShakemap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNMapAnnotationShakemap.swift; sourceTree = "<group>"; };
|
||||||
657747FC2D4D12A200213830 /* SeismicNetworkData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkData.swift; sourceTree = "<group>"; };
|
657747FC2D4D12A200213830 /* SeismicNetworkData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkData.swift; sourceTree = "<group>"; };
|
||||||
657747FE2D4D2BA100213830 /* SeismicNetworkScrollIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkScrollIndicatorView.swift; sourceTree = "<group>"; };
|
657747FE2D4D2BA100213830 /* SeismicNetworkScrollIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkScrollIndicatorView.swift; sourceTree = "<group>"; };
|
||||||
|
657CCF072E323AF700E91715 /* NotificationContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentViewController.swift; sourceTree = "<group>"; };
|
||||||
|
657CCF0B2E32711D00E91715 /* MapSeismicWaveAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapSeismicWaveAnimator.swift; sourceTree = "<group>"; };
|
||||||
6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBlurredCloseButton.swift; sourceTree = "<group>"; };
|
6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBlurredCloseButton.swift; sourceTree = "<group>"; };
|
||||||
658BAB7A25FE67930015C454 /* EQNBaseMapRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseMapRepresentable.swift; sourceTree = "<group>"; };
|
658BAB7A25FE67930015C454 /* EQNBaseMapRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseMapRepresentable.swift; sourceTree = "<group>"; };
|
||||||
658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealtimeAlertViewController.swift; sourceTree = "<group>"; };
|
658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealtimeAlertViewController.swift; sourceTree = "<group>"; };
|
||||||
@@ -554,8 +563,6 @@
|
|||||||
8CF12CD121DE49B600613AC5 /* EQNNotificationContent.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = EQNNotificationContent.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
8CF12CD121DE49B600613AC5 /* EQNNotificationContent.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = EQNNotificationContent.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
8CF12CD221DE49B600613AC5 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
|
8CF12CD221DE49B600613AC5 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
|
||||||
8CF12CD421DE49B600613AC5 /* UserNotificationsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotificationsUI.framework; path = System/Library/Frameworks/UserNotificationsUI.framework; sourceTree = SDKROOT; };
|
8CF12CD421DE49B600613AC5 /* UserNotificationsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotificationsUI.framework; path = System/Library/Frameworks/UserNotificationsUI.framework; sourceTree = SDKROOT; };
|
||||||
8CF12CD721DE49B600613AC5 /* NotificationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationViewController.h; sourceTree = "<group>"; };
|
|
||||||
8CF12CD821DE49B600613AC5 /* NotificationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationViewController.m; sourceTree = "<group>"; };
|
|
||||||
8CF12CDB21DE49B600613AC5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
8CF12CDB21DE49B600613AC5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||||
8CF12CDD21DE49B600613AC5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
8CF12CDD21DE49B600613AC5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
8CF4F4D6216D3A110057110B /* EQNAreaCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EQNAreaCheck.h; sourceTree = "<group>"; };
|
8CF4F4D6216D3A110057110B /* EQNAreaCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EQNAreaCheck.h; sourceTree = "<group>"; };
|
||||||
@@ -678,6 +685,7 @@
|
|||||||
children = (
|
children = (
|
||||||
658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */,
|
658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */,
|
||||||
658BC02A2859A4D3009EECAA /* RealtimeAlertView.swift */,
|
658BC02A2859A4D3009EECAA /* RealtimeAlertView.swift */,
|
||||||
|
657CCF0B2E32711D00E91715 /* MapSeismicWaveAnimator.swift */,
|
||||||
);
|
);
|
||||||
path = "Realtime Alert";
|
path = "Realtime Alert";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -913,8 +921,7 @@
|
|||||||
children = (
|
children = (
|
||||||
6557CBBC26078A1700962757 /* EQNNotificationContent.entitlements */,
|
6557CBBC26078A1700962757 /* EQNNotificationContent.entitlements */,
|
||||||
8C483CB621FDACD100259FD2 /* EQNNotificationContent-Bridging-Header.h */,
|
8C483CB621FDACD100259FD2 /* EQNNotificationContent-Bridging-Header.h */,
|
||||||
8CF12CD721DE49B600613AC5 /* NotificationViewController.h */,
|
657CCF072E323AF700E91715 /* NotificationContentViewController.swift */,
|
||||||
8CF12CD821DE49B600613AC5 /* NotificationViewController.m */,
|
|
||||||
8CF12CDA21DE49B600613AC5 /* MainInterface.storyboard */,
|
8CF12CDA21DE49B600613AC5 /* MainInterface.storyboard */,
|
||||||
8CF12CDD21DE49B600613AC5 /* Info.plist */,
|
8CF12CDD21DE49B600613AC5 /* Info.plist */,
|
||||||
);
|
);
|
||||||
@@ -941,6 +948,7 @@
|
|||||||
6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */,
|
6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */,
|
||||||
657747FC2D4D12A200213830 /* SeismicNetworkData.swift */,
|
657747FC2D4D12A200213830 /* SeismicNetworkData.swift */,
|
||||||
657747FE2D4D2BA100213830 /* SeismicNetworkScrollIndicatorView.swift */,
|
657747FE2D4D2BA100213830 /* SeismicNetworkScrollIndicatorView.swift */,
|
||||||
|
653C5C2B2E295C5A00E25528 /* SeismicNetworkFilterRecapView.swift */,
|
||||||
DC2814372519C56100C1AFF7 /* SeismicNetworksViewController.swift */,
|
DC2814372519C56100C1AFF7 /* SeismicNetworksViewController.swift */,
|
||||||
DCC76BD7251F56050005C4DC /* SeismicCardSettingsViewController.swift */,
|
DCC76BD7251F56050005C4DC /* SeismicCardSettingsViewController.swift */,
|
||||||
65DBFB4A25E29DD60041CBA6 /* SeismicNetworksMapDetailViewController.swift */,
|
65DBFB4A25E29DD60041CBA6 /* SeismicNetworksMapDetailViewController.swift */,
|
||||||
@@ -1656,6 +1664,7 @@
|
|||||||
65F9B4A02A8CC58200F13260 /* UpdateUserLocationTask.swift in Sources */,
|
65F9B4A02A8CC58200F13260 /* UpdateUserLocationTask.swift in Sources */,
|
||||||
8C4E34422152B5E8008B0D2A /* EQNRilevamento.m in Sources */,
|
8C4E34422152B5E8008B0D2A /* EQNRilevamento.m in Sources */,
|
||||||
8C7A3B66225A5EA40045B266 /* NSDictionary+EQNExtensions.m in Sources */,
|
8C7A3B66225A5EA40045B266 /* NSDictionary+EQNExtensions.m in Sources */,
|
||||||
|
653C5C2C2E295C5A00E25528 /* SeismicNetworkFilterRecapView.swift in Sources */,
|
||||||
65AB4A992C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift in Sources */,
|
65AB4A992C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift in Sources */,
|
||||||
8CF66053214C12DC009F4314 /* EQNMath.m in Sources */,
|
8CF66053214C12DC009F4314 /* EQNMath.m in Sources */,
|
||||||
DCF4A54524F8DB8300B17326 /* SettingDateTableViewCell.swift in Sources */,
|
DCF4A54524F8DB8300B17326 /* SettingDateTableViewCell.swift in Sources */,
|
||||||
@@ -1673,6 +1682,7 @@
|
|||||||
653C67E225F3CC2E00FE52AC /* EQNCustomAnnotationView.swift in Sources */,
|
653C67E225F3CC2E00FE52AC /* EQNCustomAnnotationView.swift in Sources */,
|
||||||
8CF4F4D8216D3A110057110B /* EQNAreaCheck.m in Sources */,
|
8CF4F4D8216D3A110057110B /* EQNAreaCheck.m in Sources */,
|
||||||
8C4E34452152B707008B0D2A /* EQNAccelerometroManager.m in Sources */,
|
8C4E34452152B707008B0D2A /* EQNAccelerometroManager.m in Sources */,
|
||||||
|
657CCF0C2E32711D00E91715 /* MapSeismicWaveAnimator.swift in Sources */,
|
||||||
65D409942619BA34008CF356 /* SegnalazioniSendReportCell.swift in Sources */,
|
65D409942619BA34008CF356 /* SegnalazioniSendReportCell.swift in Sources */,
|
||||||
65F9B49C2A8CA22800F13260 /* BackgroundTaskManager.swift in Sources */,
|
65F9B49C2A8CA22800F13260 /* BackgroundTaskManager.swift in Sources */,
|
||||||
656D13912C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift in Sources */,
|
656D13912C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift in Sources */,
|
||||||
@@ -1704,17 +1714,21 @@
|
|||||||
8C465D9F21F7BE0600F04673 /* Assets.xcassets in Sources */,
|
8C465D9F21F7BE0600F04673 /* Assets.xcassets in Sources */,
|
||||||
65D9938C2922647800F2B0EB /* AppTheme.swift in Sources */,
|
65D9938C2922647800F2B0EB /* AppTheme.swift in Sources */,
|
||||||
DC0AE1B92538204100111307 /* EQNSegnalazione.m in Sources */,
|
DC0AE1B92538204100111307 /* EQNSegnalazione.m in Sources */,
|
||||||
|
657CCF092E323BE500E91715 /* EQNRealtimePushNotification.swift in Sources */,
|
||||||
|
657CCF082E323AF700E91715 /* NotificationContentViewController.swift in Sources */,
|
||||||
654D18DE25F943E200BB6DB0 /* EQNMapAnnotationUserReport.swift in Sources */,
|
654D18DE25F943E200BB6DB0 /* EQNMapAnnotationUserReport.swift in Sources */,
|
||||||
654D18D625F9420500BB6DB0 /* EQNMapAnnotationPastquake.swift in Sources */,
|
654D18D625F9420500BB6DB0 /* EQNMapAnnotationPastquake.swift in Sources */,
|
||||||
65D507DB2A852274005BDC57 /* EQNUserData.swift in Sources */,
|
65D507DB2A852274005BDC57 /* EQNUserData.swift in Sources */,
|
||||||
|
657CCF0A2E323DC600E91715 /* Foundation+Extensions.swift in Sources */,
|
||||||
DC0AE1B52538202300111307 /* EQNUtility.m in Sources */,
|
DC0AE1B52538202300111307 /* EQNUtility.m in Sources */,
|
||||||
65D507DC2A85227F005BDC57 /* Constants.swift in Sources */,
|
65D507DC2A85227F005BDC57 /* Constants.swift in Sources */,
|
||||||
|
657CCF0D2E32711D00E91715 /* MapSeismicWaveAnimator.swift in Sources */,
|
||||||
653C67E625F3CC8400FE52AC /* EQNCustomAnnotationView.swift in Sources */,
|
653C67E625F3CC8400FE52AC /* EQNCustomAnnotationView.swift in Sources */,
|
||||||
654D18DA25F9424700BB6DB0 /* EQNUtility+Extensions.swift in Sources */,
|
654D18DA25F9424700BB6DB0 /* EQNUtility+Extensions.swift in Sources */,
|
||||||
DC0AE1BA2538204100111307 /* EQNPastquakes.m in Sources */,
|
DC0AE1BA2538204100111307 /* EQNPastquakes.m in Sources */,
|
||||||
|
6568C2D42E2A930500402F16 /* EQNBlurredCloseButton.swift in Sources */,
|
||||||
65D9938A29219DEC00F2B0EB /* UIKit+Extensions.swift in Sources */,
|
65D9938A29219DEC00F2B0EB /* UIKit+Extensions.swift in Sources */,
|
||||||
6514FF6C2D720CBE000A7BD0 /* MapPinStyle.swift in Sources */,
|
6514FF6C2D720CBE000A7BD0 /* MapPinStyle.swift in Sources */,
|
||||||
8CF12CD921DE49B600613AC5 /* NotificationViewController.m in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -1829,7 +1843,6 @@
|
|||||||
INFOPLIST_FILE = EQNNotificationService/Info.plist;
|
INFOPLIST_FILE = EQNNotificationService/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = EQNNotificationService;
|
INFOPLIST_KEY_CFBundleDisplayName = EQNNotificationService;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Earthquake Network. All rights reserved.";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Earthquake Network. All rights reserved.";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1847,7 +1860,6 @@
|
|||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -1867,7 +1879,6 @@
|
|||||||
INFOPLIST_FILE = EQNNotificationService/Info.plist;
|
INFOPLIST_FILE = EQNNotificationService/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = EQNNotificationService;
|
INFOPLIST_KEY_CFBundleDisplayName = EQNNotificationService;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Earthquake Network. All rights reserved.";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Earthquake Network. All rights reserved.";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1883,7 +1894,6 @@
|
|||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -1923,7 +1933,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 154;
|
CURRENT_PROJECT_VERSION = 159;
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
@@ -1943,8 +1953,8 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MARKETING_VERSION = 5.10.0;
|
MARKETING_VERSION = 5.11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@@ -1987,7 +1997,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 154;
|
CURRENT_PROJECT_VERSION = 159;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
@@ -2001,8 +2011,8 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MARKETING_VERSION = 5.10.0;
|
MARKETING_VERSION = 5.11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
@@ -2025,7 +2035,6 @@
|
|||||||
ENABLE_MODULE_VERIFIER = YES;
|
ENABLE_MODULE_VERIFIER = YES;
|
||||||
GCC_PREFIX_HEADER = "Earthquake Network/Earthquake Network-Prefix.pch";
|
GCC_PREFIX_HEADER = "Earthquake Network/Earthquake Network-Prefix.pch";
|
||||||
INFOPLIST_FILE = "Earthquake Network/Info.plist";
|
INFOPLIST_FILE = "Earthquake Network/Info.plist";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -2094,7 +2103,6 @@
|
|||||||
SWIFT_OBJC_BRIDGING_HEADER = "Earthquake Network/Earthquake Network-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Earthquake Network/Earthquake Network-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -2112,7 +2120,6 @@
|
|||||||
ENABLE_MODULE_VERIFIER = YES;
|
ENABLE_MODULE_VERIFIER = YES;
|
||||||
GCC_PREFIX_HEADER = "Earthquake Network/Earthquake Network-Prefix.pch";
|
GCC_PREFIX_HEADER = "Earthquake Network/Earthquake Network-Prefix.pch";
|
||||||
INFOPLIST_FILE = "Earthquake Network/Info.plist";
|
INFOPLIST_FILE = "Earthquake Network/Info.plist";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -2180,7 +2187,6 @@
|
|||||||
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork - AppStore";
|
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork - AppStore";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Earthquake Network/Earthquake Network-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Earthquake Network/Earthquake Network-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -2200,7 +2206,6 @@
|
|||||||
"NOTIFICATION_CONTENT=1",
|
"NOTIFICATION_CONTENT=1",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = EQNNotificationContent/Info.plist;
|
INFOPLIST_FILE = EQNNotificationContent/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -2214,7 +2219,6 @@
|
|||||||
SWIFT_OBJC_BRIDGING_HEADER = "EQNNotificationContent/EQNNotificationContent-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "EQNNotificationContent/EQNNotificationContent-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -2232,7 +2236,6 @@
|
|||||||
"NOTIFICATION_CONTENT=1",
|
"NOTIFICATION_CONTENT=1",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = EQNNotificationContent/Info.plist;
|
INFOPLIST_FILE = EQNNotificationContent/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -2245,7 +2248,6 @@
|
|||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "EQNNotificationContent/EQNNotificationContent-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "EQNNotificationContent/EQNNotificationContent-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -2296,7 +2298,7 @@
|
|||||||
repositoryURL = "https://github.com/andreabusi-it/Shogun.git";
|
repositoryURL = "https://github.com/andreabusi-it/Shogun.git";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = upToNextMajorVersion;
|
kind = upToNextMajorVersion;
|
||||||
minimumVersion = 1.0.0;
|
minimumVersion = 2.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
65B16E1C2BDFA88D0020527E /* XCRemoteSwiftPackageReference "Solar" */ = {
|
65B16E1C2BDFA88D0020527E /* XCRemoteSwiftPackageReference "Solar" */ = {
|
||||||
|
|||||||
+18
-9
@@ -42,8 +42,17 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/firebase/firebase-ios-sdk.git",
|
"location" : "https://github.com/firebase/firebase-ios-sdk.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "fbd463894af94d90eb4d6a4e54080459a8179519",
|
"revision" : "fdc352fabaf5916e7faa1f96ad02b1957e93e5a5",
|
||||||
"version" : "11.12.0"
|
"version" : "11.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "428d8bb138e00f9a3f4f61cc6cd8863607524f65",
|
||||||
|
"version" : "2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -51,8 +60,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "f7460ea630bddf172115c28493ae8b3798d95ce3",
|
"revision" : "45ce435e9406d3c674dd249a042b932bee006f60",
|
||||||
"version" : "11.12.0"
|
"version" : "11.15.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -69,8 +78,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/google/GoogleUtilities.git",
|
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "53156c7ec267db846e6b64c9f4c4e31ba4cf75eb",
|
"revision" : "60da361632d0de02786f709bdc0c4df340f7613e",
|
||||||
"version" : "8.0.2"
|
"version" : "8.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -130,10 +139,10 @@
|
|||||||
{
|
{
|
||||||
"identity" : "shogun",
|
"identity" : "shogun",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/andreabusi-it/Shogun",
|
"location" : "https://github.com/andreabusi-it/Shogun.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "ad890190d6be90f7712c2e56a38ef0937d9f8c1a",
|
"revision" : "809b56a43fadac72db9963a21c74688af7ef51b7",
|
||||||
"version" : "1.8.0"
|
"version" : "2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -207,20 +207,16 @@
|
|||||||
|
|
||||||
- (void)configureAppTracking
|
- (void)configureAppTracking
|
||||||
{
|
{
|
||||||
if (@available(iOS 14, *)) {
|
// add a delay otherwise the alert will not be displayed
|
||||||
// add a delay otherwise the alert will not be displayed
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
|
||||||
if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
|
FBSDKSettings.sharedSettings.isAdvertiserTrackingEnabled = YES;
|
||||||
FBSDKSettings.sharedSettings.isAdvertiserTrackingEnabled = YES;
|
} else {
|
||||||
} else {
|
FBSDKSettings.sharedSettings.isAdvertiserTrackingEnabled = NO;
|
||||||
FBSDKSettings.sharedSettings.isAdvertiserTrackingEnabled = NO;
|
}
|
||||||
}
|
}];
|
||||||
}];
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
FBSDKSettings.sharedSettings.isAdvertiserTrackingEnabled = YES;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)configureFirebase
|
- (void)configureFirebase
|
||||||
|
|||||||
@@ -92,10 +92,8 @@ class SubscriptionsViewController: UITableViewController {
|
|||||||
tableView.separatorStyle = .none
|
tableView.separatorStyle = .none
|
||||||
tableView.backgroundColor = .systemGroupedBackground
|
tableView.backgroundColor = .systemGroupedBackground
|
||||||
tableView.contentInset = EQNBaseContainerTableViewCell.EdgeInsets
|
tableView.contentInset = EQNBaseContainerTableViewCell.EdgeInsets
|
||||||
if #available(iOS 15.0, *) {
|
// remove extra padding on top of each section header
|
||||||
// remove extra padding on top of each section header
|
tableView.sectionHeaderTopPadding = 0.0
|
||||||
tableView.sectionHeaderTopPadding = 0.0
|
|
||||||
}
|
|
||||||
tableView.registerCell(for: SubscriptionsActiveTableViewCell.self)
|
tableView.registerCell(for: SubscriptionsActiveTableViewCell.self)
|
||||||
tableView.registerCell(for: SubscriptionsDescriptionTableViewCell.self)
|
tableView.registerCell(for: SubscriptionsDescriptionTableViewCell.self)
|
||||||
tableView.registerCell(for: SubscriptionProductTableViewCell.self)
|
tableView.registerCell(for: SubscriptionProductTableViewCell.self)
|
||||||
|
|||||||
@@ -0,0 +1,187 @@
|
|||||||
|
//
|
||||||
|
// MapSeismicWaveAnimator.swift
|
||||||
|
// Earthquake Network
|
||||||
|
//
|
||||||
|
// Created by Andrea Busi on 24/07/25.
|
||||||
|
// Copyright © 2025 Earthquake Network. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import MapKit
|
||||||
|
|
||||||
|
|
||||||
|
class MapSeismicWaveAnimator {
|
||||||
|
|
||||||
|
private weak var mapView: MKMapView?
|
||||||
|
private weak var waveTimeLabel: UILabel?
|
||||||
|
|
||||||
|
private let OverlayCircleId = "wave_animation"
|
||||||
|
|
||||||
|
/// Alert to display
|
||||||
|
private let realtimeAlert: EQNRealtimePushNotification
|
||||||
|
/// Timer to constantly update countdown label
|
||||||
|
private var countdownTimer: Timer?
|
||||||
|
/// Timer to simulate animation for the wave
|
||||||
|
private var waveAnimationTimer: Timer?
|
||||||
|
/// Refresh time for wave animation
|
||||||
|
private let waveAnimationRefreshRate = 0.1
|
||||||
|
/// Current radius of the wave animation on the map
|
||||||
|
private var waveAnimationCurrentRadius: CLLocationDistance = 0
|
||||||
|
private var waveAnimationVelocity: Double = 1_000
|
||||||
|
|
||||||
|
// MARK: - Init
|
||||||
|
|
||||||
|
init(
|
||||||
|
realtimeAlert: EQNRealtimePushNotification,
|
||||||
|
mapView: MKMapView,
|
||||||
|
waveTimeLabel: UILabel
|
||||||
|
) {
|
||||||
|
self.realtimeAlert = realtimeAlert
|
||||||
|
self.mapView = mapView
|
||||||
|
self.waveTimeLabel = waveTimeLabel
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setup() {
|
||||||
|
self.waveAnimationCurrentRadius = currentWavePosition()
|
||||||
|
self.waveAnimationVelocity = evaluateWaveAnimationVelocity()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
startCountdown()
|
||||||
|
startWaveAnimation()
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() {
|
||||||
|
stopCountdown()
|
||||||
|
stopWaveAnimation()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Wave
|
||||||
|
|
||||||
|
private func startCountdown() {
|
||||||
|
// show countdown only if time is less than 300 seconds
|
||||||
|
if realtimeAlert.currentCountdown() < 300 {
|
||||||
|
// start a timer for the countdown label
|
||||||
|
waveTimeLabel?.isHidden = false
|
||||||
|
countdownTimer = Timer.scheduledTimer(
|
||||||
|
timeInterval: 1.0,
|
||||||
|
target: self,
|
||||||
|
selector: #selector(countdownTimerFired(_:)),
|
||||||
|
userInfo: nil,
|
||||||
|
repeats: true
|
||||||
|
)
|
||||||
|
countdownTimer?.fire()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func startWaveAnimation() {
|
||||||
|
waveAnimationTimer = Timer.scheduledTimer(
|
||||||
|
timeInterval: waveAnimationRefreshRate,
|
||||||
|
target: self,
|
||||||
|
selector: #selector(mapWaveAnimationFired(_:)),
|
||||||
|
userInfo: nil,
|
||||||
|
repeats: true
|
||||||
|
)
|
||||||
|
waveAnimationTimer?.fire()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func stopCountdown() {
|
||||||
|
countdownTimer?.invalidate()
|
||||||
|
countdownTimer = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func stopWaveAnimation() {
|
||||||
|
waveAnimationTimer?.invalidate()
|
||||||
|
waveAnimationTimer = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Timer
|
||||||
|
|
||||||
|
@objc private func countdownTimerFired(_ sender: Timer) {
|
||||||
|
let countdown = realtimeAlert.currentCountdown()
|
||||||
|
waveTimeLabel?.text = String.localizedStringWithFormat(NSLocalizedString("alert_wave", comment: ""), countdown)
|
||||||
|
waveTimeLabel?.textColor = waveTimeTextColor(for: countdown)
|
||||||
|
|
||||||
|
if countdown <= 0 {
|
||||||
|
// stop the countdown
|
||||||
|
stopCountdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func mapWaveAnimationFired(_ sender: Timer) {
|
||||||
|
waveAnimationCurrentRadius += waveAnimationVelocity
|
||||||
|
addMapCircle(center: realtimeAlert.coordinate.coordinate, radius: waveAnimationCurrentRadius)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
|
|
||||||
|
/// Evaluate current position for the wave
|
||||||
|
/// Used to define initial position for the wave circle
|
||||||
|
/// - Returns: Distance of the wave from the original earthquake point
|
||||||
|
private func currentWavePosition() -> Double {
|
||||||
|
// distanza tra utente e terremoto
|
||||||
|
let distance = realtimeAlert.distanceFromUser()
|
||||||
|
|
||||||
|
// calcoliamo la distanza rimanente da mostrare, perchè la schermata potrebbe anche essere aperta in ritardo
|
||||||
|
let remainingDistance = realtimeAlert.waveSpeed * Double(realtimeAlert.currentCountdown())
|
||||||
|
return distance - remainingDistance
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Evaluate wave velocity based on push notification data
|
||||||
|
/// - Returns: Wave velocity, used for animation
|
||||||
|
private func evaluateWaveAnimationVelocity() -> Double {
|
||||||
|
let velocity = realtimeAlert.waveSpeed
|
||||||
|
return velocity * waveAnimationRefreshRate
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the text color based on impact countdown
|
||||||
|
private func waveTimeTextColor(for countdown: Int) -> UIColor {
|
||||||
|
switch countdown {
|
||||||
|
case _ where countdown > 15:
|
||||||
|
return UIColor(red: 255.0/255.0, green: 140.0/255.0, blue: 0.0, alpha: 1.0)
|
||||||
|
case _ where countdown > 5:
|
||||||
|
return UIColor(red: 255.0/255.0, green: 100.0/255.0, blue: 0.0, alpha: 1.0)
|
||||||
|
default:
|
||||||
|
return UIColor(red: 255.0/255.0, green: 0.0/255.0, blue: 0.0, alpha: 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Map management
|
||||||
|
|
||||||
|
func addMapCircle(
|
||||||
|
center: CLLocationCoordinate2D,
|
||||||
|
radius: CLLocationDistance
|
||||||
|
) {
|
||||||
|
guard let mapView else { return }
|
||||||
|
|
||||||
|
// remove any other existing overlays
|
||||||
|
let overlays = mapView.overlays.filter { $0.title == OverlayCircleId }
|
||||||
|
mapView.removeOverlays(overlays)
|
||||||
|
|
||||||
|
// add new overlay
|
||||||
|
let circle = MKCircle(center: center, radius: radius)
|
||||||
|
circle.title = OverlayCircleId
|
||||||
|
mapView.addOverlay(circle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOverlayRenderer(for overlay: MKOverlay) -> MKOverlayRenderer? {
|
||||||
|
switch overlay {
|
||||||
|
case let circle as MKCircle where overlay.title == OverlayCircleId:
|
||||||
|
let circleRenderer = MKCircleRenderer(overlay: circle)
|
||||||
|
circleRenderer.strokeColor = AppTheme.Colors.red
|
||||||
|
circleRenderer.fillColor = AppTheme.Colors.red.withAlphaComponent(0.2)
|
||||||
|
circleRenderer.lineWidth = 3.0
|
||||||
|
return circleRenderer
|
||||||
|
case let polyline as MKPolyline:
|
||||||
|
let polylineRenderer = MKPolylineRenderer(polyline: polyline)
|
||||||
|
polylineRenderer.strokeColor = .blue
|
||||||
|
polylineRenderer.lineWidth = 2.0
|
||||||
|
return polylineRenderer
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,7 +102,6 @@ class RealtimeAlertView: UIView {
|
|||||||
lazy var mapView: MKMapView = {
|
lazy var mapView: MKMapView = {
|
||||||
let map = MKMapView()
|
let map = MKMapView()
|
||||||
map.translatesAutoresizingMaskIntoConstraints = false
|
map.translatesAutoresizingMaskIntoConstraints = false
|
||||||
map.delegate = self
|
|
||||||
map.register(EQNCustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SingleLineIdentifier)
|
map.register(EQNCustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SingleLineIdentifier)
|
||||||
map.showsUserLocation = true
|
map.showsUserLocation = true
|
||||||
return map
|
return map
|
||||||
@@ -160,28 +159,13 @@ class RealtimeAlertView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Public
|
// MARK: - Public
|
||||||
|
|
||||||
func addMapCircle(
|
func addMapLine(
|
||||||
center: CLLocationCoordinate2D,
|
coordinates: [CLLocationCoordinate2D]
|
||||||
radius: CLLocationDistance,
|
|
||||||
overlayId: String
|
|
||||||
) {
|
) {
|
||||||
// remove any other existing overlays
|
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
|
||||||
let overlays = mapView.overlays.filter { $0.title == overlayId }
|
mapView.addOverlay(polyline)
|
||||||
mapView.removeOverlays(overlays)
|
|
||||||
|
|
||||||
// add new overlay
|
|
||||||
let circle = MKCircle(center: center, radius: radius)
|
|
||||||
circle.title = overlayId
|
|
||||||
mapView.addOverlay(circle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addMapLine(
|
|
||||||
coordinates: [CLLocationCoordinate2D]
|
|
||||||
) {
|
|
||||||
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
|
|
||||||
mapView.addOverlay(polyline)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addMapAnnotation(
|
func addMapAnnotation(
|
||||||
title: String = "",
|
title: String = "",
|
||||||
@@ -192,35 +176,3 @@ class RealtimeAlertView: UIView {
|
|||||||
mapView.addAnnotation(annotation)
|
mapView.addAnnotation(annotation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RealtimeAlertView: MKMapViewDelegate {
|
|
||||||
|
|
||||||
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
|
|
||||||
switch overlay {
|
|
||||||
case let circle as MKCircle:
|
|
||||||
let circleRenderer = MKCircleRenderer(overlay: circle)
|
|
||||||
circleRenderer.strokeColor = AppTheme.Colors.red
|
|
||||||
circleRenderer.fillColor = AppTheme.Colors.red.withAlphaComponent(0.2)
|
|
||||||
circleRenderer.lineWidth = 3.0
|
|
||||||
return circleRenderer
|
|
||||||
case let polyline as MKPolyline:
|
|
||||||
let polylineRenderer = MKPolylineRenderer(polyline: polyline)
|
|
||||||
polylineRenderer.strokeColor = .blue
|
|
||||||
polylineRenderer.lineWidth = 2.0
|
|
||||||
return polylineRenderer
|
|
||||||
default:
|
|
||||||
return MKOverlayRenderer(overlay: overlay)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
|
|
||||||
guard let annotation = annotation as? EQNMapAnnotationPastquake else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: EQNCustomAnnotationView.SingleLineIdentifier, for: annotation) as! EQNCustomAnnotationView
|
|
||||||
annotationView.image = annotation.image
|
|
||||||
annotationView.title = annotation.title
|
|
||||||
return annotationView
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+27
-85
@@ -10,7 +10,7 @@ import UIKit
|
|||||||
import MapKit
|
import MapKit
|
||||||
|
|
||||||
|
|
||||||
class RealtimeAlertViewController: UIViewController, MKMapViewDelegate {
|
class RealtimeAlertViewController: UIViewController {
|
||||||
|
|
||||||
@objc var onClose: () -> Void = {}
|
@objc var onClose: () -> Void = {}
|
||||||
|
|
||||||
@@ -20,17 +20,17 @@ class RealtimeAlertViewController: UIViewController, MKMapViewDelegate {
|
|||||||
private var notificationView: RealtimeAlertView {
|
private var notificationView: RealtimeAlertView {
|
||||||
containerView.alertView
|
containerView.alertView
|
||||||
}
|
}
|
||||||
|
/// Manage the wave animation on the map and the countdown label
|
||||||
|
private lazy var animator: MapSeismicWaveAnimator = {
|
||||||
|
let animator = MapSeismicWaveAnimator(
|
||||||
|
realtimeAlert: realtimeAlert,
|
||||||
|
mapView: notificationView.mapView,
|
||||||
|
waveTimeLabel: notificationView.waveTimeLabel
|
||||||
|
)
|
||||||
|
return animator
|
||||||
|
}()
|
||||||
/// Alert to display
|
/// Alert to display
|
||||||
private let realtimeAlert: EQNRealtimePushNotification
|
private let realtimeAlert: EQNRealtimePushNotification
|
||||||
/// Timer to constantly update countdown label
|
|
||||||
private var countdownTimer: Timer?
|
|
||||||
/// Refresh time for wave animation
|
|
||||||
private let waveAnimationRefreshRate = 0.1
|
|
||||||
/// Current radius of the wave animation on the map
|
|
||||||
private var waveAnimationCurrentRadius: CLLocationDistance = 0
|
|
||||||
private var waveAnimationVelocity: Double = 1_000
|
|
||||||
/// Timer to simulate animation for the wave
|
|
||||||
private var waveAnimationTimer: Timer?
|
|
||||||
|
|
||||||
// MARK: - Init
|
// MARK: - Init
|
||||||
|
|
||||||
@@ -38,9 +38,6 @@ class RealtimeAlertViewController: UIViewController, MKMapViewDelegate {
|
|||||||
init(notification: EQNRealtimePushNotification) {
|
init(notification: EQNRealtimePushNotification) {
|
||||||
self.realtimeAlert = notification
|
self.realtimeAlert = notification
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
self.waveAnimationCurrentRadius = currentWavePosition()
|
|
||||||
self.waveAnimationVelocity = evaluateWaveAnimationVelocity()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@@ -64,8 +61,7 @@ class RealtimeAlertViewController: UIViewController, MKMapViewDelegate {
|
|||||||
configureUI()
|
configureUI()
|
||||||
updateUI()
|
updateUI()
|
||||||
|
|
||||||
startCountdown()
|
animator.start()
|
||||||
startWaveAnimation()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
@@ -77,6 +73,8 @@ class RealtimeAlertViewController: UIViewController, MKMapViewDelegate {
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func configureUI() {
|
private func configureUI() {
|
||||||
|
notificationView.mapView.delegate = self
|
||||||
|
|
||||||
notificationView.closeButton.addTarget(self, action: #selector(onTapClose(_:)), for: .touchUpInside)
|
notificationView.closeButton.addTarget(self, action: #selector(onTapClose(_:)), for: .touchUpInside)
|
||||||
|
|
||||||
// configure color for animation
|
// configure color for animation
|
||||||
@@ -104,93 +102,37 @@ class RealtimeAlertViewController: UIViewController, MKMapViewDelegate {
|
|||||||
// aggiungiamo annotation con epicentro sisma
|
// aggiungiamo annotation con epicentro sisma
|
||||||
notificationView.addMapAnnotation(center: realtimeAlert.coordinate.coordinate, intensity: realtimeAlert.intensity)
|
notificationView.addMapAnnotation(center: realtimeAlert.coordinate.coordinate, intensity: realtimeAlert.intensity)
|
||||||
|
|
||||||
// simuliamo animazione dell'onda sismica
|
|
||||||
notificationView.addMapCircle(center: realtimeAlert.coordinate.coordinate, radius: waveAnimationCurrentRadius, overlayId: "wave_animation")
|
|
||||||
|
|
||||||
// aggiungiamo un segmento tra la posizione del sisma e quella dell'utente
|
// aggiungiamo un segmento tra la posizione del sisma e quella dell'utente
|
||||||
if let lastPosition = EQNUser.default().lastPosition {
|
if let lastPosition = EQNUser.default().lastPosition {
|
||||||
notificationView.addMapLine(coordinates: [realtimeAlert.coordinate.coordinate, lastPosition.coordinate])
|
notificationView.addMapLine(coordinates: [realtimeAlert.coordinate.coordinate, lastPosition.coordinate])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startCountdown() {
|
|
||||||
// show countdown only if time is less than 300 seconds
|
|
||||||
if realtimeAlert.currentCountdown() < 300 {
|
|
||||||
// start a timer for the countdown label
|
|
||||||
notificationView.waveTimeLabel.isHidden = false
|
|
||||||
countdownTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(countdownTimerFired(_:)), userInfo: nil, repeats: true)
|
|
||||||
countdownTimer?.fire()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startWaveAnimation() {
|
|
||||||
waveAnimationTimer = Timer.scheduledTimer(timeInterval: waveAnimationRefreshRate, target: self, selector: #selector(mapWaveAnimationFired(_:)), userInfo: nil, repeats: true)
|
|
||||||
waveAnimationTimer?.fire()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Action
|
// MARK: - Action
|
||||||
|
|
||||||
@objc private func onTapClose(_ sender: UIButton) {
|
@objc private func onTapClose(_ sender: UIButton) {
|
||||||
// invalidiamo i timer, altri
|
// stoppiamo animazione e countdown
|
||||||
countdownTimer?.invalidate()
|
animator.stop()
|
||||||
countdownTimer = nil
|
|
||||||
waveAnimationTimer?.invalidate()
|
|
||||||
waveAnimationTimer = nil
|
|
||||||
|
|
||||||
onClose()
|
onClose()
|
||||||
dismiss(animated: true)
|
dismiss(animated: true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RealtimeAlertViewController: MKMapViewDelegate {
|
||||||
|
|
||||||
// MARK: - Timer
|
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
|
||||||
|
animator.getOverlayRenderer(for: overlay) ?? MKOverlayRenderer(overlay: overlay)
|
||||||
|
}
|
||||||
|
|
||||||
@objc private func countdownTimerFired(_ sender: Timer) {
|
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
|
||||||
let countdown = realtimeAlert.currentCountdown()
|
guard let annotation = annotation as? EQNMapAnnotationPastquake else {
|
||||||
notificationView.waveTimeLabel.text = String.localizedStringWithFormat(NSLocalizedString("alert_wave", comment: ""), countdown)
|
return nil
|
||||||
notificationView.waveTimeLabel.textColor = waveTimeTextColor(for: countdown)
|
|
||||||
|
|
||||||
if countdown <= 0 {
|
|
||||||
// stop the countdown
|
|
||||||
countdownTimer?.invalidate()
|
|
||||||
countdownTimer = nil
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func mapWaveAnimationFired(_ sender: Timer) {
|
|
||||||
waveAnimationCurrentRadius += waveAnimationVelocity
|
|
||||||
notificationView.addMapCircle(center: realtimeAlert.coordinate.coordinate, radius: waveAnimationCurrentRadius, overlayId: "wave_animation")
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Helpers
|
|
||||||
|
|
||||||
/// Evaluate current position for the wave
|
|
||||||
/// Used to define initial position for the wave circle
|
|
||||||
/// - Returns: Distance of the wave from the original earthquake point
|
|
||||||
private func currentWavePosition() -> Double {
|
|
||||||
// distanza tra utente e terremoto
|
|
||||||
let distance = realtimeAlert.distanceFromUser()
|
|
||||||
|
|
||||||
// calcoliamo la distanza rimanente da mostrare, perchè la schermata potrebbe anche essere aperta in ritardo
|
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: EQNCustomAnnotationView.SingleLineIdentifier, for: annotation) as! EQNCustomAnnotationView
|
||||||
let remainingDistance = realtimeAlert.waveSpeed * Double(realtimeAlert.currentCountdown())
|
annotationView.image = annotation.image
|
||||||
return distance - remainingDistance
|
annotationView.title = annotation.title
|
||||||
}
|
return annotationView
|
||||||
|
|
||||||
/// Evaluate wave velocity based on push notification data
|
|
||||||
/// - Returns: Wave velocity, used for animation
|
|
||||||
private func evaluateWaveAnimationVelocity() -> Double {
|
|
||||||
let velocity = realtimeAlert.waveSpeed
|
|
||||||
return velocity * waveAnimationRefreshRate
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the text color based on impact countdown
|
|
||||||
private func waveTimeTextColor(for countdown: Int) -> UIColor {
|
|
||||||
switch countdown {
|
|
||||||
case _ where countdown > 15:
|
|
||||||
return UIColor(red: 255.0/255.0, green: 140.0/255.0, blue: 0.0, alpha: 1.0)
|
|
||||||
case _ where countdown > 5:
|
|
||||||
return UIColor(red: 255.0/255.0, green: 100.0/255.0, blue: 0.0, alpha: 1.0)
|
|
||||||
default:
|
|
||||||
return UIColor(red: 255.0/255.0, green: 0.0/255.0, blue: 0.0, alpha: 1.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -45,7 +45,7 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
|
|||||||
]
|
]
|
||||||
|
|
||||||
private let initialFilterType = EQNSeismic.shared.filterOption
|
private let initialFilterType = EQNSeismic.shared.filterOption
|
||||||
private var currentFilterType = EQNSeismic.FilterType.inRadius
|
private(set) var currentFilterType = EQNSeismic.FilterType.inRadius
|
||||||
private var currentMaximumDistance = EQNData.DefaultFilterRadius
|
private var currentMaximumDistance = EQNData.DefaultFilterRadius
|
||||||
private var currentMinimumMagnitude = EQNData.DefaultFilterMagnitude
|
private var currentMinimumMagnitude = EQNData.DefaultFilterMagnitude
|
||||||
|
|
||||||
|
|||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
//
|
||||||
|
// SeismicNetworkFilterRecapView.swift
|
||||||
|
// Earthquake Network
|
||||||
|
//
|
||||||
|
// Created by Andrea Busi on 17/07/25.
|
||||||
|
// Copyright © 2025 Earthquake Network. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Shogun
|
||||||
|
|
||||||
|
|
||||||
|
struct SeismicNetworkFilterRecapView: View {
|
||||||
|
class Model: ObservableObject {
|
||||||
|
@Published var filter = EQNSeismic.shared.filterOption
|
||||||
|
@Published var sort = EQNSeismic.shared.sort
|
||||||
|
}
|
||||||
|
|
||||||
|
@ObservedObject private var model: Model
|
||||||
|
private let onSort: (_ sort: EQNSeismic.Sort) -> Void
|
||||||
|
private let onMainFilter: () -> Void
|
||||||
|
private let onMap: () -> Void
|
||||||
|
|
||||||
|
// MARK: - Init
|
||||||
|
|
||||||
|
init(
|
||||||
|
model: Model,
|
||||||
|
onSort: @escaping (_ sort: EQNSeismic.Sort) -> Void,
|
||||||
|
onMainFilter: @escaping () -> Void,
|
||||||
|
onMap: @escaping () -> Void
|
||||||
|
) {
|
||||||
|
self.model = model
|
||||||
|
self.onSort = onSort
|
||||||
|
self.onMainFilter = onMainFilter
|
||||||
|
self.onMap = onMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - View
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
RoundedButton(
|
||||||
|
systemName: sortIcon,
|
||||||
|
tintColor: tintColor,
|
||||||
|
action: {
|
||||||
|
model.sort.advance()
|
||||||
|
onSort(model.sort)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Button {
|
||||||
|
onMainFilter()
|
||||||
|
} label: {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "magnifyingglass")
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(height: 12)
|
||||||
|
|
||||||
|
Text(filterTitle)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
.overlay {
|
||||||
|
Capsule().stroke(AppTheme.Colors.gray.color, lineWidth: 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.font(.caption)
|
||||||
|
.tint(tintColor)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
RoundedButton(
|
||||||
|
systemName: "globe",
|
||||||
|
tintColor: tintColor,
|
||||||
|
action: onMap
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.background(Color.clear)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var tintColor: Color {
|
||||||
|
Color.blue
|
||||||
|
//AppTheme.Colors.lightBlue.color
|
||||||
|
}
|
||||||
|
|
||||||
|
private var filterTitle: String {
|
||||||
|
switch model.filter {
|
||||||
|
case .inRadius: "filter_area".localized
|
||||||
|
case .positionRelevant: "filter_relevant".localized
|
||||||
|
case .worldWide: "filter_all".localized
|
||||||
|
case .userFelt: "filter_felt".localized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var sortIcon: String {
|
||||||
|
switch model.sort {
|
||||||
|
case .time: "clock"
|
||||||
|
case .position:
|
||||||
|
if #available(iOS 16, *) {
|
||||||
|
"compass.drawing"
|
||||||
|
} else {
|
||||||
|
"ruler"
|
||||||
|
}
|
||||||
|
case .magnitude: "thermometer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct RoundedButton: View {
|
||||||
|
let systemName: String
|
||||||
|
let tintColor: Color
|
||||||
|
let action: () -> Void
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button {
|
||||||
|
action()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: systemName)
|
||||||
|
.resizable()
|
||||||
|
.tint(tintColor)
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(maxHeight: .infinity)
|
||||||
|
.frame(width: 40.0)
|
||||||
|
.padding(8)
|
||||||
|
.overlay {
|
||||||
|
Capsule().stroke(AppTheme.Colors.gray.color, lineWidth: 1)
|
||||||
|
}
|
||||||
|
.animation(nil, value: systemName) // previene animazioni implicite nel bottone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
SeismicNetworkFilterRecapView(
|
||||||
|
model: .init(),
|
||||||
|
onSort: { _ in },
|
||||||
|
onMainFilter: {},
|
||||||
|
onMap: {}
|
||||||
|
)
|
||||||
|
.frame(height: 34.0)
|
||||||
|
}
|
||||||
+22
-2
@@ -140,7 +140,7 @@ class SeismicNetworksIntensityMapViewController: EQNBaseMapViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func nextPinStyle() {
|
private func nextPinStyle() {
|
||||||
pinStyle.next()
|
pinStyle.advance()
|
||||||
reloadMap()
|
reloadMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +233,7 @@ extension EQNMapAnnotationShakemap {
|
|||||||
case .full, .light:
|
case .full, .light:
|
||||||
let identifier = EQNSeismicAnnotationView.identifier(for: style)
|
let identifier = EQNSeismicAnnotationView.identifier(for: style)
|
||||||
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: self) as! EQNSeismicAnnotationView
|
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: self) as! EQNSeismicAnnotationView
|
||||||
annotationView.magnitude = String(format: "%.1f", shakemap.intensity)
|
annotationView.magnitude = intensityString(from: shakemap.intensity)
|
||||||
annotationView.magnitudeTextColor = intensityTextColor ?? .black
|
annotationView.magnitudeTextColor = intensityTextColor ?? .black
|
||||||
annotationView.magnitudeBackgroundColor = intensityColor
|
annotationView.magnitudeBackgroundColor = intensityColor
|
||||||
annotationView.canShowCallout = true
|
annotationView.canShowCallout = true
|
||||||
@@ -242,6 +242,26 @@ extension EQNMapAnnotationShakemap {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func intensityString(from intensity: Float) -> String {
|
||||||
|
let intensityRounded = (intensity * 10).rounded() / 10
|
||||||
|
let intensityFloor = floor(intensityRounded)
|
||||||
|
|
||||||
|
let romanNumerals: [Int: String] = [
|
||||||
|
1: "I", 2: "II", 3: "III", 4: "IV",
|
||||||
|
5: "V", 6: "VI", 7: "VII", 8: "VIII",
|
||||||
|
9: "IX", 10: "X", 11: "XI", 12: "XII"
|
||||||
|
]
|
||||||
|
|
||||||
|
var result = romanNumerals[Int(intensityFloor)] ?? ""
|
||||||
|
|
||||||
|
if intensityRounded != intensityFloor {
|
||||||
|
let reminder = Int(((intensityRounded - intensityFloor) * 10).rounded())
|
||||||
|
result += ".\(reminder)"
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate class ShakemapPolyline: MKPolyline {
|
fileprivate class ShakemapPolyline: MKPolyline {
|
||||||
|
|||||||
+11
-4
@@ -63,14 +63,17 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
|||||||
|
|
||||||
// MARK: - Internal
|
// MARK: - Internal
|
||||||
|
|
||||||
private let seismic: EQNSisma
|
private let seismic: EQNSisma?
|
||||||
private var allSeismics: [EQNSisma]
|
private var allSeismics: [EQNSisma]
|
||||||
/// Contains circles drawed on the map
|
/// Contains circles drawed on the map
|
||||||
private var mapCircles = [MKCircle]()
|
private var mapCircles = [MKCircle]()
|
||||||
|
|
||||||
// MARK: - Init
|
// MARK: - Init
|
||||||
|
|
||||||
init(seismic: EQNSisma, allSeismics: [EQNSisma]) {
|
init(
|
||||||
|
seismic: EQNSisma?,
|
||||||
|
allSeismics: [EQNSisma]
|
||||||
|
) {
|
||||||
self.seismic = seismic
|
self.seismic = seismic
|
||||||
self.allSeismics = allSeismics
|
self.allSeismics = allSeismics
|
||||||
super.init()
|
super.init()
|
||||||
@@ -128,7 +131,11 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func elaborateMapCenter() {
|
override func elaborateMapCenter() {
|
||||||
setMapCenter(for: seismic.coordinate)
|
if let seismic {
|
||||||
|
setMapCenter(for: seismic.coordinate)
|
||||||
|
} else if let location = CLLocationManager().location {
|
||||||
|
setMapCenter(for: location)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didTapAnnotation(_ annotation: MKAnnotation) {
|
override func didTapAnnotation(_ annotation: MKAnnotation) {
|
||||||
@@ -178,7 +185,7 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func nextPinStyle() {
|
private func nextPinStyle() {
|
||||||
pinStyle.next()
|
pinStyle.advance()
|
||||||
reloadMap()
|
reloadMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+80
-32
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import SwiftUI
|
||||||
import EventKitUI
|
import EventKitUI
|
||||||
import DZNEmptyDataSet
|
import DZNEmptyDataSet
|
||||||
import Shogun
|
import Shogun
|
||||||
@@ -68,7 +69,6 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
// MARK: - UI
|
// MARK: - UI
|
||||||
|
|
||||||
@IBOutlet private weak var displayModeButton: UIBarButtonItem!
|
@IBOutlet private weak var displayModeButton: UIBarButtonItem!
|
||||||
@IBOutlet private weak var sortButton: UIBarButtonItem!
|
|
||||||
private var tableViewTopConstraint: NSLayoutConstraint?
|
private var tableViewTopConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
private lazy var tableView: UITableView = {
|
private lazy var tableView: UITableView = {
|
||||||
@@ -111,6 +111,32 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
view.layer.borderColor = AppTheme.Colors.gray.cgColor
|
view.layer.borderColor = AppTheme.Colors.gray.cgColor
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// model is needed in order to send data to SwiftUI view
|
||||||
|
private let model = SeismicNetworkFilterRecapView.Model()
|
||||||
|
|
||||||
|
private lazy var filterRecapView: UIView = {
|
||||||
|
let hosting = UIHostingController(
|
||||||
|
rootView: SeismicNetworkFilterRecapView(
|
||||||
|
model: model,
|
||||||
|
onSort: { [weak self] sort in
|
||||||
|
self?.changeSort(to: sort)
|
||||||
|
},
|
||||||
|
onMainFilter: { [weak self] in
|
||||||
|
self?.openFilter()
|
||||||
|
},
|
||||||
|
onMap: { [weak self] in
|
||||||
|
self?.showMapDetail(for: nil)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
addChild(hosting)
|
||||||
|
let filterRecapView = hosting.view!
|
||||||
|
hosting.view.isOpaque = false
|
||||||
|
hosting.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
hosting.didMove(toParent: self)
|
||||||
|
return hosting.view
|
||||||
|
}()
|
||||||
|
|
||||||
// MARK: - View Lifecycle
|
// MARK: - View Lifecycle
|
||||||
|
|
||||||
@@ -147,19 +173,44 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func setupUI() {
|
private func setupUI() {
|
||||||
|
view.backgroundColor = tableView.backgroundColor
|
||||||
view.addSubview(scrollIndicatorView)
|
view.addSubview(scrollIndicatorView)
|
||||||
view.addSubview(tableView)
|
view.addSubview(tableView)
|
||||||
|
view.addSubview(filterRecapView)
|
||||||
|
|
||||||
scrollIndicatorView.topAnchor.constraint(equalTo: tableView.topAnchor).isActive = true
|
scrollIndicatorView.topAnchor.constraint(equalTo: tableView.topAnchor).isActive = true
|
||||||
scrollIndicatorView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
scrollIndicatorView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
||||||
scrollIndicatorView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
|
scrollIndicatorView.bottomAnchor.constraint(equalTo: tableView.bottomAnchor).isActive = true
|
||||||
scrollIndicatorView.widthAnchor.constraint(equalToConstant: 10.0).isActive = true
|
scrollIndicatorView.widthAnchor.constraint(equalToConstant: 10.0).isActive = true
|
||||||
|
|
||||||
tableViewTopConstraint = tableView.topAnchor.constraint(equalTo: view.topAnchor)
|
tableViewTopConstraint = tableView.topAnchor.constraint(equalTo: view.topAnchor)
|
||||||
tableViewTopConstraint?.isActive = true
|
tableViewTopConstraint?.isActive = true
|
||||||
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
||||||
tableView.trailingAnchor.constraint(equalTo: scrollIndicatorView.leadingAnchor).isActive = true
|
tableView.trailingAnchor.constraint(equalTo: scrollIndicatorView.leadingAnchor).isActive = true
|
||||||
tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
|
tableView.bottomAnchor
|
||||||
|
.constraint(
|
||||||
|
equalTo: filterRecapView.topAnchor,
|
||||||
|
constant: -8
|
||||||
|
).isActive = true
|
||||||
|
|
||||||
|
filterRecapView.heightAnchor.constraint(equalToConstant: 34.0).isActive = true
|
||||||
|
filterRecapView.leadingAnchor
|
||||||
|
.constraint(
|
||||||
|
equalTo: view.leadingAnchor,
|
||||||
|
constant: 10.0
|
||||||
|
).isActive = true
|
||||||
|
filterRecapView.trailingAnchor
|
||||||
|
.constraint(
|
||||||
|
equalTo: view.trailingAnchor,
|
||||||
|
constant: -10.0
|
||||||
|
).isActive = true
|
||||||
|
filterRecapView.topAnchor
|
||||||
|
.constraint(equalTo: tableView.bottomAnchor).isActive = true
|
||||||
|
filterRecapView.bottomAnchor
|
||||||
|
.constraint(
|
||||||
|
equalTo: view.safeAreaLayoutGuide.bottomAnchor,
|
||||||
|
constant: -8
|
||||||
|
).isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupFilterView(isVisible: Bool) {
|
private func setupFilterView(isVisible: Bool) {
|
||||||
@@ -201,31 +252,13 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
tableView.emptyDataSetSource = self
|
tableView.emptyDataSetSource = self
|
||||||
tableView.separatorStyle = .none
|
tableView.separatorStyle = .none
|
||||||
tableView.contentInset = EQNBaseContainerTableViewCell.EdgeInsets
|
tableView.contentInset = EQNBaseContainerTableViewCell.EdgeInsets
|
||||||
|
|
||||||
setupSortMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func setupSortMenu() {
|
|
||||||
let currentSort = EQNSeismic.shared.sort
|
|
||||||
sortButton.menu = UIMenu(title: "", image: nil, identifier: nil, options: [], children: [
|
|
||||||
UIAction(title: NSLocalizedString("sort_date", comment: ""), image: UIImage(systemName: "calendar"), state: currentSort == .time ? .on : .off) { [weak self ] _ in
|
|
||||||
self?.changeSort(to: .time)
|
|
||||||
},
|
|
||||||
UIAction(title: NSLocalizedString("sort_position", comment: ""), image: UIImage(systemName: "ruler"), state: currentSort == .position ? .on : .off) { [weak self] _ in
|
|
||||||
self?.changeSort(to: .position)
|
|
||||||
},
|
|
||||||
UIAction(title: NSLocalizedString("sort_magnitude", comment: ""), image: UIImage(systemName: "thermometer"), state: currentSort == .magnitude ? .on : .off) { [weak self] _ in
|
|
||||||
self?.changeSort(to: .magnitude)
|
|
||||||
}
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func checkForLocation() {
|
private func checkForLocation() {
|
||||||
// check if a valid location is available,
|
// check if a valid location is available,
|
||||||
// otherwise change the filter settings
|
// otherwise change the filter settings
|
||||||
if !isLocationAvailable() {
|
if !isLocationAvailable() {
|
||||||
EQNSeismic.shared.filterOption = .worldWide
|
updateFilter(type: .worldWide)
|
||||||
EQNSeismic.shared.saveFilters()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +277,7 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func showMapDetail(for seismic: EQNSisma) {
|
private func showMapDetail(for seismic: EQNSisma?) {
|
||||||
let seismics = getSeismics()
|
let seismics = getSeismics()
|
||||||
let controller = SeismicNetworksMapDetailViewController(seismic: seismic, allSeismics: seismics)
|
let controller = SeismicNetworksMapDetailViewController(seismic: seismic, allSeismics: seismics)
|
||||||
controller.delegate = self
|
controller.delegate = self
|
||||||
@@ -335,10 +368,7 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func changeSort(to sort: EQNSeismic.Sort) {
|
private func changeSort(to sort: EQNSeismic.Sort) {
|
||||||
EQNSeismic.shared.sort = sort
|
updateFilter(sort: sort)
|
||||||
EQNSeismic.shared.saveFilters()
|
|
||||||
|
|
||||||
setupSortMenu()
|
|
||||||
refreshUI()
|
refreshUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,11 +598,22 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
|
|
||||||
private func updateFilter(
|
private func updateFilter(
|
||||||
type: EQNSeismic.FilterType? = nil,
|
type: EQNSeismic.FilterType? = nil,
|
||||||
|
sort: EQNSeismic.Sort? = nil,
|
||||||
radius: Double? = nil,
|
radius: Double? = nil,
|
||||||
magnitude: Double? = nil
|
magnitude: Double? = nil
|
||||||
) {
|
) {
|
||||||
if let type {
|
if let type {
|
||||||
|
let previous = EQNSeismic.shared.filterOption
|
||||||
|
if previous == .userFelt && previous != type {
|
||||||
|
loadData(forced: true)
|
||||||
|
}
|
||||||
|
|
||||||
EQNSeismic.shared.filterOption = type
|
EQNSeismic.shared.filterOption = type
|
||||||
|
model.filter = type
|
||||||
|
}
|
||||||
|
if let sort {
|
||||||
|
EQNSeismic.shared.sort = sort
|
||||||
|
model.sort = sort
|
||||||
}
|
}
|
||||||
if let radius {
|
if let radius {
|
||||||
EQNSeismic.shared.maximumDistance = String(format: "%.0f", radius)
|
EQNSeismic.shared.maximumDistance = String(format: "%.0f", radius)
|
||||||
@@ -628,9 +669,15 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
if let centerIndexPath = getCenterCellIndexPath(), centerIndexPath != currentCenteredIndexPath {
|
if let centerIndexPath = getCenterCellIndexPath(), centerIndexPath != currentCenteredIndexPath {
|
||||||
currentCenteredIndexPath = centerIndexPath
|
currentCenteredIndexPath = centerIndexPath
|
||||||
|
|
||||||
let row = rows[centerIndexPath.row]
|
if rows.count > centerIndexPath.row {
|
||||||
if case .seismic = row, seismicViewModels.count > centerIndexPath.row {
|
let row = rows[centerIndexPath.row]
|
||||||
scrollIndicatorView.highlighted = seismicViewModels[centerIndexPath.row]
|
if case .seismic = row, seismicViewModels.count > centerIndexPath.row {
|
||||||
|
scrollIndicatorView.highlighted = seismicViewModels[centerIndexPath.row]
|
||||||
|
} else {
|
||||||
|
scrollIndicatorView.highlighted = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scrollIndicatorView.highlighted = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -641,12 +688,12 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
|||||||
loadData(forced: true)
|
loadData(forced: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func openFilterTapped(_ sender: Any) {
|
private func openFilter() {
|
||||||
performSegue(withIdentifier: Self.SegueIdentifierFilters, sender: nil)
|
performSegue(withIdentifier: Self.SegueIdentifierFilters, sender: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func collapseExpandTapped(_ sender: Any) {
|
@IBAction func collapseExpandTapped(_ sender: Any) {
|
||||||
cardDisplayType.next()
|
cardDisplayType.advance()
|
||||||
|
|
||||||
switch cardDisplayType {
|
switch cardDisplayType {
|
||||||
case .small:
|
case .small:
|
||||||
@@ -851,6 +898,7 @@ extension SeismicNetworksViewController: EKEventEditViewDelegate {
|
|||||||
|
|
||||||
extension SeismicNetworksViewController: SeismicFiltersViewControllerDelegate {
|
extension SeismicNetworksViewController: SeismicFiltersViewControllerDelegate {
|
||||||
func seismicFiltersControllerDidUpdateFilters(_ controller: SeismicFiltersViewController) {
|
func seismicFiltersControllerDidUpdateFilters(_ controller: SeismicFiltersViewController) {
|
||||||
|
model.filter = controller.currentFilterType
|
||||||
loadData(forced: controller.needsDataUpdate)
|
loadData(forced: controller.needsDataUpdate)
|
||||||
refreshUI()
|
refreshUI()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,13 +37,3 @@ extension CGFloat {
|
|||||||
self*2.0
|
self*2.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CaseIterable where Self: Equatable {
|
|
||||||
mutating func next() {
|
|
||||||
let all = Self.allCases
|
|
||||||
let idx = all.firstIndex(of: self)!
|
|
||||||
let next = all.index(after: idx)
|
|
||||||
let newValue = all[next == all.endIndex ? all.startIndex : next]
|
|
||||||
self = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ public class Log {
|
|||||||
shared.log(level: .debug, tag: tag ?? "nil", message: message ?? "nil", functionName: functionName)
|
shared.log(level: .debug, tag: tag ?? "nil", message: message ?? "nil", functionName: functionName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 15.0, *)
|
|
||||||
public func dumpLog() async -> String {
|
public func dumpLog() async -> String {
|
||||||
return (try? await getLogEntries()) ?? ""
|
return (try? await getLogEntries()) ?? ""
|
||||||
}
|
}
|
||||||
@@ -104,7 +103,6 @@ public class Log {
|
|||||||
|
|
||||||
/// Retrieve log entries from a specified time.
|
/// Retrieve log entries from a specified time.
|
||||||
/// - Returns: String of log entries, newlines separated
|
/// - Returns: String of log entries, newlines separated
|
||||||
@available(iOS 15.0, *)
|
|
||||||
private func getLogEntries() async throws -> String {
|
private func getLogEntries() async throws -> String {
|
||||||
let logTask = Task.init(priority: .utility) { () -> String in
|
let logTask = Task.init(priority: .utility) { () -> String in
|
||||||
let logs = try retrieveLogEntries()
|
let logs = try retrieveLogEntries()
|
||||||
@@ -116,7 +114,6 @@ public class Log {
|
|||||||
return try await logTask.value
|
return try await logTask.value
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 15.0, *)
|
|
||||||
private func retrieveLogEntries() throws -> [OSLogEntryLog] {
|
private func retrieveLogEntries() throws -> [OSLogEntryLog] {
|
||||||
// Open the log store.
|
// Open the log store.
|
||||||
let logStore = try OSLogStore(scope: .currentProcessIdentifier)
|
let logStore = try OSLogStore(scope: .currentProcessIdentifier)
|
||||||
@@ -134,7 +131,6 @@ public class Log {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 15.0, *)
|
|
||||||
extension OSLogEntryLog.Level: @retroactive CustomStringConvertible {
|
extension OSLogEntryLog.Level: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
|
|||||||
@@ -134,11 +134,13 @@
|
|||||||
// L'endpoint per lo scaricamento dei dati prende due parametri:
|
// L'endpoint per lo scaricamento dei dati prende due parametri:
|
||||||
// - `pro` per il provider selezionato,
|
// - `pro` per il provider selezionato,
|
||||||
// - `mag` per la magnitudo minima.
|
// - `mag` per la magnitudo minima.
|
||||||
// Dalla v5.8 non esiste più la selezione delle reti, quindi passiamo sempre "ALL".
|
// Dalla v5.8 non esiste più la selezione delle reti, quindi il provider da passare diventa:
|
||||||
|
// - `FELT` se filtro selezionato è sismi percepiti
|
||||||
|
// - `ALL` in tutti gli altri casi
|
||||||
// Per la magnitudo minima, invece, passiamo 0 per i filtri "raggio" e "rilevanti,
|
// Per la magnitudo minima, invece, passiamo 0 per i filtri "raggio" e "rilevanti,
|
||||||
// altrimenti passiamo 2 per il filtro "mondo"
|
// altrimenti passiamo 2 per il filtro "mondo"
|
||||||
|
|
||||||
NSString *filterProvider = @"ALL";
|
NSString *filterProvider = [EQNSeismic shared].filterOption == FilterTypeUserFelt ? @"FELT" : @"ALL";
|
||||||
NSString *filterMagnitude = [EQNSeismic shared].filterOption == FilterTypeWorldWide ? @"2.0" : @"0.0";
|
NSString *filterMagnitude = [EQNSeismic shared].filterOption == FilterTypeWorldWide ? @"2.0" : @"0.0";
|
||||||
|
|
||||||
NSString *queryString = [NSString stringWithFormat:@"?pro=%@&mag=%@", filterProvider, filterMagnitude];
|
NSString *queryString = [NSString stringWithFormat:@"?pro=%@&mag=%@", filterProvider, filterMagnitude];
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class EQNRealtimePushNotification: NSObject, Codable {
|
|||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case type
|
case type
|
||||||
case intensity
|
case intensity
|
||||||
|
case magnitude
|
||||||
case latitude
|
case latitude
|
||||||
case longitude
|
case longitude
|
||||||
case counter
|
case counter
|
||||||
@@ -36,6 +37,7 @@ class EQNRealtimePushNotification: NSObject, Codable {
|
|||||||
let type: String
|
let type: String
|
||||||
/// Earthquake intensity
|
/// Earthquake intensity
|
||||||
let intensity: Int
|
let intensity: Int
|
||||||
|
let magnitude: Int
|
||||||
/// Earthquake coordinate
|
/// Earthquake coordinate
|
||||||
let latitude: Double
|
let latitude: Double
|
||||||
let longitude: Double
|
let longitude: Double
|
||||||
@@ -63,6 +65,7 @@ class EQNRealtimePushNotification: NSObject, Codable {
|
|||||||
init(
|
init(
|
||||||
type: String,
|
type: String,
|
||||||
intensity: Int,
|
intensity: Int,
|
||||||
|
magnitude: Int,
|
||||||
latitude: Double,
|
latitude: Double,
|
||||||
longitude: Double,
|
longitude: Double,
|
||||||
counter: Int,
|
counter: Int,
|
||||||
@@ -76,6 +79,7 @@ class EQNRealtimePushNotification: NSObject, Codable {
|
|||||||
) {
|
) {
|
||||||
self.type = type
|
self.type = type
|
||||||
self.intensity = intensity
|
self.intensity = intensity
|
||||||
|
self.magnitude = magnitude
|
||||||
self.latitude = latitude
|
self.latitude = latitude
|
||||||
self.longitude = longitude
|
self.longitude = longitude
|
||||||
self.counter = counter
|
self.counter = counter
|
||||||
@@ -201,6 +205,27 @@ class EQNRealtimePushNotification: NSObject, Codable {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var title: String = ""
|
||||||
|
if let titleKey = alert["loc-key"] as? String, let args = alert["loc-args"] as? [String], let arg = args.first {
|
||||||
|
title = String(format: NSLocalizedString(titleKey, comment: ""), arg)
|
||||||
|
}
|
||||||
|
let displayTitle = payload.string(forKey: "title", orDefault: "")
|
||||||
|
let displayBody = payload.string(forKey: "body", orDefault: "")
|
||||||
|
|
||||||
|
return from(
|
||||||
|
userInfo: userInfo,
|
||||||
|
title: title,
|
||||||
|
displayTitle: displayTitle,
|
||||||
|
displayBody: displayBody
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func from(
|
||||||
|
userInfo: [AnyHashable: Any],
|
||||||
|
title: String,
|
||||||
|
displayTitle: String,
|
||||||
|
displayBody: String
|
||||||
|
) -> EQNRealtimePushNotification? {
|
||||||
guard let latitude = userInfo.double(forKey: "latitude"),
|
guard let latitude = userInfo.double(forKey: "latitude"),
|
||||||
let longitude = userInfo.double(forKey: "longitude") else {
|
let longitude = userInfo.double(forKey: "longitude") else {
|
||||||
print("[EQNRealtimePushNotification] Unable to get coordinate from push notification")
|
print("[EQNRealtimePushNotification] Unable to get coordinate from push notification")
|
||||||
@@ -209,6 +234,7 @@ class EQNRealtimePushNotification: NSObject, Codable {
|
|||||||
|
|
||||||
let type = userInfo.string(forKey: "type", orDefault: "")
|
let type = userInfo.string(forKey: "type", orDefault: "")
|
||||||
let intensity = userInfo.integer(forKey: "intensity", orDefault: 0)
|
let intensity = userInfo.integer(forKey: "intensity", orDefault: 0)
|
||||||
|
let magnitude = userInfo.integer(forKey: "magnitude", orDefault: 0)
|
||||||
|
|
||||||
let counter = userInfo.integer(forKey: "counter", orDefault: 0)
|
let counter = userInfo.integer(forKey: "counter", orDefault: 0)
|
||||||
var dateTime: Date?
|
var dateTime: Date?
|
||||||
@@ -222,16 +248,10 @@ class EQNRealtimePushNotification: NSObject, Codable {
|
|||||||
}
|
}
|
||||||
let peak = userInfo.double(forKey: "peak")
|
let peak = userInfo.double(forKey: "peak")
|
||||||
|
|
||||||
var title: String = ""
|
|
||||||
if let titleKey = alert["loc-key"] as? String, let args = alert["loc-args"] as? [String], let arg = args.first {
|
|
||||||
title = String(format: NSLocalizedString(titleKey, comment: ""), arg)
|
|
||||||
}
|
|
||||||
let displayTitle = payload.string(forKey: "title", orDefault: "")
|
|
||||||
let displayBody = payload.string(forKey: "body", orDefault: "")
|
|
||||||
|
|
||||||
return .init(
|
return .init(
|
||||||
type: type,
|
type: type,
|
||||||
intensity: intensity,
|
intensity: intensity,
|
||||||
|
magnitude: magnitude,
|
||||||
latitude: latitude,
|
latitude: latitude,
|
||||||
longitude: longitude,
|
longitude: longitude,
|
||||||
counter: counter,
|
counter: counter,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import Foundation
|
|||||||
case userFelt
|
case userFelt
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Sort: Int {
|
enum Sort: Int, CaseIterable {
|
||||||
case time
|
case time
|
||||||
case position
|
case position
|
||||||
case magnitude
|
case magnitude
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="CWo-PE-Dqp">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="CWo-PE-Dqp">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
@@ -26,12 +26,6 @@
|
|||||||
<action selector="collapseExpandTapped:" destination="tVM-DH-fmv" id="EnD-92-5ZX"/>
|
<action selector="collapseExpandTapped:" destination="tVM-DH-fmv" id="EnD-92-5ZX"/>
|
||||||
</connections>
|
</connections>
|
||||||
</barButtonItem>
|
</barButtonItem>
|
||||||
<barButtonItem image="navbar-icon-filters" id="vOM-Np-CIk">
|
|
||||||
<connections>
|
|
||||||
<action selector="openFilterTapped:" destination="tVM-DH-fmv" id="76a-Bl-bCj"/>
|
|
||||||
</connections>
|
|
||||||
</barButtonItem>
|
|
||||||
<barButtonItem image="navbar-icon-sort" id="LyU-KI-3Mb"/>
|
|
||||||
<barButtonItem image="navbar-icon-refresh" id="ZJh-jF-ILm">
|
<barButtonItem image="navbar-icon-refresh" id="ZJh-jF-ILm">
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="refreshDataTapped:" destination="tVM-DH-fmv" id="qs5-jS-0Op"/>
|
<action selector="refreshDataTapped:" destination="tVM-DH-fmv" id="qs5-jS-0Op"/>
|
||||||
@@ -41,7 +35,6 @@
|
|||||||
</navigationItem>
|
</navigationItem>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="displayModeButton" destination="HTN-07-s5p" id="Lhc-Od-MvL"/>
|
<outlet property="displayModeButton" destination="HTN-07-s5p" id="Lhc-Od-MvL"/>
|
||||||
<outlet property="sortButton" destination="LyU-KI-3Mb" id="969-Zg-YBB"/>
|
|
||||||
<segue destination="6LP-zk-O1z" kind="presentation" identifier="ShowFilters" modalPresentationStyle="overCurrentContext" modalTransitionStyle="crossDissolve" id="Nzu-iH-UgB"/>
|
<segue destination="6LP-zk-O1z" kind="presentation" identifier="ShowFilters" modalPresentationStyle="overCurrentContext" modalTransitionStyle="crossDissolve" id="Nzu-iH-UgB"/>
|
||||||
<segue destination="Rfp-kt-2Kx" kind="presentation" identifier="ShowCardSettings" modalPresentationStyle="overCurrentContext" modalTransitionStyle="crossDissolve" id="VWw-16-xGw"/>
|
<segue destination="Rfp-kt-2Kx" kind="presentation" identifier="ShowCardSettings" modalPresentationStyle="overCurrentContext" modalTransitionStyle="crossDissolve" id="VWw-16-xGw"/>
|
||||||
</connections>
|
</connections>
|
||||||
@@ -59,7 +52,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="jl5-sK-UaA">
|
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="jl5-sK-UaA">
|
||||||
<rect key="frame" x="0.0" y="144" width="414" height="614"/>
|
<rect key="frame" x="0.0" y="192" width="414" height="532"/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="dataSource" destination="fbo-Ug-IiE" id="meg-jS-D2z"/>
|
<outlet property="dataSource" destination="fbo-Ug-IiE" id="meg-jS-D2z"/>
|
||||||
@@ -67,7 +60,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</tableView>
|
</tableView>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4mK-no-RDk">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4mK-no-RDk">
|
||||||
<rect key="frame" x="0.0" y="758" width="414" height="55"/>
|
<rect key="frame" x="0.0" y="724" width="414" height="55"/>
|
||||||
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
|
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="55" id="1Dm-ex-6od"/>
|
<constraint firstAttribute="height" constant="55" id="1Dm-ex-6od"/>
|
||||||
@@ -276,17 +269,17 @@
|
|||||||
<objects>
|
<objects>
|
||||||
<viewController storyboardIdentifier="EQNLogViewController" id="noK-2F-IZE" customClass="EQNLogViewController" sceneMemberID="viewController">
|
<viewController storyboardIdentifier="EQNLogViewController" id="noK-2F-IZE" customClass="EQNLogViewController" sceneMemberID="viewController">
|
||||||
<view key="view" contentMode="scaleToFill" id="6P7-SV-yrd">
|
<view key="view" contentMode="scaleToFill" id="6P7-SV-yrd">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="886"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="838"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="ija-iK-2hE">
|
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="ija-iK-2hE">
|
||||||
<rect key="frame" x="0.0" y="20" width="414" height="808"/>
|
<rect key="frame" x="0.0" y="20" width="414" height="760"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||||
</textView>
|
</textView>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="g5C-Wg-DEu">
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="g5C-Wg-DEu">
|
||||||
<rect key="frame" x="16" y="836" width="382" height="30"/>
|
<rect key="frame" x="16" y="788" width="382" height="30"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="30" id="CFr-4Z-X1A"/>
|
<constraint firstAttribute="height" constant="30" id="CFr-4Z-X1A"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
@@ -404,7 +397,7 @@
|
|||||||
<tabBarItem key="tabBarItem" title="Settings" image="tabbar-icon-settings" id="5VO-yI-kw5"/>
|
<tabBarItem key="tabBarItem" title="Settings" image="tabbar-icon-settings" id="5VO-yI-kw5"/>
|
||||||
<toolbarItems/>
|
<toolbarItems/>
|
||||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="B9g-HM-VPb">
|
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="B9g-HM-VPb">
|
||||||
<rect key="frame" x="0.0" y="48" width="414" height="96"/>
|
<rect key="frame" x="0.0" y="96" width="414" height="96"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</navigationBar>
|
</navigationBar>
|
||||||
<nil name="viewControllers"/>
|
<nil name="viewControllers"/>
|
||||||
@@ -506,7 +499,7 @@
|
|||||||
<tabBarItem key="tabBarItem" title="Reports" image="tabbar-icon-reports" id="oaL-SG-Zpq"/>
|
<tabBarItem key="tabBarItem" title="Reports" image="tabbar-icon-reports" id="oaL-SG-Zpq"/>
|
||||||
<toolbarItems/>
|
<toolbarItems/>
|
||||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="xbw-SF-Eq7">
|
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="xbw-SF-Eq7">
|
||||||
<rect key="frame" x="0.0" y="48" width="414" height="96"/>
|
<rect key="frame" x="0.0" y="96" width="414" height="96"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</navigationBar>
|
</navigationBar>
|
||||||
<nil name="viewControllers"/>
|
<nil name="viewControllers"/>
|
||||||
@@ -525,7 +518,7 @@
|
|||||||
<tabBarItem key="tabBarItem" title="Alerts" image="tabbar-icon-alerts" id="aeo-GH-qCD"/>
|
<tabBarItem key="tabBarItem" title="Alerts" image="tabbar-icon-alerts" id="aeo-GH-qCD"/>
|
||||||
<toolbarItems/>
|
<toolbarItems/>
|
||||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="bk1-MS-moG">
|
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="bk1-MS-moG">
|
||||||
<rect key="frame" x="0.0" y="48" width="414" height="96"/>
|
<rect key="frame" x="0.0" y="96" width="414" height="96"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</navigationBar>
|
</navigationBar>
|
||||||
<nil name="viewControllers"/>
|
<nil name="viewControllers"/>
|
||||||
@@ -544,7 +537,7 @@
|
|||||||
<tabBarItem key="tabBarItem" title="Seismic Networks" image="tabbar-icon-networks" id="eed-sY-0Ua"/>
|
<tabBarItem key="tabBarItem" title="Seismic Networks" image="tabbar-icon-networks" id="eed-sY-0Ua"/>
|
||||||
<toolbarItems/>
|
<toolbarItems/>
|
||||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="LRX-7t-Fk4">
|
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="LRX-7t-Fk4">
|
||||||
<rect key="frame" x="0.0" y="48" width="414" height="96"/>
|
<rect key="frame" x="0.0" y="96" width="414" height="96"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</navigationBar>
|
</navigationBar>
|
||||||
<nil name="viewControllers"/>
|
<nil name="viewControllers"/>
|
||||||
@@ -565,7 +558,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="200" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="a35-sg-TCr">
|
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="200" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="a35-sg-TCr">
|
||||||
<rect key="frame" x="0.0" y="144" width="414" height="614"/>
|
<rect key="frame" x="0.0" y="192" width="414" height="532"/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="dataSource" destination="syj-UE-OWc" id="Vah-TU-YfT"/>
|
<outlet property="dataSource" destination="syj-UE-OWc" id="Vah-TU-YfT"/>
|
||||||
@@ -573,7 +566,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</tableView>
|
</tableView>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PyX-yA-DXv">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PyX-yA-DXv">
|
||||||
<rect key="frame" x="0.0" y="758" width="414" height="55"/>
|
<rect key="frame" x="0.0" y="724" width="414" height="55"/>
|
||||||
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
|
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="55" id="kmt-E8-s2w"/>
|
<constraint firstAttribute="height" constant="55" id="kmt-E8-s2w"/>
|
||||||
@@ -623,9 +616,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<image name="1.square" catalog="system" width="128" height="114"/>
|
<image name="1.square" catalog="system" width="128" height="114"/>
|
||||||
<image name="navbar-icon-arrow-collapse" width="24" height="24"/>
|
<image name="navbar-icon-arrow-collapse" width="24" height="24"/>
|
||||||
<image name="navbar-icon-filters" width="24" height="24"/>
|
|
||||||
<image name="navbar-icon-refresh" width="24" height="24"/>
|
<image name="navbar-icon-refresh" width="24" height="24"/>
|
||||||
<image name="navbar-icon-sort" width="24" height="24"/>
|
|
||||||
<image name="tabbar-icon-alerts" width="25" height="25"/>
|
<image name="tabbar-icon-alerts" width="25" height="25"/>
|
||||||
<image name="tabbar-icon-networks" width="25" height="25"/>
|
<image name="tabbar-icon-networks" width="25" height="25"/>
|
||||||
<image name="tabbar-icon-reports" width="25" height="25"/>
|
<image name="tabbar-icon-reports" width="25" height="25"/>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
class EQNBlurredCloseButton: UIButton {
|
class EQNBlurredCloseButton: UIButton {
|
||||||
@@ -18,6 +19,12 @@ class EQNBlurredCloseButton: UIButton {
|
|||||||
setupUI()
|
setupUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func awakeFromNib() {
|
||||||
|
super.awakeFromNib()
|
||||||
|
|
||||||
|
setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func setupUI() {
|
private func setupUI() {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class EQNSeismicAnnotationView: MKAnnotationView {
|
|||||||
private static let FullViewHeight: CGFloat = MagnitudeHeight + 2*LabelHeight
|
private static let FullViewHeight: CGFloat = MagnitudeHeight + 2*LabelHeight
|
||||||
private static let FullViewWidth: CGFloat = 100.0
|
private static let FullViewWidth: CGFloat = 100.0
|
||||||
private static let SmallViewHeight: CGFloat = MagnitudeHeight
|
private static let SmallViewHeight: CGFloat = MagnitudeHeight
|
||||||
private static let SmallViewWidth: CGFloat = 100.0
|
private static let SmallViewWidth: CGFloat = 80.0
|
||||||
static let CircleViewHeight: CGFloat = 20.0
|
static let CircleViewHeight: CGFloat = 20.0
|
||||||
|
|
||||||
// MARK: - Public
|
// MARK: - Public
|
||||||
@@ -80,7 +80,7 @@ class EQNSeismicAnnotationView: MKAnnotationView {
|
|||||||
|
|
||||||
private lazy var magnitudeLabel: UILabel = {
|
private lazy var magnitudeLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = UIFont.systemFont(ofSize: 12, weight: .bold)
|
label.font = UIFont.systemFont(ofSize: 11, weight: .bold)
|
||||||
label.textAlignment = .center
|
label.textAlignment = .center
|
||||||
label.textColor = AppTheme.Colors.lightBlue
|
label.textColor = AppTheme.Colors.lightBlue
|
||||||
return label
|
return label
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"permission_location_no_background_solve" = "حل المشكلة";
|
"permission_location_no_background_solve" = "حل المشكلة";
|
||||||
"main_share_app" = "شارك التطبيق";
|
"main_share_app" = "شارك التطبيق";
|
||||||
"main_vote" = "قيّم التطبيق";
|
"main_vote" = "قيّم التطبيق";
|
||||||
"main_twitter_see" = "التبيين في تويتر";
|
"main_twitter_see" = "عرض على X";
|
||||||
"map_smartphone_magnitude" = "سيتم تقدير قوة الزلزال بواسطة الشبكة الزلزالية الوطنية وسيظهر في علامة تبويب الشبكات الزلزالية في التطبيق";
|
"map_smartphone_magnitude" = "سيتم تقدير قوة الزلزال بواسطة الشبكة الزلزالية الوطنية وسيظهر في علامة تبويب الشبكات الزلزالية في التطبيق";
|
||||||
"main_alerttest" = "تنبيه اختياري";
|
"main_alerttest" = "تنبيه اختياري";
|
||||||
"main_simulator" = "محاكي";
|
"main_simulator" = "محاكي";
|
||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "شهريا";
|
"subscription_plan_monthly" = "شهريا";
|
||||||
"subscription_plan_yearly" = "سنوي";
|
"subscription_plan_yearly" = "سنوي";
|
||||||
"subscription_plan_perpetual" = "حياة";
|
"subscription_plan_perpetual" = "حياة";
|
||||||
|
"tap_to_open" = "انقر للتكبير";
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"permission_location_no_background_solve" = "Διόρθωση";
|
"permission_location_no_background_solve" = "Διόρθωση";
|
||||||
"main_share_app" = "Μοιράσου";
|
"main_share_app" = "Μοιράσου";
|
||||||
"main_vote" = "Ψήφισε την Εφαρμογή";
|
"main_vote" = "Ψήφισε την Εφαρμογή";
|
||||||
"main_twitter_see" = "Twitter";
|
"main_twitter_see" = "X";
|
||||||
"map_smartphone_magnitude" = "Το μέγεθος θα εκτιμηθεί από το εθνικό σεισμικό δίκτυο και θα εμφανιστεί στην οθόνη Σεισμικών Δικτύων της εφαρμογής";
|
"map_smartphone_magnitude" = "Το μέγεθος θα εκτιμηθεί από το εθνικό σεισμικό δίκτυο και θα εμφανιστεί στην οθόνη Σεισμικών Δικτύων της εφαρμογής";
|
||||||
"main_alerttest" = "Τεστ ειδοποίησης";
|
"main_alerttest" = "Τεστ ειδοποίησης";
|
||||||
"main_simulator" = "Προσομοιωτής";
|
"main_simulator" = "Προσομοιωτής";
|
||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "Μηνιαίο";
|
"subscription_plan_monthly" = "Μηνιαίο";
|
||||||
"subscription_plan_yearly" = "Ετήσιο";
|
"subscription_plan_yearly" = "Ετήσιο";
|
||||||
"subscription_plan_perpetual" = "Διάρκεια Ζωής";
|
"subscription_plan_perpetual" = "Διάρκεια Ζωής";
|
||||||
|
"tap_to_open" = "Πατήστε για μεγέθυνση";
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"permission_location_no_background_solve" = "Solve";
|
"permission_location_no_background_solve" = "Solve";
|
||||||
"main_share_app" = "Share App";
|
"main_share_app" = "Share App";
|
||||||
"main_vote" = "Rate the App";
|
"main_vote" = "Rate the App";
|
||||||
"main_twitter_see" = "View on Twitter";
|
"main_twitter_see" = "View on X";
|
||||||
"map_smartphone_magnitude" = "The magnitude will be estimated by the national seismic network and it will appear in the Seismic Networks tab of the app";
|
"map_smartphone_magnitude" = "The magnitude will be estimated by the national seismic network and it will appear in the Seismic Networks tab of the app";
|
||||||
"main_alerttest" = "Test alert";
|
"main_alerttest" = "Test alert";
|
||||||
"main_simulator" = "Simulator";
|
"main_simulator" = "Simulator";
|
||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "Monthly";
|
"subscription_plan_monthly" = "Monthly";
|
||||||
"subscription_plan_yearly" = "Annual";
|
"subscription_plan_yearly" = "Annual";
|
||||||
"subscription_plan_perpetual" = "Lifetime";
|
"subscription_plan_perpetual" = "Lifetime";
|
||||||
|
"tap_to_open" = "Tap to open";
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"permission_location_no_background_solve" = "Corregir";
|
"permission_location_no_background_solve" = "Corregir";
|
||||||
"main_share_app" = "Comparte App";
|
"main_share_app" = "Comparte App";
|
||||||
"main_vote" = "Vota la app";
|
"main_vote" = "Vota la app";
|
||||||
"main_twitter_see" = "Ver en Twitter";
|
"main_twitter_see" = "Ver en X";
|
||||||
"map_smartphone_magnitude" = "La magnitud será comunicada por la red sísmica nacional y aparecerá en la sección de Redes Sísmicas de la app";
|
"map_smartphone_magnitude" = "La magnitud será comunicada por la red sísmica nacional y aparecerá en la sección de Redes Sísmicas de la app";
|
||||||
"main_alerttest" = "Prueba alerta";
|
"main_alerttest" = "Prueba alerta";
|
||||||
"main_simulator" = "Simulador";
|
"main_simulator" = "Simulador";
|
||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "Mensual";
|
"subscription_plan_monthly" = "Mensual";
|
||||||
"subscription_plan_yearly" = "Anual";
|
"subscription_plan_yearly" = "Anual";
|
||||||
"subscription_plan_perpetual" = "Para siempre";
|
"subscription_plan_perpetual" = "Para siempre";
|
||||||
|
"tap_to_open" = "Toque para ampliar";
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"permission_location_no_background_solve" = "Corriger";
|
"permission_location_no_background_solve" = "Corriger";
|
||||||
"main_share_app" = "Partager l'App";
|
"main_share_app" = "Partager l'App";
|
||||||
"main_vote" = "Voter l'App";
|
"main_vote" = "Voter l'App";
|
||||||
"main_twitter_see" = "Voir sur Twitter";
|
"main_twitter_see" = "Voir sur X";
|
||||||
"map_smartphone_magnitude" = "La magnitude sera estimée par le réseau sismique national et s'affichera dans la page d'écran Réseaux Sismiques de l'app";
|
"map_smartphone_magnitude" = "La magnitude sera estimée par le réseau sismique national et s'affichera dans la page d'écran Réseaux Sismiques de l'app";
|
||||||
"main_alerttest" = "Test alerte";
|
"main_alerttest" = "Test alerte";
|
||||||
"main_simulator" = "Simulateur";
|
"main_simulator" = "Simulateur";
|
||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "Mensuel";
|
"subscription_plan_monthly" = "Mensuel";
|
||||||
"subscription_plan_yearly" = "Annuel";
|
"subscription_plan_yearly" = "Annuel";
|
||||||
"subscription_plan_perpetual" = "Pour toujours";
|
"subscription_plan_perpetual" = "Pour toujours";
|
||||||
|
"tap_to_open" = "Appuyez pour agrandir";
|
||||||
|
|||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "Mjesečno";
|
"subscription_plan_monthly" = "Mjesečno";
|
||||||
"subscription_plan_yearly" = "Godišnji";
|
"subscription_plan_yearly" = "Godišnji";
|
||||||
"subscription_plan_perpetual" = "Zauvijek";
|
"subscription_plan_perpetual" = "Zauvijek";
|
||||||
|
"tap_to_open" = "Dodirnite za uvećanje";
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"permission_location_no_background_solve" = "Atasi";
|
"permission_location_no_background_solve" = "Atasi";
|
||||||
"main_share_app" = "Bagikan Aplikasi";
|
"main_share_app" = "Bagikan Aplikasi";
|
||||||
"main_vote" = "Beri Rating untuk Aplikasi";
|
"main_vote" = "Beri Rating untuk Aplikasi";
|
||||||
"main_twitter_see" = "Lihat di Twitter";
|
"main_twitter_see" = "Lihat di X";
|
||||||
"map_smartphone_magnitude" = "Magnitudo akan diperkirakan oleh jaringan seismik nasional dan akan muncul di tab Jaringan Seismik pada aplikasi";
|
"map_smartphone_magnitude" = "Magnitudo akan diperkirakan oleh jaringan seismik nasional dan akan muncul di tab Jaringan Seismik pada aplikasi";
|
||||||
"main_alerttest" = "Tes peringatan";
|
"main_alerttest" = "Tes peringatan";
|
||||||
"main_simulator" = "Simulator";
|
"main_simulator" = "Simulator";
|
||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "Bulanan";
|
"subscription_plan_monthly" = "Bulanan";
|
||||||
"subscription_plan_yearly" = "Tahunan";
|
"subscription_plan_yearly" = "Tahunan";
|
||||||
"subscription_plan_perpetual" = "Selamanya";
|
"subscription_plan_perpetual" = "Selamanya";
|
||||||
|
"tap_to_open" = "Ketuk untuk memperbesar";
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"permission_location_no_background_solve" = "Correggi";
|
"permission_location_no_background_solve" = "Correggi";
|
||||||
"main_share_app" = "Condividi App";
|
"main_share_app" = "Condividi App";
|
||||||
"main_vote" = "Vota l'App";
|
"main_vote" = "Vota l'App";
|
||||||
"main_twitter_see" = "Vedi in Twitter";
|
"main_twitter_see" = "Vedi in X";
|
||||||
"map_smartphone_magnitude" = "La magnitudo sarà comunicata dalla rete sismica nazionale e comparirà nella sezione Reti Sismiche dell'app";
|
"map_smartphone_magnitude" = "La magnitudo sarà comunicata dalla rete sismica nazionale e comparirà nella sezione Reti Sismiche dell'app";
|
||||||
"main_alerttest" = "Test Allerta";
|
"main_alerttest" = "Test Allerta";
|
||||||
"main_simulator" = "Simulatore";
|
"main_simulator" = "Simulatore";
|
||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "Mensile";
|
"subscription_plan_monthly" = "Mensile";
|
||||||
"subscription_plan_yearly" = "Annuale";
|
"subscription_plan_yearly" = "Annuale";
|
||||||
"subscription_plan_perpetual" = "A vita";
|
"subscription_plan_perpetual" = "A vita";
|
||||||
|
"tap_to_open" = "Tocca per aprire";
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"permission_location_no_background_solve" = "Çözün";
|
"permission_location_no_background_solve" = "Çözün";
|
||||||
"main_share_app" = "Uygul. Paylaş";
|
"main_share_app" = "Uygul. Paylaş";
|
||||||
"main_vote" = "Uygulamayı oyla";
|
"main_vote" = "Uygulamayı oyla";
|
||||||
"main_twitter_see" = "Twitter";
|
"main_twitter_see" = "X";
|
||||||
"map_smartphone_magnitude" = "Büyüklük ulusal sismik ağ tarafından tahmin edilecek ve uygulamanın Sismik Ağlar sekmesinde görünecektir.";
|
"map_smartphone_magnitude" = "Büyüklük ulusal sismik ağ tarafından tahmin edilecek ve uygulamanın Sismik Ağlar sekmesinde görünecektir.";
|
||||||
"main_alerttest" = "Test uyarısı";
|
"main_alerttest" = "Test uyarısı";
|
||||||
"main_simulator" = "Simülatör";
|
"main_simulator" = "Simülatör";
|
||||||
@@ -236,3 +236,4 @@
|
|||||||
"subscription_plan_monthly" = "Aylık";
|
"subscription_plan_monthly" = "Aylık";
|
||||||
"subscription_plan_yearly" = "Yıllık";
|
"subscription_plan_yearly" = "Yıllık";
|
||||||
"subscription_plan_perpetual" = "Sonsuza kadar";
|
"subscription_plan_perpetual" = "Sonsuza kadar";
|
||||||
|
"tap_to_open" = "Büyütmek için dokunun";
|
||||||
|
|||||||
Reference in New Issue
Block a user