Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84c388044b | |||
| e61a45f78f | |||
| 0fdc60b938 | |||
| 5f02e2b8bb | |||
| b17a57b98e | |||
| 2379077272 | |||
| 78f0cfb2fa | |||
| f6bfe3fca0 | |||
| d5ab49b807 | |||
| b8bd547d65 | |||
| 547c503726 | |||
| 234622bcfd | |||
| 589466c8c6 | |||
| 2e7742951e | |||
| 3ed77ff1af | |||
| c98530fc54 | |||
| 98cc7e7c4c | |||
| 4db0bb6316 | |||
| 8c3f2dad6d | |||
| e0f346a4dc | |||
| eac0f8249e | |||
| d7c691101c | |||
| 49edbe1a14 | |||
| c5b3750ee7 | |||
| 98fb65a640 | |||
| c20041127b | |||
| 3995c29b22 | |||
| dfa07d0d10 | |||
| ce6fbb24ff | |||
| 382dcfa794 | |||
| d46a2e1559 | |||
| b0d1cde42b | |||
| d8612e33a3 | |||
| 73826d7520 | |||
| 3f57ac9b96 | |||
| 54c78aac0f | |||
| 975f5ed5bc | |||
| 52142486cf | |||
| b4b676ca8d | |||
| dd9ef878e2 | |||
| 5b978e535c | |||
| 242c15ba58 | |||
| a224837dcb | |||
| a21c16a01c | |||
| 1496f25251 | |||
| ad6eb6619c | |||
| f9a8dffad5 | |||
| a708a0f79a | |||
| 49431a760c | |||
| a57e883409 | |||
| b373dc1d60 | |||
| 01f1df9c01 | |||
| 72441d0532 | |||
| a4afb84e6d | |||
| 45a59e30ba | |||
| dac13acb9e | |||
| a9e264d666 | |||
| e64aaf2469 | |||
| 30c7536d4c | |||
| 70e82a67b1 | |||
| f020ac70a1 | |||
| dc4ccd796d | |||
| f66d6558b5 | |||
| 536ed32fb9 | |||
| 2e1a2a8e04 | |||
| 527132b7eb | |||
| 8cf69a9d12 | |||
| 6cba42994d | |||
| fd7821c083 | |||
| 5fab419d0e | |||
| befe46465b | |||
| 5e6ee892ce | |||
| 79d4b3b3bd | |||
| 357bdd47e3 | |||
| 1e4dd507da |
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## Versione 5.8
|
||||
- Modifica algoritmo filtro lista (issue #70)
|
||||
- Modifica impostazioni "Notifiche da reti sismiche" (issue #66)
|
||||
- Modifica invio impostazioni app per notifiche (issue #68)
|
||||
- Modifica impostazioni "Notifiche segnalazioni utente" (issue #67)
|
||||
- Modifica tab Reti Sismiche (issue #69)
|
||||
|
||||
## Versione 5.7
|
||||
- Aumentato target ad iOS 13
|
||||
- Disattivata logica calibrazione/monitoraggio
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Simulator Target Bundle": "com.finazzi.distquake",
|
||||
"magnitude_range" : "0",
|
||||
"provider" : "SGC",
|
||||
"google.c.a.e" : "1",
|
||||
@@ -9,6 +9,7 @@
|
||||
import UserNotifications
|
||||
import CoreLocation
|
||||
import Shogun
|
||||
import UIKit
|
||||
|
||||
class NotificationService: UNNotificationServiceExtension {
|
||||
|
||||
@@ -119,13 +120,26 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
}
|
||||
|
||||
// add the icon as notification attachment
|
||||
if !iconName.isEmpty {
|
||||
iconName = iconName.replacingOccurrences(of: ".png", with: "")
|
||||
|
||||
if let imageUrl = Bundle(for: NotificationService.self).url(forResource: iconName, withExtension: "png"),
|
||||
let attachment = try? UNNotificationAttachment(identifier: iconName, url: imageUrl) {
|
||||
bestAttemptContent.attachments = [ attachment ]
|
||||
}
|
||||
// if !iconName.isEmpty {
|
||||
// iconName = iconName.replacingOccurrences(of: ".png", with: "")
|
||||
//
|
||||
// if let imageUrl = Bundle(for: NotificationService.self).url(forResource: iconName, withExtension: "png"),
|
||||
// let attachment = try? UNNotificationAttachment(identifier: iconName, url: imageUrl) {
|
||||
// bestAttemptContent.attachments = [ attachment ]
|
||||
// }
|
||||
// }
|
||||
|
||||
do {
|
||||
let image = createImage(for: "M2.3")
|
||||
let imageData = try NotificationServiceImageDownloader.shared.storeImage(image)
|
||||
let imageAttachment = try UNNotificationAttachment(
|
||||
identifier: "image",
|
||||
url: imageData.localUrl,
|
||||
options: nil)
|
||||
bestAttemptContent.attachments = [imageAttachment]
|
||||
bestAttemptContent.title = bestAttemptContent.title + " [IMG]"
|
||||
} catch {
|
||||
bestAttemptContent.title = bestAttemptContent.title + " [ROTTO]"
|
||||
}
|
||||
|
||||
// remove same type posted notification
|
||||
@@ -209,4 +223,145 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
private func createImage(
|
||||
for magnitude: String
|
||||
) -> UIImage {
|
||||
let frame = CGRect(x: 0, y: 0, width: 200, height: 200)
|
||||
let renderer = UIGraphicsImageRenderer(size: frame.size)
|
||||
let image = renderer.image { ctx in
|
||||
ctx.cgContext.setFillColor(UIColor.white.cgColor)
|
||||
ctx.cgContext.setStrokeColor(UIColor.black.cgColor) // dark
|
||||
ctx.cgContext.setLineWidth(1.0)
|
||||
|
||||
let rectXPadding: CGFloat = 5.0
|
||||
let rectYPadding: CGFloat = 40.0
|
||||
let rectWidth = frame.width - 2*rectXPadding
|
||||
let rectHeight = frame.height - 2*rectYPadding
|
||||
let rectFrame = CGRect(x: rectXPadding, y: rectYPadding, width: rectWidth, height: rectHeight)
|
||||
ctx.cgContext.addRect(rectFrame)
|
||||
ctx.cgContext.drawPath(using: .fillStroke)
|
||||
|
||||
// text
|
||||
let paragraphStyle = NSMutableParagraphStyle()
|
||||
paragraphStyle.alignment = .center
|
||||
let attrs = [
|
||||
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 60.0, weight: .bold),
|
||||
NSAttributedString.Key.paragraphStyle: paragraphStyle,
|
||||
NSAttributedString.Key.foregroundColor: UIColor.blue
|
||||
]
|
||||
|
||||
ctx.cgContext.setStrokeColor(UIColor.blue.cgColor)
|
||||
|
||||
let textMargin: CGFloat = 5.0
|
||||
let textWidth = rectFrame.width - 2*textMargin
|
||||
let textHeight: CGFloat = 60.0
|
||||
let xPos = rectFrame.minX + textMargin
|
||||
let yPos = rectFrame.minY + (rectFrame.height - textHeight) / 2.0
|
||||
let textFrame = CGRect(x: xPos, y: yPos, width: textWidth, height: textHeight)
|
||||
magnitude.draw(with: textFrame, options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
|
||||
}
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NotificationServiceImageDownloader {
|
||||
|
||||
enum DownloadError: Error {
|
||||
case invalidUrl
|
||||
case emptyData
|
||||
case invalidImage
|
||||
}
|
||||
|
||||
struct Image {
|
||||
let data: Data
|
||||
let png: UIImage
|
||||
let localUrl: URL
|
||||
}
|
||||
|
||||
|
||||
static let shared = NotificationServiceImageDownloader()
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func downloadAndStoreImage(
|
||||
for stringUrl: String
|
||||
) async throws -> Image {
|
||||
guard let url = URL(string: stringUrl) else {
|
||||
throw DownloadError.invalidUrl
|
||||
}
|
||||
return try await downloadAndStoreImage(for: url)
|
||||
}
|
||||
|
||||
func downloadAndStoreImage(
|
||||
for url: URL
|
||||
) async throws -> Image {
|
||||
// download image from URL
|
||||
let (data, _) = try await URLSession.shared.data(from: url)
|
||||
guard let image = UIImage(data: data) else {
|
||||
throw DownloadError.invalidImage
|
||||
}
|
||||
|
||||
let identifier = "\(UUID().uuidString).\(url.pathExtension)"
|
||||
let localUrl = try saveImageLocally(image: image, with: identifier)
|
||||
return .init(data: data, png: image, localUrl: localUrl)
|
||||
|
||||
}
|
||||
|
||||
func storeImage(
|
||||
_ image: UIImage
|
||||
) throws -> Image {
|
||||
let identifier = "\(UUID().uuidString).png"
|
||||
let localUrl = try saveImageLocally(image: image, with: identifier)
|
||||
return .init(data: Data(), png: image, localUrl: localUrl)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func saveImageLocally(
|
||||
image: UIImage,
|
||||
with identifier: String
|
||||
) throws -> URL {
|
||||
guard let imageData = image.pngData() else {
|
||||
throw DownloadError.invalidImage
|
||||
}
|
||||
// create a subfolder in Caches directory and
|
||||
// store the given image
|
||||
let cacheDirectory = try FileManager.default.createSubfolder(in: .cachesDirectory, name: "NotificationImages")
|
||||
let fileURL = cacheDirectory.appendingPathComponent(identifier)
|
||||
|
||||
try imageData.write(to: fileURL)
|
||||
return fileURL
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public extension FileManager {
|
||||
|
||||
/// Check if a subfolder already exists in a search path directory. If the folder does not exists, it will be created.
|
||||
/// - Parameters:
|
||||
/// - directory: The search path directory
|
||||
/// - name: Name of the subfolder
|
||||
/// - Returns: URL that specifies the directory
|
||||
func createSubfolder(in directory: FileManager.SearchPathDirectory, name: String) throws -> URL {
|
||||
let searchPathDirectory = urls(for: directory, in: .userDomainMask).first!
|
||||
return try createSubfolder(at: searchPathDirectory, name: name)
|
||||
}
|
||||
|
||||
/// Check if a subfolder already exists at a given URL. If the folder does not exists, it will be created.
|
||||
/// - Parameters:
|
||||
/// - directory: The search path directory
|
||||
/// - name: Name of the subfolder
|
||||
/// - Returns: URL that specifies the directory
|
||||
func createSubfolder(at url: URL, name: String) throws -> URL {
|
||||
let directoryUrl = url.appendingPathComponent(name)
|
||||
|
||||
var isDirectory: ObjCBool = false
|
||||
if !fileExists(atPath: directoryUrl.path, isDirectory: &isDirectory) {
|
||||
try createDirectory(at: directoryUrl, withIntermediateDirectories: false)
|
||||
}
|
||||
|
||||
return directoryUrl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 52;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -13,10 +13,10 @@
|
||||
650247122A61832F001AC512 /* EQNBackgroundPositionDebugHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650247112A61832F001AC512 /* EQNBackgroundPositionDebugHelper.swift */; };
|
||||
650247152A618D7F001AC512 /* Foundation+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650247142A618D7F001AC512 /* Foundation+Extensions.swift */; };
|
||||
650B23AB2632CCD3007AE752 /* UIView+EQNExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650B23AA2632CCD3007AE752 /* UIView+EQNExtensions.swift */; };
|
||||
65172F532C25C496006D2A5C /* EQNSeismicAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65172F522C25C496006D2A5C /* EQNSeismicAnnotationView.swift */; };
|
||||
651901B925F5358700CAFF20 /* EQNMapAnnotationSeismic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 651901B825F5358700CAFF20 /* EQNMapAnnotationSeismic.swift */; };
|
||||
6525A82625E13FD4008FE0D0 /* SeismicNetworkAdvertiseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6525A82525E13FD4008FE0D0 /* SeismicNetworkAdvertiseTableViewCell.swift */; };
|
||||
652A3C6B2A8A757800719796 /* EQNBackgrounPositionDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652A3C6A2A8A757800719796 /* EQNBackgrounPositionDebugViewController.swift */; };
|
||||
652C37BD26092B3C0068EC3B /* FiltersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652C37BC26092B3C0068EC3B /* FiltersViewModel.swift */; };
|
||||
65355FFF25F38D3300BB57D2 /* SegnalazioniMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65355FFE25F38D3300BB57D2 /* SegnalazioniMapViewController.swift */; };
|
||||
653604E9262348FA00B2B651 /* EQNBaseMapFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653604E8262348FA00B2B651 /* EQNBaseMapFilter.swift */; };
|
||||
653C67E225F3CC2E00FE52AC /* EQNCustomAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */; };
|
||||
@@ -36,13 +36,23 @@
|
||||
65583A05261B83BE00ECA9F9 /* UIKit+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65583A04261B83BE00ECA9F9 /* UIKit+Extensions.swift */; };
|
||||
6562C80725FFA6B100C85273 /* SeismicNetworkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */; };
|
||||
6563DAA42AAF515F0072D309 /* BackgroundTaskIdentifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6563DAA32AAF515F0072D309 /* BackgroundTaskIdentifiable.swift */; };
|
||||
656D138F2C2225560094F597 /* SubscriptionDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656D138E2C2225560094F597 /* SubscriptionDetailsViewController.swift */; };
|
||||
656D13912C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656D13902C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift */; };
|
||||
656E02162C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656E02152C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift */; };
|
||||
656EB9362A15FD16009DADF3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 656EB9382A15FD16009DADF3 /* Localizable.stringsdict */; };
|
||||
656EB9412A16288A009DADF3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 656EB9382A15FD16009DADF3 /* Localizable.stringsdict */; };
|
||||
6586971125F44C26009C0182 /* EQNBlurredCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */; };
|
||||
658BAB7B25FE67930015C454 /* EQNBaseMapRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BAB7A25FE67930015C454 /* EQNBaseMapRepresentable.swift */; };
|
||||
658BC0292859A456009EECAA /* RealtimeAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */; };
|
||||
658BC02B2859A4D3009EECAA /* RealtimeAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BC02A2859A4D3009EECAA /* RealtimeAlertView.swift */; };
|
||||
65AB4A952C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AB4A942C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift */; };
|
||||
65AB4A972C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AB4A962C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift */; };
|
||||
65AB4A992C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AB4A982C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift */; };
|
||||
65AD23CE261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AD23CD261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift */; };
|
||||
65B16E1E2BDFA88D0020527E /* Solar in Frameworks */ = {isa = PBXBuildFile; productRef = 65B16E1D2BDFA88D0020527E /* Solar */; };
|
||||
65B16E222BDFA8ED0020527E /* DZNEmptyDataSet in Frameworks */ = {isa = PBXBuildFile; productRef = 65B16E212BDFA8ED0020527E /* DZNEmptyDataSet */; };
|
||||
65B16E262BDFB2A40020527E /* GoogleMobileAds in Frameworks */ = {isa = PBXBuildFile; productRef = 65B16E252BDFB2A40020527E /* GoogleMobileAds */; };
|
||||
65B16E2A2BDFB39B0020527E /* FacebookCore in Frameworks */ = {isa = PBXBuildFile; productRef = 65B16E292BDFB39B0020527E /* FacebookCore */; };
|
||||
65BBB22C26064BE6005D6CDF /* SegnalazioniLast24HoursCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BBB22B26064BE6005D6CDF /* SegnalazioniLast24HoursCell.swift */; };
|
||||
65CB83432915720400EE1E35 /* EQNUserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65CB83422915720400EE1E35 /* EQNUserData.swift */; };
|
||||
65D409942619BA34008CF356 /* SegnalazioniSendReportCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D409932619BA34008CF356 /* SegnalazioniSendReportCell.swift */; };
|
||||
@@ -50,10 +60,17 @@
|
||||
65D507DC2A85227F005BDC57 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502470C2A612E4A001AC512 /* Constants.swift */; };
|
||||
65D9938A29219DEC00F2B0EB /* UIKit+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65583A04261B83BE00ECA9F9 /* UIKit+Extensions.swift */; };
|
||||
65D9938C2922647800F2B0EB /* AppTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */; };
|
||||
65DB60F02C16F5B100164366 /* SettingsBaseTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DB60EF2C16F5B100164366 /* SettingsBaseTableViewController.swift */; };
|
||||
65DB60F22C16FA3600164366 /* SettingsRealTimeAlertsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DB60F12C16FA3600164366 /* SettingsRealTimeAlertsViewController.swift */; };
|
||||
65DB60F82C1714E100164366 /* EQNSettingUserReportNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DB60F72C1714E100164366 /* EQNSettingUserReportNotification.swift */; };
|
||||
65DB60FA2C17158D00164366 /* SettingsUserReportNotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DB60F92C17158D00164366 /* SettingsUserReportNotificationsViewController.swift */; };
|
||||
65DB60FD2C172C4A00164366 /* EQNSettingRealTimeAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DB60FC2C172C4A00164366 /* EQNSettingRealTimeAlert.swift */; };
|
||||
65DBFB4B25E29DD60041CBA6 /* SeismicNetworksMapDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DBFB4A25E29DD60041CBA6 /* SeismicNetworksMapDetailViewController.swift */; };
|
||||
65DBFB7425E2BBF20041CBA6 /* GADTMediumTemplateView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 65DBFB6F25E2BBF20041CBA6 /* GADTMediumTemplateView.xib */; };
|
||||
65DBFB7525E2BBF20041CBA6 /* GADTMediumTemplateView.m in Sources */ = {isa = PBXBuildFile; fileRef = 65DBFB7125E2BBF20041CBA6 /* GADTMediumTemplateView.m */; };
|
||||
65DBFB7625E2BBF20041CBA6 /* GADTTemplateView.m in Sources */ = {isa = PBXBuildFile; fileRef = 65DBFB7225E2BBF20041CBA6 /* GADTTemplateView.m */; };
|
||||
65E6AC6E2C2DB3B60073F8FE /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = 65E6AC6D2C2DB3B60073F8FE /* FirebaseCrashlytics */; };
|
||||
65E6AC702C2DB3B60073F8FE /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 65E6AC6F2C2DB3B60073F8FE /* FirebaseMessaging */; };
|
||||
65EA58802A60269C0038EE9D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8C10B0BD2281FE7F00125C9F /* Localizable.strings */; };
|
||||
65EA58822A60360D0038EE9D /* EQNRealtimePushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65EA58812A60360D0038EE9D /* EQNRealtimePushNotification.swift */; };
|
||||
65F9B49C2A8CA22800F13260 /* BackgroundTaskManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F9B49B2A8CA22800F13260 /* BackgroundTaskManager.swift */; };
|
||||
@@ -167,13 +184,11 @@
|
||||
65FFDD6C292F70F700EA821B /* alert_sound.wav in Resources */ = {isa = PBXBuildFile; fileRef = DC958D662535788E00D73D4A /* alert_sound.wav */; };
|
||||
8C10B0B92281FE7F00125C9F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8C10B0BD2281FE7F00125C9F /* Localizable.strings */; };
|
||||
8C10B0BB2281FE7F00125C9F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8C10B0BD2281FE7F00125C9F /* Localizable.strings */; };
|
||||
8C14113121ED3E5B00A59729 /* SettingsRealTimeAlertsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C14113021ED3E5B00A59729 /* SettingsRealTimeAlertsViewController.m */; };
|
||||
8C14113721EE502800A59729 /* EQNAllertaSismica.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C14113621EE502800A59729 /* EQNAllertaSismica.m */; };
|
||||
8C465D9A21F653AB00F04673 /* Assets.xcassets in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CBD3DD12149B9AD0070C963 /* Assets.xcassets */; };
|
||||
8C465D9F21F7BE0600F04673 /* Assets.xcassets in Sources */ = {isa = PBXBuildFile; fileRef = 8CBD3DD12149B9AD0070C963 /* Assets.xcassets */; };
|
||||
8C483CAE21FDA53B00259FD2 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C483CAD21FDA53B00259FD2 /* StoreKit.framework */; };
|
||||
8C483CB821FDACD300259FD2 /* IAPHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C483CB721FDACD300259FD2 /* IAPHelper.swift */; };
|
||||
8C483CBC21FDACE500259FD2 /* VersioneProProducts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C483CBB21FDACE500259FD2 /* VersioneProProducts.swift */; };
|
||||
8C483CBC21FDACE500259FD2 /* EQNInAppProducts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C483CBB21FDACE500259FD2 /* EQNInAppProducts.swift */; };
|
||||
8C4DD4F9228237E000AE77ED /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8C4DD4FB228237E000AE77ED /* InfoPlist.strings */; };
|
||||
8C4E343F215012FA008B0D2A /* EQNManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C4E343E215012FA008B0D2A /* EQNManager.m */; };
|
||||
8C4E34422152B5E8008B0D2A /* EQNRilevamento.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C4E34412152B5E8008B0D2A /* EQNRilevamento.m */; };
|
||||
@@ -194,10 +209,6 @@
|
||||
8CBD3DD52149B9AD0070C963 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8CBD3DD32149B9AD0070C963 /* LaunchScreen.storyboard */; };
|
||||
8CBD3DD82149B9AD0070C963 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CBD3DD72149B9AD0070C963 /* main.m */; };
|
||||
8CC2B44F214AC7F8002ED1B2 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CC2B44E214AC7F8002ED1B2 /* CoreMotion.framework */; };
|
||||
8CCE164E21E7BACE00173CD9 /* EQNNotificheSegnalazioniUtente.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCE164D21E7BACE00173CD9 /* EQNNotificheSegnalazioniUtente.m */; };
|
||||
8CCE165121E7BAEC00173CD9 /* EQNNotificheReteSismiche.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCE165021E7BAEC00173CD9 /* EQNNotificheReteSismiche.m */; };
|
||||
8CCE165521EA378800173CD9 /* SettingsUserReportAlertsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCE165421EA378800173CD9 /* SettingsUserReportAlertsViewController.m */; };
|
||||
8CCE165821EB1E0000173CD9 /* SettingsSeismicNetworkAlertsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCE165721EB1E0000173CD9 /* SettingsSeismicNetworkAlertsViewController.m */; };
|
||||
8CF05B57218C93BA0055012B /* EQNUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF05B56218C93BA0055012B /* EQNUtility.m */; };
|
||||
8CF12CD321DE49B600613AC5 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CF12CD221DE49B600613AC5 /* UserNotifications.framework */; };
|
||||
8CF12CD521DE49B600613AC5 /* UserNotificationsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CF12CD421DE49B600613AC5 /* UserNotificationsUI.framework */; };
|
||||
@@ -210,7 +221,6 @@
|
||||
8CF66053214C12DC009F4314 /* EQNMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF66052214C12DC009F4314 /* EQNMath.m */; };
|
||||
8CF66058214C566B009F4314 /* ServerRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF66055214C566A009F4314 /* ServerRequest.m */; };
|
||||
8CF66059214C566B009F4314 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF66056214C566A009F4314 /* Reachability.m */; };
|
||||
C89115902FEA7A0A31514912 /* Pods_Earthquake_Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25A8BFFE29D46740E8A8A7A3 /* Pods_Earthquake_Network.framework */; };
|
||||
DC03BEAB250BC0A60084769B /* EQNRoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC03BEAA250BC0A60084769B /* EQNRoundedButton.swift */; };
|
||||
DC08803F24F5A89000186D97 /* SettingEnableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC08803E24F5A89000186D97 /* SettingEnableTableViewCell.swift */; };
|
||||
DC08804124F5B41400186D97 /* SettingSliderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC08804024F5B41400186D97 /* SettingSliderTableViewCell.swift */; };
|
||||
@@ -218,7 +228,6 @@
|
||||
DC0AE1B92538204100111307 /* EQNSegnalazione.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C593E89217BA2470008B260 /* EQNSegnalazione.m */; };
|
||||
DC0AE1BA2538204100111307 /* EQNPastquakes.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CF4F4DA216D44930057110B /* EQNPastquakes.m */; };
|
||||
DC0E551324F8063300D54270 /* SettingSegmentedTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC0E551224F8063300D54270 /* SettingSegmentedTableViewCell.swift */; };
|
||||
DC27EB2F24F6EBE000ACBFE0 /* SettingsSeismicNetworksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC27EB2E24F6EBE000ACBFE0 /* SettingsSeismicNetworksViewController.swift */; };
|
||||
DC2814302519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC28142F2519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift */; };
|
||||
DC2814382519C56100C1AFF7 /* SeismicNetworksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC2814372519C56100C1AFF7 /* SeismicNetworksViewController.swift */; };
|
||||
DC3B5429257FCBCA00C0B6A5 /* EQNReteSmartphone.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3B5428257FCBCA00C0B6A5 /* EQNReteSmartphone.swift */; };
|
||||
@@ -226,11 +235,9 @@
|
||||
DC3CE50A250EB7A8005A7DD5 /* EQNGenericPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3CE509250EB7A8005A7DD5 /* EQNGenericPickerViewController.swift */; };
|
||||
DC47D1BC252A0C2B004119F6 /* AlertsPastEartquakesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC47D1BB252A0C2B004119F6 /* AlertsPastEartquakesTableViewCell.swift */; };
|
||||
DC4B67612517833F00634277 /* EQNSeismic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4B67602517833F00634277 /* EQNSeismic.swift */; };
|
||||
DC52B8A224FC145500ABEBA6 /* SettingsBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DC52B8A124FC145500ABEBA6 /* SettingsBaseViewController.m */; };
|
||||
DC52B8A524FCCD6900ABEBA6 /* AppTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */; };
|
||||
DC646F27252B694A000AA5FD /* AlertsSeismicNotificationExpandedTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC646F26252B694A000AA5FD /* AlertsSeismicNotificationExpandedTableViewCell.swift */; };
|
||||
DC646F32252B698B000AA5FD /* AlertsSeismicNotificationCompactTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC646F31252B698B000AA5FD /* AlertsSeismicNotificationCompactTableViewCell.swift */; };
|
||||
DC65B391250F243E00251693 /* SeismicSettingsNetworksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC65B390250F243E00251693 /* SeismicSettingsNetworksViewController.swift */; };
|
||||
DC7EEE4A252A11C9004B4A2A /* AlertsSmartphoneNetworkTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7EEE49252A11C9004B4A2A /* AlertsSmartphoneNetworkTableViewCell.swift */; };
|
||||
DC7EEE4F252A1634004B4A2A /* AlertsPriorityServiceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7EEE4E252A1634004B4A2A /* AlertsPriorityServiceTableViewCell.swift */; };
|
||||
DC886A5D24E92D5500F7A5D3 /* EQNBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DC886A5C24E92D5500F7A5D3 /* EQNBaseViewController.m */; };
|
||||
@@ -242,11 +249,9 @@
|
||||
DCA5B6E7252E4BD8002AEC96 /* EQNBaseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA5B6E6252E4BD8002AEC96 /* EQNBaseTableViewCell.swift */; };
|
||||
DCAA913F24F68A1D00145A3D /* SettingMultivaluesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAA913E24F68A1D00145A3D /* SettingMultivaluesTableViewCell.swift */; };
|
||||
DCB28CEE24FB8400001F557E /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB28CED24FB8400001F557E /* SettingsViewController.swift */; };
|
||||
DCB45BC8250E86E100DB2D0C /* SeismicSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB45BC7250E86E100DB2D0C /* SeismicSettingsViewController.swift */; };
|
||||
DCB528212560161C005288E5 /* AlertSimulatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB528202560161C005288E5 /* AlertSimulatorViewController.swift */; };
|
||||
DCBB267A24D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCBB267924D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift */; };
|
||||
DCBB267E24D1EA2000F04559 /* SubscriptionProductTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCBB267D24D1EA2000F04559 /* SubscriptionProductTableViewCell.swift */; };
|
||||
DCBB268024D1ECE200F04559 /* SubscriptionDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCBB267F24D1ECE200F04559 /* SubscriptionDetailViewController.swift */; };
|
||||
DCBB84F0252CFC4600F12633 /* AlertsNoLocationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCBB84EF252CFC4600F12633 /* AlertsNoLocationTableViewCell.swift */; };
|
||||
DCC23DEC24D281CE003A2404 /* SubscriptionsActiveTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC23DEB24D281CE003A2404 /* SubscriptionsActiveTableViewCell.swift */; };
|
||||
DCC23DEF24D28F58003A2404 /* EQNEdgeInsetLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC23DEE24D28F58003A2404 /* EQNEdgeInsetLabel.swift */; };
|
||||
@@ -299,16 +304,14 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
25A8BFFE29D46740E8A8A7A3 /* Pods_Earthquake_Network.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Earthquake_Network.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
40CD2E5581CF2FA3D52F392D /* Pods-Earthquake Network.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Earthquake Network.release.xcconfig"; path = "Pods/Target Support Files/Pods-Earthquake Network/Pods-Earthquake Network.release.xcconfig"; sourceTree = "<group>"; };
|
||||
6502470C2A612E4A001AC512 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
650247112A61832F001AC512 /* EQNBackgroundPositionDebugHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBackgroundPositionDebugHelper.swift; sourceTree = "<group>"; };
|
||||
650247142A618D7F001AC512 /* Foundation+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Foundation+Extensions.swift"; sourceTree = "<group>"; };
|
||||
650B23AA2632CCD3007AE752 /* UIView+EQNExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+EQNExtensions.swift"; sourceTree = "<group>"; };
|
||||
65172F522C25C496006D2A5C /* EQNSeismicAnnotationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNSeismicAnnotationView.swift; sourceTree = "<group>"; };
|
||||
651901B825F5358700CAFF20 /* EQNMapAnnotationSeismic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNMapAnnotationSeismic.swift; sourceTree = "<group>"; };
|
||||
6525A82525E13FD4008FE0D0 /* SeismicNetworkAdvertiseTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkAdvertiseTableViewCell.swift; sourceTree = "<group>"; };
|
||||
652A3C6A2A8A757800719796 /* EQNBackgrounPositionDebugViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBackgrounPositionDebugViewController.swift; sourceTree = "<group>"; };
|
||||
652C37BC26092B3C0068EC3B /* FiltersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersViewModel.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>"; };
|
||||
653B791F2934B6DA00E8FFFB /* EQNNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EQNNotificationService.entitlements; sourceTree = "<group>"; };
|
||||
@@ -324,6 +327,9 @@
|
||||
65583A04261B83BE00ECA9F9 /* UIKit+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKit+Extensions.swift"; sourceTree = "<group>"; };
|
||||
6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkViewModel.swift; sourceTree = "<group>"; };
|
||||
6563DAA32AAF515F0072D309 /* BackgroundTaskIdentifiable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundTaskIdentifiable.swift; sourceTree = "<group>"; };
|
||||
656D138E2C2225560094F597 /* SubscriptionDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionDetailsViewController.swift; sourceTree = "<group>"; };
|
||||
656D13902C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionDetailsTableViewCell.swift; sourceTree = "<group>"; };
|
||||
656E02152C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseContainerTableViewCell.swift; sourceTree = "<group>"; };
|
||||
656EB9372A15FD16009DADF3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
656EB9392A15FD19009DADF3 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ar; path = ar.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
656EB93A2A15FD1B009DADF3 /* hr-HR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "hr-HR"; path = "hr-HR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
@@ -349,10 +355,18 @@
|
||||
65A4D5B126280B61003918E0 /* tr-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "tr-TR"; path = "tr-TR.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
65A4D5B526281126003918E0 /* id-ID */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "id-ID"; path = "id-ID.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
65A4D5B626281126003918E0 /* id-ID */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "id-ID"; path = "id-ID.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
65AB4A942C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSeismicNetworkNotificationsViewController.swift; sourceTree = "<group>"; };
|
||||
65AB4A962C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSeismicNetworkNotificationsFilterViewController.swift; sourceTree = "<group>"; };
|
||||
65AB4A982C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNSettingSeismicNetworkNotification.swift; sourceTree = "<group>"; };
|
||||
65AD23CD261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsDescriptionTableViewCell.swift; sourceTree = "<group>"; };
|
||||
65BBB22B26064BE6005D6CDF /* SegnalazioniLast24HoursCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegnalazioniLast24HoursCell.swift; sourceTree = "<group>"; };
|
||||
65CB83422915720400EE1E35 /* EQNUserData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNUserData.swift; sourceTree = "<group>"; };
|
||||
65D409932619BA34008CF356 /* SegnalazioniSendReportCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegnalazioniSendReportCell.swift; sourceTree = "<group>"; };
|
||||
65DB60EF2C16F5B100164366 /* SettingsBaseTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsBaseTableViewController.swift; sourceTree = "<group>"; };
|
||||
65DB60F12C16FA3600164366 /* SettingsRealTimeAlertsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRealTimeAlertsViewController.swift; sourceTree = "<group>"; };
|
||||
65DB60F72C1714E100164366 /* EQNSettingUserReportNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNSettingUserReportNotification.swift; sourceTree = "<group>"; };
|
||||
65DB60F92C17158D00164366 /* SettingsUserReportNotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsUserReportNotificationsViewController.swift; sourceTree = "<group>"; };
|
||||
65DB60FC2C172C4A00164366 /* EQNSettingRealTimeAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNSettingRealTimeAlert.swift; sourceTree = "<group>"; };
|
||||
65DBFB4A25E29DD60041CBA6 /* SeismicNetworksMapDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworksMapDetailViewController.swift; sourceTree = "<group>"; };
|
||||
65DBFB6F25E2BBF20041CBA6 /* GADTMediumTemplateView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GADTMediumTemplateView.xib; sourceTree = "<group>"; };
|
||||
65DBFB7025E2BBF20041CBA6 /* GADTTemplateView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GADTTemplateView.h; sourceTree = "<group>"; };
|
||||
@@ -472,16 +486,12 @@
|
||||
8C10B0BE2281FE9E00125C9F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
8C10B0BF2281FEA000125C9F /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
8C10B0C42282360900125C9F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
8C14112F21ED3E5B00A59729 /* SettingsRealTimeAlertsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsRealTimeAlertsViewController.h; sourceTree = "<group>"; };
|
||||
8C14113021ED3E5B00A59729 /* SettingsRealTimeAlertsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsRealTimeAlertsViewController.m; sourceTree = "<group>"; };
|
||||
8C14113521EE502800A59729 /* EQNAllertaSismica.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EQNAllertaSismica.h; sourceTree = "<group>"; };
|
||||
8C14113621EE502800A59729 /* EQNAllertaSismica.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EQNAllertaSismica.m; sourceTree = "<group>"; };
|
||||
8C465D9721F6539700F04673 /* Earthquake Network.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = "Earthquake Network.xcodeproj"; sourceTree = "<group>"; };
|
||||
8C483CAD21FDA53B00259FD2 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
|
||||
8C483CB021FDA8C700259FD2 /* Earthquake Network-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Earthquake Network-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
8C483CB621FDACD100259FD2 /* EQNNotificationContent-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "EQNNotificationContent-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
8C483CB721FDACD300259FD2 /* IAPHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IAPHelper.swift; sourceTree = "<group>"; };
|
||||
8C483CBB21FDACE500259FD2 /* VersioneProProducts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersioneProProducts.swift; sourceTree = "<group>"; };
|
||||
8C483CBB21FDACE500259FD2 /* EQNInAppProducts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EQNInAppProducts.swift; sourceTree = "<group>"; };
|
||||
8C4DD4FA228237E000AE77ED /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
8C4DD4FC228237E200AE77ED /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
8C4DD4FD228237E400AE77ED /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
@@ -518,14 +528,6 @@
|
||||
8CBD3DD72149B9AD0070C963 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
8CBD3DDE2149BA300070C963 /* Earthquake Network.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Earthquake Network.entitlements"; sourceTree = "<group>"; };
|
||||
8CC2B44E214AC7F8002ED1B2 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; };
|
||||
8CCE164C21E7BACE00173CD9 /* EQNNotificheSegnalazioniUtente.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EQNNotificheSegnalazioniUtente.h; sourceTree = "<group>"; };
|
||||
8CCE164D21E7BACE00173CD9 /* EQNNotificheSegnalazioniUtente.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EQNNotificheSegnalazioniUtente.m; sourceTree = "<group>"; };
|
||||
8CCE164F21E7BAEC00173CD9 /* EQNNotificheReteSismiche.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EQNNotificheReteSismiche.h; sourceTree = "<group>"; };
|
||||
8CCE165021E7BAEC00173CD9 /* EQNNotificheReteSismiche.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EQNNotificheReteSismiche.m; sourceTree = "<group>"; };
|
||||
8CCE165321EA378800173CD9 /* SettingsUserReportAlertsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsUserReportAlertsViewController.h; sourceTree = "<group>"; };
|
||||
8CCE165421EA378800173CD9 /* SettingsUserReportAlertsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsUserReportAlertsViewController.m; sourceTree = "<group>"; };
|
||||
8CCE165621EB1E0000173CD9 /* SettingsSeismicNetworkAlertsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsSeismicNetworkAlertsViewController.h; sourceTree = "<group>"; };
|
||||
8CCE165721EB1E0000173CD9 /* SettingsSeismicNetworkAlertsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsSeismicNetworkAlertsViewController.m; sourceTree = "<group>"; };
|
||||
8CF05B55218C93BA0055012B /* EQNUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EQNUtility.h; sourceTree = "<group>"; };
|
||||
8CF05B56218C93BA0055012B /* EQNUtility.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EQNUtility.m; sourceTree = "<group>"; };
|
||||
8CF12CD121DE49B600613AC5 /* EQNNotificationContent.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = EQNNotificationContent.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -548,12 +550,10 @@
|
||||
8CF66055214C566A009F4314 /* ServerRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerRequest.m; sourceTree = "<group>"; };
|
||||
8CF66056214C566A009F4314 /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
|
||||
8CF66057214C566B009F4314 /* ServerRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerRequest.h; sourceTree = "<group>"; };
|
||||
C4FB0D7EEA34F8222369E1BB /* Pods-Earthquake Network.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Earthquake Network.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Earthquake Network/Pods-Earthquake Network.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
DC03BEAA250BC0A60084769B /* EQNRoundedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNRoundedButton.swift; sourceTree = "<group>"; };
|
||||
DC08803E24F5A89000186D97 /* SettingEnableTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingEnableTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC08804024F5B41400186D97 /* SettingSliderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingSliderTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC0E551224F8063300D54270 /* SettingSegmentedTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingSegmentedTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC27EB2E24F6EBE000ACBFE0 /* SettingsSeismicNetworksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSeismicNetworksViewController.swift; sourceTree = "<group>"; };
|
||||
DC28142F2519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC2814372519C56100C1AFF7 /* SeismicNetworksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworksViewController.swift; sourceTree = "<group>"; };
|
||||
DC3B5428257FCBCA00C0B6A5 /* EQNReteSmartphone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNReteSmartphone.swift; sourceTree = "<group>"; };
|
||||
@@ -562,12 +562,9 @@
|
||||
DC414C0024CDA09A008D9AE4 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = "<group>"; };
|
||||
DC47D1BB252A0C2B004119F6 /* AlertsPastEartquakesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertsPastEartquakesTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC4B67602517833F00634277 /* EQNSeismic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNSeismic.swift; sourceTree = "<group>"; };
|
||||
DC52B8A024FC145500ABEBA6 /* SettingsBaseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsBaseViewController.h; sourceTree = "<group>"; };
|
||||
DC52B8A124FC145500ABEBA6 /* SettingsBaseViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsBaseViewController.m; sourceTree = "<group>"; };
|
||||
DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTheme.swift; sourceTree = "<group>"; };
|
||||
DC646F26252B694A000AA5FD /* AlertsSeismicNotificationExpandedTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertsSeismicNotificationExpandedTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC646F31252B698B000AA5FD /* AlertsSeismicNotificationCompactTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertsSeismicNotificationCompactTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC65B390250F243E00251693 /* SeismicSettingsNetworksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicSettingsNetworksViewController.swift; sourceTree = "<group>"; };
|
||||
DC7EEE49252A11C9004B4A2A /* AlertsSmartphoneNetworkTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertsSmartphoneNetworkTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC7EEE4E252A1634004B4A2A /* AlertsPriorityServiceTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertsPriorityServiceTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DC886A5B24E92D5500F7A5D3 /* EQNBaseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EQNBaseViewController.h; sourceTree = "<group>"; };
|
||||
@@ -580,11 +577,9 @@
|
||||
DCA5B6E6252E4BD8002AEC96 /* EQNBaseTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DCAA913E24F68A1D00145A3D /* SettingMultivaluesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingMultivaluesTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DCB28CED24FB8400001F557E /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
|
||||
DCB45BC7250E86E100DB2D0C /* SeismicSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicSettingsViewController.swift; sourceTree = "<group>"; };
|
||||
DCB528202560161C005288E5 /* AlertSimulatorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertSimulatorViewController.swift; sourceTree = "<group>"; };
|
||||
DCBB267924D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsHeaderTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DCBB267D24D1EA2000F04559 /* SubscriptionProductTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionProductTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DCBB267F24D1ECE200F04559 /* SubscriptionDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionDetailViewController.swift; sourceTree = "<group>"; };
|
||||
DCBB84EF252CFC4600F12633 /* AlertsNoLocationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertsNoLocationTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DCC23DEB24D281CE003A2404 /* SubscriptionsActiveTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsActiveTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DCC23DEE24D28F58003A2404 /* EQNEdgeInsetLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNEdgeInsetLabel.swift; sourceTree = "<group>"; };
|
||||
@@ -619,12 +614,17 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
65B16E222BDFA8ED0020527E /* DZNEmptyDataSet in Frameworks */,
|
||||
65B16E2A2BDFB39B0020527E /* FacebookCore in Frameworks */,
|
||||
65B16E1E2BDFA88D0020527E /* Solar in Frameworks */,
|
||||
65506C052A8F950000AB6448 /* CoreLocation.framework in Frameworks */,
|
||||
65B16E262BDFB2A40020527E /* GoogleMobileAds in Frameworks */,
|
||||
6552C13829262119008E723C /* Shogun in Frameworks */,
|
||||
8C5EA22D21763103002DC156 /* MapKit.framework in Frameworks */,
|
||||
65E6AC6E2C2DB3B60073F8FE /* FirebaseCrashlytics in Frameworks */,
|
||||
8CC2B44F214AC7F8002ED1B2 /* CoreMotion.framework in Frameworks */,
|
||||
65E6AC702C2DB3B60073F8FE /* FirebaseMessaging in Frameworks */,
|
||||
8C483CAE21FDA53B00259FD2 /* StoreKit.framework in Frameworks */,
|
||||
C89115902FEA7A0A31514912 /* Pods_Earthquake_Network.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -688,7 +688,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DC974AFE251748B300A139EC /* SeismicFiltersViewController.swift */,
|
||||
652C37BC26092B3C0068EC3B /* FiltersViewModel.swift */,
|
||||
);
|
||||
path = Filters;
|
||||
sourceTree = "<group>";
|
||||
@@ -841,7 +840,6 @@
|
||||
65FFDC93292F672B00EA821B /* EQNNotificationService */,
|
||||
8CBD3DC32149B9AD0070C963 /* Products */,
|
||||
8CC2B44D214AC7F8002ED1B2 /* Frameworks */,
|
||||
A7982CE92BD5D51B8E2AA92F /* Pods */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -884,7 +882,6 @@
|
||||
8CC2B44E214AC7F8002ED1B2 /* CoreMotion.framework */,
|
||||
8CF12CD221DE49B600613AC5 /* UserNotifications.framework */,
|
||||
8CF12CD421DE49B600613AC5 /* UserNotificationsUI.framework */,
|
||||
25A8BFFE29D46740E8A8A7A3 /* Pods_Earthquake_Network.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -902,15 +899,6 @@
|
||||
path = EQNNotificationContent;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A7982CE92BD5D51B8E2AA92F /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4FB0D7EEA34F8222369E1BB /* Pods-Earthquake Network.debug.xcconfig */,
|
||||
40CD2E5581CF2FA3D52F392D /* Pods-Earthquake Network.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DC10563F251E7EC0002579BB /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -929,8 +917,6 @@
|
||||
6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */,
|
||||
DC28142E2519C21400C1AFF7 /* Cells */,
|
||||
65F0857E2609288E0002615C /* Filters */,
|
||||
DCB45BC7250E86E100DB2D0C /* SeismicSettingsViewController.swift */,
|
||||
DC65B390250F243E00251693 /* SeismicSettingsNetworksViewController.swift */,
|
||||
DC2814372519C56100C1AFF7 /* SeismicNetworksViewController.swift */,
|
||||
DCC76BD7251F56050005C4DC /* SeismicCardSettingsViewController.swift */,
|
||||
65DBFB4A25E29DD60041CBA6 /* SeismicNetworksMapDetailViewController.swift */,
|
||||
@@ -1104,7 +1090,7 @@
|
||||
DC99A50124E66DFB0071BC9F /* Commands */,
|
||||
DCEFF21824F587CC009D3FE1 /* Settings */,
|
||||
65DBFB5225E2A2580041CBA6 /* Map annotation */,
|
||||
8C483CBB21FDACE500259FD2 /* VersioneProProducts.swift */,
|
||||
8C483CBB21FDACE500259FD2 /* EQNInAppProducts.swift */,
|
||||
8C483CB721FDACD300259FD2 /* IAPHelper.swift */,
|
||||
DCF10DC524D2B8C7009F34C3 /* EQNPurchaseUtility.swift */,
|
||||
DCF10DCC24D2C935009F34C3 /* EQNPurchaseAvailability.swift */,
|
||||
@@ -1159,8 +1145,10 @@
|
||||
DC03BEAA250BC0A60084769B /* EQNRoundedButton.swift */,
|
||||
DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */,
|
||||
DCA5B6E6252E4BD8002AEC96 /* EQNBaseTableViewCell.swift */,
|
||||
656E02152C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift */,
|
||||
653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */,
|
||||
6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */,
|
||||
65172F522C25C496006D2A5C /* EQNSeismicAnnotationView.swift */,
|
||||
);
|
||||
path = UI;
|
||||
sourceTree = "<group>";
|
||||
@@ -1170,10 +1158,11 @@
|
||||
children = (
|
||||
DC3BA11024D1A9C90062EE7F /* SubscriptionsViewController.swift */,
|
||||
DCC23DEB24D281CE003A2404 /* SubscriptionsActiveTableViewCell.swift */,
|
||||
DCBB267924D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift */,
|
||||
65AD23CD261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift */,
|
||||
DCBB267924D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift */,
|
||||
DCBB267D24D1EA2000F04559 /* SubscriptionProductTableViewCell.swift */,
|
||||
DCBB267F24D1ECE200F04559 /* SubscriptionDetailViewController.swift */,
|
||||
656D138E2C2225560094F597 /* SubscriptionDetailsViewController.swift */,
|
||||
656D13902C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift */,
|
||||
);
|
||||
path = InApp;
|
||||
sourceTree = "<group>";
|
||||
@@ -1183,15 +1172,11 @@
|
||||
children = (
|
||||
DCEFF21124F581F9009D3FE1 /* Cells */,
|
||||
DCB28CED24FB8400001F557E /* SettingsViewController.swift */,
|
||||
DC52B8A024FC145500ABEBA6 /* SettingsBaseViewController.h */,
|
||||
DC52B8A124FC145500ABEBA6 /* SettingsBaseViewController.m */,
|
||||
8CCE165321EA378800173CD9 /* SettingsUserReportAlertsViewController.h */,
|
||||
8CCE165421EA378800173CD9 /* SettingsUserReportAlertsViewController.m */,
|
||||
8CCE165621EB1E0000173CD9 /* SettingsSeismicNetworkAlertsViewController.h */,
|
||||
8CCE165721EB1E0000173CD9 /* SettingsSeismicNetworkAlertsViewController.m */,
|
||||
DC27EB2E24F6EBE000ACBFE0 /* SettingsSeismicNetworksViewController.swift */,
|
||||
8C14112F21ED3E5B00A59729 /* SettingsRealTimeAlertsViewController.h */,
|
||||
8C14113021ED3E5B00A59729 /* SettingsRealTimeAlertsViewController.m */,
|
||||
65DB60EF2C16F5B100164366 /* SettingsBaseTableViewController.swift */,
|
||||
65DB60F92C17158D00164366 /* SettingsUserReportNotificationsViewController.swift */,
|
||||
65AB4A942C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift */,
|
||||
65AB4A962C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift */,
|
||||
65DB60F12C16FA3600164366 /* SettingsRealTimeAlertsViewController.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
@@ -1214,12 +1199,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DCEFF21924F587E3009D3FE1 /* SettingItem.swift */,
|
||||
8CCE164C21E7BACE00173CD9 /* EQNNotificheSegnalazioniUtente.h */,
|
||||
8CCE164D21E7BACE00173CD9 /* EQNNotificheSegnalazioniUtente.m */,
|
||||
8CCE164F21E7BAEC00173CD9 /* EQNNotificheReteSismiche.h */,
|
||||
8CCE165021E7BAEC00173CD9 /* EQNNotificheReteSismiche.m */,
|
||||
8C14113521EE502800A59729 /* EQNAllertaSismica.h */,
|
||||
8C14113621EE502800A59729 /* EQNAllertaSismica.m */,
|
||||
65DB60F72C1714E100164366 /* EQNSettingUserReportNotification.swift */,
|
||||
65AB4A982C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift */,
|
||||
65DB60FC2C172C4A00164366 /* EQNSettingRealTimeAlert.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
@@ -1259,12 +1241,10 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 8CBD3DDB2149B9AD0070C963 /* Build configuration list for PBXNativeTarget "Earthquake Network" */;
|
||||
buildPhases = (
|
||||
566F2B7433267D7429970520 /* [CP] Check Pods Manifest.lock */,
|
||||
8CBD3DBE2149B9AD0070C963 /* Sources */,
|
||||
8CBD3DBF2149B9AD0070C963 /* Frameworks */,
|
||||
8CBD3DC02149B9AD0070C963 /* Resources */,
|
||||
8CADAAA521B98C550044E256 /* Embed Foundation Extensions */,
|
||||
213FE27D012BFA5BA1F850E2 /* [CP] Embed Pods Frameworks */,
|
||||
DCF07F9824D40DB600DCCA63 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
@@ -1276,6 +1256,12 @@
|
||||
name = "Earthquake Network";
|
||||
packageProductDependencies = (
|
||||
6552C13729262119008E723C /* Shogun */,
|
||||
65B16E1D2BDFA88D0020527E /* Solar */,
|
||||
65B16E212BDFA8ED0020527E /* DZNEmptyDataSet */,
|
||||
65B16E252BDFB2A40020527E /* GoogleMobileAds */,
|
||||
65B16E292BDFB39B0020527E /* FacebookCore */,
|
||||
65E6AC6D2C2DB3B60073F8FE /* FirebaseCrashlytics */,
|
||||
65E6AC6F2C2DB3B60073F8FE /* FirebaseMessaging */,
|
||||
);
|
||||
productName = "Earthquake Network";
|
||||
productReference = 8CBD3DC22149B9AD0070C963 /* Earthquake Network.app */;
|
||||
@@ -1356,6 +1342,11 @@
|
||||
mainGroup = 8CBD3DB92149B9AD0070C963;
|
||||
packageReferences = (
|
||||
6552C13629262119008E723C /* XCRemoteSwiftPackageReference "Shogun" */,
|
||||
65B16E1C2BDFA88D0020527E /* XCRemoteSwiftPackageReference "Solar" */,
|
||||
65B16E202BDFA8ED0020527E /* XCRemoteSwiftPackageReference "DZNEmptyDataSet" */,
|
||||
65B16E242BDFB2A40020527E /* XCRemoteSwiftPackageReference "swift-package-manager-google-mobile-ads" */,
|
||||
65B16E282BDFB39B0020527E /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */,
|
||||
65E6AC6C2C2DB3B60073F8FE /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
|
||||
);
|
||||
productRefGroup = 8CBD3DC32149B9AD0070C963 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -1515,74 +1506,6 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
213FE27D012BFA5BA1F850E2 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Earthquake Network/Pods-Earthquake Network-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/DZNEmptyDataSet/DZNEmptyDataSet.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCoreExtension/FirebaseCoreExtension.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseCrashlytics/FirebaseCrashlytics.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FirebaseSessions/FirebaseSessions.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/PromisesSwift/Promises.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/Solar/Solar.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FBAEMKit/FBAEMKit.framework/FBAEMKit",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKCoreKit/FBSDKCoreKit.framework/FBSDKCoreKit",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKCoreKit_Basics/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DZNEmptyDataSet.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreExtension.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCrashlytics.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseSessions.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Promises.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Solar.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBAEMKit.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit_Basics.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Earthquake Network/Pods-Earthquake Network-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
566F2B7433267D7429970520 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Earthquake Network-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DCF07F9824D40DB600DCCA63 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1600,7 +1523,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\"${PODS_ROOT}/FirebaseCrashlytics/run\"\n";
|
||||
shellScript = "${BUILD_DIR%Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run\n\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
@@ -1624,13 +1547,8 @@
|
||||
DC3B5429257FCBCA00C0B6A5 /* EQNReteSmartphone.swift in Sources */,
|
||||
DCC23DEF24D28F58003A2404 /* EQNEdgeInsetLabel.swift in Sources */,
|
||||
DCF0188F252F09C500C783F0 /* EQNUtility+Extensions.swift in Sources */,
|
||||
8CCE165121E7BAEC00173CD9 /* EQNNotificheReteSismiche.m in Sources */,
|
||||
DC52B8A224FC145500ABEBA6 /* SettingsBaseViewController.m in Sources */,
|
||||
DC2814382519C56100C1AFF7 /* SeismicNetworksViewController.swift in Sources */,
|
||||
8CF4F4DB216D44930057110B /* EQNPastquakes.m in Sources */,
|
||||
8CCE165821EB1E0000173CD9 /* SettingsSeismicNetworkAlertsViewController.m in Sources */,
|
||||
8CCE165521EA378800173CD9 /* SettingsUserReportAlertsViewController.m in Sources */,
|
||||
DCBB268024D1ECE200F04559 /* SubscriptionDetailViewController.swift in Sources */,
|
||||
DCC76BE4251F69FB0005C4DC /* EQNUserDefaultsCommand.swift in Sources */,
|
||||
DC4B67612517833F00634277 /* EQNSeismic.swift in Sources */,
|
||||
6544416B25E9599000C41714 /* EQNDebugViewController.swift in Sources */,
|
||||
@@ -1643,18 +1561,15 @@
|
||||
65DBFB7525E2BBF20041CBA6 /* GADTMediumTemplateView.m in Sources */,
|
||||
DC03BEAB250BC0A60084769B /* EQNRoundedButton.swift in Sources */,
|
||||
65AD23CE261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift in Sources */,
|
||||
8CCE164E21E7BACE00173CD9 /* EQNNotificheSegnalazioniUtente.m in Sources */,
|
||||
DCD4571C24F6CF0D00B58304 /* EQNGenericValue.swift in Sources */,
|
||||
8C4E343F215012FA008B0D2A /* EQNManager.m in Sources */,
|
||||
DCAA913F24F68A1D00145A3D /* SettingMultivaluesTableViewCell.swift in Sources */,
|
||||
652C37BD26092B3C0068EC3B /* FiltersViewModel.swift in Sources */,
|
||||
DCF9E14F24F6EA07002B6B1D /* EQNSeismicNetwork.swift in Sources */,
|
||||
DC2814302519C24400C1AFF7 /* SeismicNetworkTableViewCell.swift in Sources */,
|
||||
650247122A61832F001AC512 /* EQNBackgroundPositionDebugHelper.swift in Sources */,
|
||||
65CB83432915720400EE1E35 /* EQNUserData.swift in Sources */,
|
||||
654D18C425F93C0600BB6DB0 /* PasquakesMapViewController.swift in Sources */,
|
||||
8C14113721EE502800A59729 /* EQNAllertaSismica.m in Sources */,
|
||||
8C483CBC21FDACE500259FD2 /* VersioneProProducts.swift in Sources */,
|
||||
8C483CBC21FDACE500259FD2 /* EQNInAppProducts.swift in Sources */,
|
||||
8C483CB821FDACD300259FD2 /* IAPHelper.swift in Sources */,
|
||||
6562C80725FFA6B100C85273 /* SeismicNetworkViewModel.swift in Sources */,
|
||||
DCDE0BD924E58CCE00209778 /* EQNMainTabBarController.m in Sources */,
|
||||
@@ -1666,7 +1581,6 @@
|
||||
DC52B8A524FCCD6900ABEBA6 /* AppTheme.swift in Sources */,
|
||||
653C680425F3DF8A00FE52AC /* EQNBaseMapViewController.swift in Sources */,
|
||||
658BC02B2859A4D3009EECAA /* RealtimeAlertView.swift in Sources */,
|
||||
DC27EB2F24F6EBE000ACBFE0 /* SettingsSeismicNetworksViewController.swift in Sources */,
|
||||
8CF66059214C566B009F4314 /* Reachability.m in Sources */,
|
||||
DC886A5D24E92D5500F7A5D3 /* EQNBaseViewController.m in Sources */,
|
||||
8C593E8A217BA2470008B260 /* EQNSegnalazione.m in Sources */,
|
||||
@@ -1676,6 +1590,8 @@
|
||||
6552C1462926DBA1008E723C /* AppPreferences.swift in Sources */,
|
||||
DC08803F24F5A89000186D97 /* SettingEnableTableViewCell.swift in Sources */,
|
||||
652A3C6B2A8A757800719796 /* EQNBackgrounPositionDebugViewController.swift in Sources */,
|
||||
65DB60F02C16F5B100164366 /* SettingsBaseTableViewController.swift in Sources */,
|
||||
65AB4A952C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift in Sources */,
|
||||
6586971125F44C26009C0182 /* EQNBlurredCloseButton.swift in Sources */,
|
||||
8CAFD7C521825E4A00F8BD29 /* EQNSisma.m in Sources */,
|
||||
DCC23DEC24D281CE003A2404 /* SubscriptionsActiveTableViewCell.swift in Sources */,
|
||||
@@ -1685,17 +1601,16 @@
|
||||
DCBB84F0252CFC4600F12633 /* AlertsNoLocationTableViewCell.swift in Sources */,
|
||||
651901B925F5358700CAFF20 /* EQNMapAnnotationSeismic.swift in Sources */,
|
||||
DC99A50324E66E270071BC9F /* EQNCommandProtocol.swift in Sources */,
|
||||
DCB45BC8250E86E100DB2D0C /* SeismicSettingsViewController.swift in Sources */,
|
||||
DCF10DC624D2B8C7009F34C3 /* EQNPurchaseUtility.swift in Sources */,
|
||||
DC0E551324F8063300D54270 /* SettingSegmentedTableViewCell.swift in Sources */,
|
||||
650247152A618D7F001AC512 /* Foundation+Extensions.swift in Sources */,
|
||||
65BBB22C26064BE6005D6CDF /* SegnalazioniLast24HoursCell.swift in Sources */,
|
||||
DC47D1BC252A0C2B004119F6 /* AlertsPastEartquakesTableViewCell.swift in Sources */,
|
||||
654D18C925F93CD700BB6DB0 /* EQNMapAnnotationPastquake.swift in Sources */,
|
||||
65AB4A972C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift in Sources */,
|
||||
DCEFF21724F58569009D3FE1 /* SettingSectionHeaderView.swift in Sources */,
|
||||
8C14113121ED3E5B00A59729 /* SettingsRealTimeAlertsViewController.m in Sources */,
|
||||
65DB60FD2C172C4A00164366 /* EQNSettingRealTimeAlert.swift in Sources */,
|
||||
DCBB267A24D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift in Sources */,
|
||||
DC65B391250F243E00251693 /* SeismicSettingsNetworksViewController.swift in Sources */,
|
||||
65DBFB4B25E29DD60041CBA6 /* SeismicNetworksMapDetailViewController.swift in Sources */,
|
||||
DC08804124F5B41400186D97 /* SettingSliderTableViewCell.swift in Sources */,
|
||||
658BC0292859A456009EECAA /* RealtimeAlertViewController.swift in Sources */,
|
||||
@@ -1704,23 +1619,31 @@
|
||||
65F9B4A02A8CC58200F13260 /* UpdateUserLocationTask.swift in Sources */,
|
||||
8C4E34422152B5E8008B0D2A /* EQNRilevamento.m in Sources */,
|
||||
8C7A3B66225A5EA40045B266 /* NSDictionary+EQNExtensions.m in Sources */,
|
||||
65AB4A992C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift in Sources */,
|
||||
8CF66053214C12DC009F4314 /* EQNMath.m in Sources */,
|
||||
DCF4A54524F8DB8300B17326 /* SettingDateTableViewCell.swift in Sources */,
|
||||
65DB60FA2C17158D00164366 /* SettingsUserReportNotificationsViewController.swift in Sources */,
|
||||
DC7EEE4A252A11C9004B4A2A /* AlertsSmartphoneNetworkTableViewCell.swift in Sources */,
|
||||
DC7EEE4F252A1634004B4A2A /* AlertsPriorityServiceTableViewCell.swift in Sources */,
|
||||
653604E9262348FA00B2B651 /* EQNBaseMapFilter.swift in Sources */,
|
||||
65583A05261B83BE00ECA9F9 /* UIKit+Extensions.swift in Sources */,
|
||||
65DBFB7625E2BBF20041CBA6 /* GADTTemplateView.m in Sources */,
|
||||
8C5EA23D2177B51C002DC156 /* SegnalazioniViewController.m in Sources */,
|
||||
656E02162C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift in Sources */,
|
||||
656D138F2C2225560094F597 /* SubscriptionDetailsViewController.swift in Sources */,
|
||||
653C67E225F3CC2E00FE52AC /* EQNCustomAnnotationView.swift in Sources */,
|
||||
8CF4F4D8216D3A110057110B /* EQNAreaCheck.m in Sources */,
|
||||
8C4E34452152B707008B0D2A /* EQNAccelerometroManager.m in Sources */,
|
||||
65D409942619BA34008CF356 /* SegnalazioniSendReportCell.swift in Sources */,
|
||||
65F9B49C2A8CA22800F13260 /* BackgroundTaskManager.swift in Sources */,
|
||||
656D13912C22371F0094F597 /* SubscriptionDetailsTableViewCell.swift in Sources */,
|
||||
8CBD3DC72149B9AD0070C963 /* AppDelegate.m in Sources */,
|
||||
65172F532C25C496006D2A5C /* EQNSeismicAnnotationView.swift in Sources */,
|
||||
DC974AFF251748B300A139EC /* SeismicFiltersViewController.swift in Sources */,
|
||||
65DB60F22C16FA3600164366 /* SettingsRealTimeAlertsViewController.swift in Sources */,
|
||||
DCB28CEE24FB8400001F557E /* SettingsViewController.swift in Sources */,
|
||||
DCB528212560161C005288E5 /* AlertSimulatorViewController.swift in Sources */,
|
||||
65DB60F82C1714E100164366 /* EQNSettingUserReportNotification.swift in Sources */,
|
||||
6502470D2A612E4A001AC512 /* Constants.swift in Sources */,
|
||||
DCC76BD8251F56050005C4DC /* SeismicCardSettingsViewController.swift in Sources */,
|
||||
650B23AB2632CCD3007AE752 /* UIView+EQNExtensions.swift in Sources */,
|
||||
@@ -1854,7 +1777,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 129;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WJA4MR4CPC;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -1865,13 +1788,13 @@
|
||||
INFOPLIST_FILE = EQNNotificationService/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = EQNNotificationService;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Earthquake Network. All rights reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.7;
|
||||
MARKETING_VERSION = 5.8;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationservice;
|
||||
@@ -1896,20 +1819,20 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 129;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WJA4MR4CPC;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = EQNNotificationService/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = EQNNotificationService;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Earthquake Network. All rights reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.7;
|
||||
MARKETING_VERSION = 5.8;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationservice;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1978,7 +1901,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -2034,7 +1957,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
@@ -2044,7 +1967,6 @@
|
||||
};
|
||||
8CBD3DDC2149B9AD0070C963 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = C4FB0D7EEA34F8222369E1BB /* Pods-Earthquake Network.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
@@ -2052,17 +1974,18 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Earthquake Network/Earthquake Network.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 129;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
||||
GCC_PREFIX_HEADER = "Earthquake Network/Earthquake Network-Prefix.pch";
|
||||
INFOPLIST_FILE = "Earthquake Network/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.7;
|
||||
MARKETING_VERSION = 5.8;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -2084,28 +2007,10 @@
|
||||
"-framework",
|
||||
"\"CoreVideo\"",
|
||||
"-framework",
|
||||
"\"DZNEmptyDataSet\"",
|
||||
"-framework",
|
||||
"\"FBLPromises\"",
|
||||
"-framework",
|
||||
"\"FirebaseCore\"",
|
||||
"-framework",
|
||||
"\"FirebaseCrashlytics\"",
|
||||
"-framework",
|
||||
"\"FirebaseInstallations\"",
|
||||
"-framework",
|
||||
"\"FirebaseMessaging\"",
|
||||
"-framework",
|
||||
"\"Foundation\"",
|
||||
"-framework",
|
||||
"\"GoogleAppMeasurement\"",
|
||||
"-framework",
|
||||
"\"GoogleDataTransport\"",
|
||||
"-framework",
|
||||
"\"GoogleMobileAds\"",
|
||||
"-framework",
|
||||
"\"GoogleUtilities\"",
|
||||
"-framework",
|
||||
"\"MediaPlayer\"",
|
||||
"-framework",
|
||||
"\"MessageUI\"",
|
||||
@@ -2116,8 +2021,6 @@
|
||||
"-framework",
|
||||
"\"Security\"",
|
||||
"-framework",
|
||||
"\"Solar\"",
|
||||
"-framework",
|
||||
"\"StoreKit\"",
|
||||
"-framework",
|
||||
"\"SystemConfiguration\"",
|
||||
@@ -2127,8 +2030,6 @@
|
||||
"\"UserMessagingPlatform\"",
|
||||
"-framework",
|
||||
"\"WebKit\"",
|
||||
"-framework",
|
||||
"\"nanopb\"",
|
||||
"-weak_framework",
|
||||
"\"AdSupport\"",
|
||||
"-weak_framework",
|
||||
@@ -2153,7 +2054,6 @@
|
||||
};
|
||||
8CBD3DDD2149B9AD0070C963 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 40CD2E5581CF2FA3D52F392D /* Pods-Earthquake Network.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
@@ -2161,16 +2061,17 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Earthquake Network/Earthquake Network.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 129;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
||||
GCC_PREFIX_HEADER = "Earthquake Network/Earthquake Network-Prefix.pch";
|
||||
INFOPLIST_FILE = "Earthquake Network/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.7;
|
||||
MARKETING_VERSION = 5.8;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -2192,28 +2093,10 @@
|
||||
"-framework",
|
||||
"\"CoreVideo\"",
|
||||
"-framework",
|
||||
"\"DZNEmptyDataSet\"",
|
||||
"-framework",
|
||||
"\"FBLPromises\"",
|
||||
"-framework",
|
||||
"\"FirebaseCore\"",
|
||||
"-framework",
|
||||
"\"FirebaseCrashlytics\"",
|
||||
"-framework",
|
||||
"\"FirebaseInstallations\"",
|
||||
"-framework",
|
||||
"\"FirebaseMessaging\"",
|
||||
"-framework",
|
||||
"\"Foundation\"",
|
||||
"-framework",
|
||||
"\"GoogleAppMeasurement\"",
|
||||
"-framework",
|
||||
"\"GoogleDataTransport\"",
|
||||
"-framework",
|
||||
"\"GoogleMobileAds\"",
|
||||
"-framework",
|
||||
"\"GoogleUtilities\"",
|
||||
"-framework",
|
||||
"\"MediaPlayer\"",
|
||||
"-framework",
|
||||
"\"MessageUI\"",
|
||||
@@ -2224,8 +2107,6 @@
|
||||
"-framework",
|
||||
"\"Security\"",
|
||||
"-framework",
|
||||
"\"Solar\"",
|
||||
"-framework",
|
||||
"\"StoreKit\"",
|
||||
"-framework",
|
||||
"\"SystemConfiguration\"",
|
||||
@@ -2235,8 +2116,6 @@
|
||||
"\"UserMessagingPlatform\"",
|
||||
"-framework",
|
||||
"\"WebKit\"",
|
||||
"-framework",
|
||||
"\"nanopb\"",
|
||||
"-weak_framework",
|
||||
"\"AdSupport\"",
|
||||
"-weak_framework",
|
||||
@@ -2265,7 +2144,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = EQNNotificationContent/EQNNotificationContent.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 129;
|
||||
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
@@ -2274,13 +2153,13 @@
|
||||
"NOTIFICATION_CONTENT=1",
|
||||
);
|
||||
INFOPLIST_FILE = EQNNotificationContent/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.7;
|
||||
MARKETING_VERSION = 5.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationcontent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Content - Development";
|
||||
@@ -2299,20 +2178,20 @@
|
||||
CODE_SIGN_ENTITLEMENTS = EQNNotificationContent/EQNNotificationContent.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 129;
|
||||
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"ADS_ENABLED=0",
|
||||
"NOTIFICATION_CONTENT=1",
|
||||
);
|
||||
INFOPLIST_FILE = EQNNotificationContent/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.7;
|
||||
MARKETING_VERSION = 5.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationcontent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Content - AppStore";
|
||||
@@ -2373,6 +2252,46 @@
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
65B16E1C2BDFA88D0020527E /* XCRemoteSwiftPackageReference "Solar" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/ceeK/Solar.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 3.0.1;
|
||||
};
|
||||
};
|
||||
65B16E202BDFA8ED0020527E /* XCRemoteSwiftPackageReference "DZNEmptyDataSet" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/dzenbot/DZNEmptyDataSet";
|
||||
requirement = {
|
||||
branch = master;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
65B16E242BDFB2A40020527E /* XCRemoteSwiftPackageReference "swift-package-manager-google-mobile-ads" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/googleads/swift-package-manager-google-mobile-ads.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 11.3.0;
|
||||
};
|
||||
};
|
||||
65B16E282BDFB39B0020527E /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/facebook/facebook-ios-sdk";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 14.1.0;
|
||||
};
|
||||
};
|
||||
65E6AC6C2C2DB3B60073F8FE /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 10.28.1;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
@@ -2386,6 +2305,36 @@
|
||||
package = 6552C13629262119008E723C /* XCRemoteSwiftPackageReference "Shogun" */;
|
||||
productName = Shogun;
|
||||
};
|
||||
65B16E1D2BDFA88D0020527E /* Solar */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 65B16E1C2BDFA88D0020527E /* XCRemoteSwiftPackageReference "Solar" */;
|
||||
productName = Solar;
|
||||
};
|
||||
65B16E212BDFA8ED0020527E /* DZNEmptyDataSet */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 65B16E202BDFA8ED0020527E /* XCRemoteSwiftPackageReference "DZNEmptyDataSet" */;
|
||||
productName = DZNEmptyDataSet;
|
||||
};
|
||||
65B16E252BDFB2A40020527E /* GoogleMobileAds */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 65B16E242BDFB2A40020527E /* XCRemoteSwiftPackageReference "swift-package-manager-google-mobile-ads" */;
|
||||
productName = GoogleMobileAds;
|
||||
};
|
||||
65B16E292BDFB39B0020527E /* FacebookCore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 65B16E282BDFB39B0020527E /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
|
||||
productName = FacebookCore;
|
||||
};
|
||||
65E6AC6D2C2DB3B60073F8FE /* FirebaseCrashlytics */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 65E6AC6C2C2DB3B60073F8FE /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
|
||||
productName = FirebaseCrashlytics;
|
||||
};
|
||||
65E6AC6F2C2DB3B60073F8FE /* FirebaseMessaging */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 65E6AC6C2C2DB3B60073F8FE /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
|
||||
productName = FirebaseMessaging;
|
||||
};
|
||||
65FFDC9D292F682600EA821B /* Shogun */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 6552C13629262119008E723C /* XCRemoteSwiftPackageReference "Shogun" */;
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:Earthquake Network.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"originHash" : "702893df2780e15a380fe3df120a583fefc365501dca7487eaf0c2b967baf71c",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "abseil-cpp-binary",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/abseil-cpp-binary.git",
|
||||
"state" : {
|
||||
"revision" : "748c7837511d0e6a507737353af268484e1745e2",
|
||||
"version" : "1.2024011601.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "app-check",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/app-check.git",
|
||||
"state" : {
|
||||
"revision" : "3b62f154d00019ae29a71e9738800bb6f18b236d",
|
||||
"version" : "10.19.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "dznemptydataset",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/dzenbot/DZNEmptyDataSet",
|
||||
"state" : {
|
||||
"branch" : "master",
|
||||
"revision" : "9bffa69a83a9fa58a14b3cf43cb6dd8a63774179"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "facebook-ios-sdk",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/facebook/facebook-ios-sdk",
|
||||
"state" : {
|
||||
"revision" : "c19607d535864533523d1f437c84035e5fb101cf",
|
||||
"version" : "14.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "firebase-ios-sdk",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/firebase-ios-sdk.git",
|
||||
"state" : {
|
||||
"revision" : "e57841b296d04370ea23580f908881b0ccab17b9",
|
||||
"version" : "10.28.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googleappmeasurement",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||
"state" : {
|
||||
"revision" : "fe727587518729046fc1465625b9afd80b5ab361",
|
||||
"version" : "10.28.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googledatatransport",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||
"state" : {
|
||||
"revision" : "a637d318ae7ae246b02d7305121275bc75ed5565",
|
||||
"version" : "9.4.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googleutilities",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||
"state" : {
|
||||
"revision" : "57a1d307f42df690fdef2637f3e5b776da02aad6",
|
||||
"version" : "7.13.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "grpc-binary",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/grpc-binary.git",
|
||||
"state" : {
|
||||
"revision" : "e9fad491d0673bdda7063a0341fb6b47a30c5359",
|
||||
"version" : "1.62.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "gtm-session-fetcher",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/gtm-session-fetcher.git",
|
||||
"state" : {
|
||||
"revision" : "a2ab612cb980066ee56d90d60d8462992c07f24b",
|
||||
"version" : "3.5.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "interop-ios-for-google-sdks",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
||||
"state" : {
|
||||
"revision" : "2d12673670417654f08f5f90fdd62926dc3a2648",
|
||||
"version" : "100.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "leveldb",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/leveldb.git",
|
||||
"state" : {
|
||||
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
|
||||
"version" : "1.22.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "nanopb",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/nanopb.git",
|
||||
"state" : {
|
||||
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
|
||||
"version" : "2.30910.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "promises",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/promises.git",
|
||||
"state" : {
|
||||
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
|
||||
"version" : "2.4.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "shogun",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/andreabusi-it/Shogun",
|
||||
"state" : {
|
||||
"revision" : "ad890190d6be90f7712c2e56a38ef0937d9f8c1a",
|
||||
"version" : "1.8.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "solar",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/ceeK/Solar.git",
|
||||
"state" : {
|
||||
"revision" : "c2b96f2d5fb7f835b91cefac5e83101f54643901",
|
||||
"version" : "3.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-package-manager-google-mobile-ads",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads.git",
|
||||
"state" : {
|
||||
"revision" : "9ab66e38f5f0c2d02f2b024b1babd880130f19bf",
|
||||
"version" : "11.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-package-manager-google-user-messaging-platform",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git",
|
||||
"state" : {
|
||||
"revision" : "9b68aa69fb508f0274853e226c734151a973c7b7",
|
||||
"version" : "2.4.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-protobuf",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||
"state" : {
|
||||
"revision" : "9f0c76544701845ad98716f3f6a774a892152bcb",
|
||||
"version" : "1.26.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 3
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Earthquake Network.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "shogun",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/andreabusi-it/Shogun",
|
||||
"state" : {
|
||||
"revision" : "c164595fdd5d0771a6a24cbff85a7582f0f07311",
|
||||
"version" : "1.3.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
||||
@@ -11,9 +11,6 @@
|
||||
#import "EQNUser.h"
|
||||
#import "EQNAccelerometroManager.h"
|
||||
#import "EQNManager.h"
|
||||
#import "EQNAllertaSismica.h"
|
||||
#import "EQNNotificheSegnalazioniUtente.h"
|
||||
#import "EQNNotificheReteSismiche.h"
|
||||
#import "EQNMainTabBarController.h"
|
||||
#import "NSDictionary+EQNExtensions.h"
|
||||
|
||||
@@ -152,7 +149,7 @@
|
||||
[self handlePushNotificationWithNotificationContent:content];
|
||||
|
||||
// Change this to your preferred presentation option
|
||||
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);
|
||||
completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner | UNNotificationPresentationOptionSound);
|
||||
}
|
||||
|
||||
// Handle notification messages after display notification is tapped by the user.
|
||||
@@ -213,14 +210,14 @@
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
|
||||
FBSDKSettings.sharedSettings.isAdvertiserTrackingEnabled = YES;
|
||||
[FBSDKSettings.sharedSettings setAdvertiserTrackingEnabled:YES];
|
||||
} else {
|
||||
FBSDKSettings.sharedSettings.isAdvertiserTrackingEnabled = NO;
|
||||
[FBSDKSettings.sharedSettings setAdvertiserTrackingEnabled:NO];
|
||||
}
|
||||
}];
|
||||
});
|
||||
} else {
|
||||
FBSDKSettings.sharedSettings.isAdvertiserTrackingEnabled = YES;
|
||||
[FBSDKSettings.sharedSettings setAdvertiserTrackingEnabled:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,8 +230,7 @@
|
||||
- (void)configureFacebookSDKWithApplication:(UIApplication *)application andOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
[FBSDKApplicationDelegate.sharedInstance application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
[FBSDKSettings.sharedSettings setIsAdvertiserIDCollectionEnabled:YES];
|
||||
[FBSDKSettings.sharedSettings setIsAdvertiserIDCollectionEnabled:YES];
|
||||
[FBSDKSettings.sharedSettings setAdvertiserIDCollectionEnabled:YES];
|
||||
}
|
||||
|
||||
#pragma mark - FIRMessagingDelegate
|
||||
@@ -244,9 +240,9 @@
|
||||
NSLog(@"[Firebase] fcmToken %@", fcmToken);
|
||||
if (EQNUserData.sharedData.isFirstStart) {
|
||||
// save default values for notification settings
|
||||
[EQNAllertaSismica saveDefaultValues];
|
||||
[EQNNotificheSegnalazioniUtente saveDefaultValues];
|
||||
[EQNNotificheReteSismiche saveDefaultValues];
|
||||
[EQNSettingRealTimeAlert saveDefaultValues];
|
||||
[EQNSettingUserReportNotification saveDefaultValues];
|
||||
[EQNSettingSeismicNetworkNotification saveDefaultValues];
|
||||
}
|
||||
|
||||
[EQNUser.defaultUser registerUserIfNeededWithFirebaseToken:fcmToken];
|
||||
|
||||
@@ -21,20 +21,12 @@ extension UserDefaults {
|
||||
static let AllertaSismicaSismiDaNotificare = "NOTIFICHE_ALLERA_SISMICA_SISMI_DA_NOTIFICARE"
|
||||
static let AllertaSismicaRaggioSismiLievi = "NOTIFICHE_ALLERA_SISMICA_RAGGIO_SISMI_LIEVI"
|
||||
static let AllertaSismicaRaggioSismiForti = "NOTIFICHE_ALLERA_SISMICA_RAGGIO_SISMI_FORTI"
|
||||
static let AllertaSismicaImpostaVolume = "NOTIFICHE_ALLERA_SISMICA_IMPOSTA_VOLUME"
|
||||
static let AllertaSismicaTestaAllarma = "NOTIFICHE_ALLERA_SISMICA_TESTA_ALLARME"
|
||||
static let AllertaSismicaAbilitaIntervallo = "NOTIFICHE_ALLERA_SISMICA_ABILITA_INTERVALLO"
|
||||
static let AllertaSismicaOraInizio = "NOTIFICHE_ALLERA_SISMICA_ORA_INIZIO"
|
||||
static let AllertaSismicaOraFine = "NOTIFICHE_ALLERA_SISMICA_ORA_INIZIO"
|
||||
|
||||
// Impostazioni della sezione `Notifiche da reti sismiche`
|
||||
static let NotificheRetiSismicheAbilitato = "NOTIFICHE_ATTIVA_RETI_SISMICHE"
|
||||
static let NotificheRetiSismicheViciniAbilitato = "NOTIFICHE_ATTIVA_RETI_SISMICHE_VICINE"
|
||||
static let NotificheRetiSismicheTerremotiFortiAbilitato = "NOTIFICHE_ATTIVA_RETI_TERREMOTI_FORTI"
|
||||
static let NotificheRetiSismicheDistanzaPosizione = "NOTIFICHE_DISTANZA_POSIZIONE_RETI_SISMICHE"
|
||||
static let NotificheRetiSismicheEnergiaSisma = "NOTIFICHE_ATTIVA_RETI_ENERGIA_SISMI"
|
||||
static let NotificheRetiSismicheEnergiaTerremotiForti = "NOTIFICHE_ATTIVA_RETI_ENERGIA_FORTI"
|
||||
static let NotificheRetiSismicheListaEnti = "NOTIFICHE_ATTIVA_RETI_LISTA_ENTI"
|
||||
static let NotificheRetiSismicheMagnitudoMinima = "NOTIFICHE_ATTIVA_RETI_ENERGIA_SISMI"
|
||||
static let NotificheRetiSismicheDistanzaMassima = "NOTIFICHE_DISTANZA_POSIZIONE_RETI_SISMICHE"
|
||||
static let NotificheRetiSismicheFiltroNotifiche = "NOTIFICHE_FILTRO_NOTIFICHE_RETI_SISMICHE"
|
||||
|
||||
// Impostazioni della sezione `Notifiche segnalazioni utente`
|
||||
static let NotificheSegnalazioniUtenteAbilitato = "NOTIFICHE_SU_ATTIVA_SEGNALAZIONE_UTENTE"
|
||||
@@ -67,19 +59,22 @@ extension UserDefaults {
|
||||
// Migrazioni
|
||||
static let AppMigrationV5_3 = "EQNUserDefaultMigrationV5_3"
|
||||
static let AppMigrationV5_4 = "EQNUserDefaultMigrationV5_4"
|
||||
static let AppMigrationV5_8 = "EQNUserDefaultMigrationV5_8"
|
||||
|
||||
static let SettingsSeismicNetworkNotificationMigrationV5_8 = "EQNUserDefaultSettingsSeismicNetworkNotificationMigrationV5_8"
|
||||
static let SettingsUserReportNotificationMigrationV5_8 = "EQNUserDefaultSettingsUserReportNotificationMigrationV5_8"
|
||||
static let SismicFiltersMigrationV5_8 = "EQNUserDefaultSismicFiltersMigrationV5_8"
|
||||
static let SaveSettingsNotificationMigrationV5_8 = "EQNUserDefaultSaveSettingsNotificationMigrationV5_8"
|
||||
|
||||
// Notifica allerta salvata
|
||||
static let RealTimeAlertPayload = "EQNData.RealtimePushNotificationPayload"
|
||||
static let RealTimeAlertDate = "EQNData.RealtimeAlertDate"
|
||||
|
||||
// Filtri sezioni reti sismiche
|
||||
static let SeismicFilterOption = "EQN_SISMI_TIPOLOGIA_FILTRO"
|
||||
static let SeismicSort = "EQN_SISMI_TIPOLOGIA_ORDINAMENTO"
|
||||
static let SeismicMagnitudoMinima = "EQN_MAGNITUDO_MINIMA"
|
||||
static let SeismicDistanzaMassima = "EQN_DISTANZA_MASSIMA"
|
||||
static let SeismicEtaMassima = "EQN_ETA_MASSIMA"
|
||||
static let SeismicSismiFortiAbilitati = "EQN_SISMI_FORTI_ABILITATI"
|
||||
static let SeismicSismiForti = "EQN_SISMI_FORTI"
|
||||
static let SeismicSismiQualsiasiMagnitudo = "EQN_SISMI_QUALSIASI_MAGNITUDO"
|
||||
static let SeismicModificaImpostazioni = "EQN_SISMI_MODIFICA_IMPOSTAZIONI"
|
||||
}
|
||||
|
||||
extension UserDefaults {
|
||||
@@ -95,4 +90,13 @@ extension UserDefaults {
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func enumObject<T: RawRepresentable>(forKey key: String, or defaultValue: T) -> T {
|
||||
if let rawValue = UserDefaults.standard.object(forKey: key) as? T.RawValue,
|
||||
let value = T.init(rawValue: rawValue) {
|
||||
return value
|
||||
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
@implementation AllerteViewController
|
||||
|
||||
static NSString * const SegueIdentifierPrioritySubscriptions = @"ShowPrioritySubscriptions";
|
||||
|
||||
/// Sections inside the app
|
||||
typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
AllerteTableRowLocationPermission = 0,
|
||||
@@ -104,7 +102,13 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
self.title = [NSLocalizedString(@"tab_network", nil) capitalizedString];
|
||||
self.tableView.estimatedRowHeight = 200.0;
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
|
||||
[self.tableView registerClass:[AlertsSmartphoneNetworkTableViewCell class] forCellReuseIdentifier:@"SmartphoneNetworkCell"];
|
||||
[self.tableView registerClass:[AlertsPriorityServiceTableViewCell class] forCellReuseIdentifier:@"PriorityCell"];
|
||||
[self.tableView registerClass:[AlertsNoLocationTableViewCell class] forCellReuseIdentifier:@"NoLocationCell"];
|
||||
[self.tableView registerClass:[AlertsPastEartquakesTableViewCell class] forCellReuseIdentifier:@"PastEarthquakesCell"];
|
||||
[self.tableView registerClass:[AlertsSeismicNotificationCompactTableViewCell class] forCellReuseIdentifier:@"SeismicNotificationCell"];
|
||||
[self.tableView registerClass:[AlertsPositionDataTableViewCell class] forCellReuseIdentifier:@"PositionDataCell"];
|
||||
|
||||
if (EQNBackgroundPositionDebugHelper.shared.isEnabled) {
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:self action:@selector(backgroundPositionDebugTapped:)];
|
||||
}
|
||||
@@ -265,12 +269,14 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
|
||||
if (tableRow == AllerteTableRowLocationPermission) {
|
||||
AlertsNoLocationTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NoLocationCell" forIndexPath:indexPath];
|
||||
cell.status = CLLocationManager.authorizationStatus;
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[cell updateWith:CLLocationManager.authorizationStatus];
|
||||
return cell;
|
||||
|
||||
} else if (tableRow == AllerteTableRowSismiRilevati) {
|
||||
if (self.isNotificaAttiva) {
|
||||
AlertsSeismicNotificationExpandedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SeismicNotificationExpandedCell" forIndexPath:indexPath];
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
EQNRealtimePushNotification *notification = [EQNRealtimePushNotification storedNotification];
|
||||
cell.notification = notification;
|
||||
|
||||
@@ -292,6 +298,7 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
}
|
||||
|
||||
AlertsSeismicNotificationCompactTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SeismicNotificationCell" forIndexPath:indexPath];
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
|
||||
__weak AllerteViewController *weakSelf = self;
|
||||
cell.onTapAlertTest = ^{
|
||||
@@ -311,8 +318,9 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
|
||||
} else if (tableRow == AllerteTableRowAllertePassate) {
|
||||
AlertsPastEartquakesTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PastEarthquakesCell" forIndexPath:indexPath];
|
||||
cell.smartphoneNetwork = [EQNManager defaultManager].rete_smartphone;
|
||||
cell.onTapMapButton = ^{
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[cell updateWith:[EQNManager defaultManager].rete_smartphone];
|
||||
cell.onTapMap = ^{
|
||||
PasquakesMapViewController *controller = [[PasquakesMapViewController alloc] init];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
};
|
||||
@@ -320,7 +328,8 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
|
||||
} else if (tableRow == AllerteTableRowReteSmartphone) {
|
||||
AlertsSmartphoneNetworkTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SmartphoneNetworkCell" forIndexPath:indexPath];
|
||||
cell.smartphoneNetwork = [EQNManager defaultManager].rete_smartphone;
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[cell updateWith:[EQNManager defaultManager].rete_smartphone];
|
||||
cell.onTapButton = ^{
|
||||
[self visualizzaCopertura];
|
||||
};
|
||||
@@ -328,12 +337,13 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
|
||||
} else if (tableRow == AllerteTableRowServizioPriorita) {
|
||||
AlertsPriorityServiceTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PriorityCell" forIndexPath:indexPath];
|
||||
cell.smartphoneNetwork = [EQNManager defaultManager].rete_smartphone;
|
||||
[cell updateWith:[EQNManager defaultManager].rete_smartphone];
|
||||
return cell;
|
||||
|
||||
} else if (tableRow == AllerteTableRowDatiPosizione) {
|
||||
AlertsPositionDataTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PositionDataCell" forIndexPath:indexPath];
|
||||
cell.position = [EQNUser defaultUser].lastPosition;
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[cell updateWith:[EQNUser defaultUser].lastPosition];
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -346,9 +356,10 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
|
||||
AllerteTableRow tableRow = [self.tableItems[indexPath.row] integerValue];
|
||||
switch (tableRow) {
|
||||
case AllerteTableRowServizioPriorita:
|
||||
[self performSegueWithIdentifier:SegueIdentifierPrioritySubscriptions sender:nil];
|
||||
break;
|
||||
case AllerteTableRowServizioPriorita: {
|
||||
SubscriptionsViewController *controller = [[SubscriptionsViewController alloc] init];
|
||||
[self.navigationController pushViewController:controller animated:YES];
|
||||
}; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+51
-22
@@ -9,41 +9,70 @@
|
||||
import UIKit
|
||||
import CoreLocation
|
||||
|
||||
class AlertsNoLocationTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
@objc var status: CLAuthorizationStatus = .notDetermined {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
@objc
|
||||
class AlertsNoLocationTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
override var isHeaderVisible: Bool { false }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var messageLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.Colors.red
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var actionButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(title: NSLocalizedString("permission_location_no_background_solve", comment: ""), target: self, action: #selector(solveTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
containerView.addSubview(messageLabel)
|
||||
containerView.addSubview(actionButton)
|
||||
|
||||
messageLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
messageLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
messageLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
actionButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 40.0).isActive = true
|
||||
actionButton.topAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: .cardPadding).isActive = true
|
||||
actionButton.leadingAnchor.constraint(equalTo: messageLabel.leadingAnchor).isActive = true
|
||||
actionButton.trailingAnchor.constraint(equalTo: messageLabel.trailingAnchor).isActive = true
|
||||
actionButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardPadding.negative).isActive = true
|
||||
}
|
||||
|
||||
@IBOutlet private weak var messageLabel: UILabel!
|
||||
@IBOutlet private weak var actionButton: UIButton!
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
actionButton.backgroundColor = AppTheme.Colors.lightGray
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
// MARK: - Public
|
||||
|
||||
private func updateUI() {
|
||||
var message = ""
|
||||
switch status {
|
||||
case .authorizedAlways:
|
||||
message = ""
|
||||
case .authorizedWhenInUse:
|
||||
message = NSLocalizedString("permission_location_no_background", comment: "")
|
||||
default:
|
||||
message = NSLocalizedString("permission_location_no", comment: "")
|
||||
@objc
|
||||
func update(with status: CLAuthorizationStatus) {
|
||||
messageLabel.text = switch status {
|
||||
case .authorizedAlways: ""
|
||||
case .authorizedWhenInUse: NSLocalizedString("permission_location_no_background", comment: "")
|
||||
default: NSLocalizedString("permission_location_no", comment: "")
|
||||
}
|
||||
messageLabel.text = message
|
||||
actionButton.setLocalizedTitle(key: "permission_location_no_background_solve")
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction private func solveTapped(_ sender: UIButton) {
|
||||
@objc private func solveTapped(_ sender: UIButton) {
|
||||
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
|
||||
return
|
||||
}
|
||||
|
||||
UIApplication.shared.open(settingsUrl, options: [:], completionHandler: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+63
-26
@@ -8,50 +8,87 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class AlertsPastEartquakesTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
@objc var smartphoneNetwork: EQNReteSmartphone? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@objc
|
||||
class AlertsPastEartquakesTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
@objc var onTapMapButton: (() -> Void)?
|
||||
@objc var onTapMap: (() -> Void)?
|
||||
|
||||
override var headerText: String { NSLocalizedString("main_past_quakes", comment: "") }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var last24hLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .title3)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
private lazy var from2013Label: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .title3)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var mapButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(mapTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
@IBOutlet private weak var headerLabel: UILabel!
|
||||
@IBOutlet private weak var last24hLabel: UILabel!
|
||||
@IBOutlet private weak var from2013Label: UILabel!
|
||||
@IBOutlet private weak var mapButton: UIButton!
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
containerView.addSubview(last24hLabel)
|
||||
containerView.addSubview(from2013Label)
|
||||
containerView.addSubview(mapButton)
|
||||
|
||||
last24hLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
last24hLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
last24hLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
from2013Label.topAnchor.constraint(equalTo: last24hLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
from2013Label.leadingAnchor.constraint(equalTo: last24hLabel.leadingAnchor).isActive = true
|
||||
from2013Label.trailingAnchor.constraint(equalTo: last24hLabel.trailingAnchor).isActive = true
|
||||
|
||||
mapButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 40.0).isActive = true
|
||||
mapButton.topAnchor.constraint(equalTo: from2013Label.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
mapButton.leadingAnchor.constraint(equalTo: from2013Label.leadingAnchor).isActive = true
|
||||
mapButton.trailingAnchor.constraint(equalTo: from2013Label.trailingAnchor).isActive = true
|
||||
mapButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardPadding.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
headerLabel.text = NSLocalizedString("main_past_quakes", comment: "")
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
last24hLabel.text = NSLocalizedString("main_recent_quakes_initial", comment: "")
|
||||
from2013Label.text = NSLocalizedString("main_total_quakes_initial", comment: "")
|
||||
mapButton.setLocalizedTitle(key: "official_button_map", uppercased: true, emoji: "🗺")
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
guard let smartphoneNetwork = smartphoneNetwork else { return }
|
||||
// MARK: - Public
|
||||
|
||||
@objc
|
||||
func update(with smartphoneNetwork: EQNReteSmartphone?) {
|
||||
guard let smartphoneNetwork else { return }
|
||||
|
||||
last24hLabel.text = String(format: NSLocalizedString("main_recent_quakes", comment: ""), smartphoneNetwork.counterLastDayAlerts)
|
||||
from2013Label.text = String(format: NSLocalizedString("main_total_quakes", comment: ""), smartphoneNetwork.counterTotalAlerts)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func mapTapped(_ sender: UIButton) {
|
||||
onTapMapButton?()
|
||||
@objc private func mapTapped(_ sender: UIButton) {
|
||||
onTapMap?()
|
||||
}
|
||||
}
|
||||
|
||||
+107
-25
@@ -9,20 +9,11 @@
|
||||
import UIKit
|
||||
import Solar
|
||||
|
||||
class AlertsPositionDataTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
@objc var position: CLLocation? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@objc
|
||||
class AlertsPositionDataTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
// MARK: - Internal
|
||||
override var headerText: String { NSLocalizedString("weather_location", comment: "") }
|
||||
|
||||
@IBOutlet private weak var headerLabel: UILabel!
|
||||
@IBOutlet private weak var positionLabel: UILabel!
|
||||
@IBOutlet private weak var sunriseTimeLabel: UILabel!
|
||||
@IBOutlet private weak var sunsetTimeLabel: UILabel!
|
||||
private lazy var dateFormatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .none
|
||||
@@ -30,26 +21,117 @@ class AlertsPositionDataTableViewCell: EQNBaseTableViewCell {
|
||||
return formatter
|
||||
}()
|
||||
|
||||
// MARK: - Private
|
||||
// MARK: - UI
|
||||
|
||||
private func updateUI() {
|
||||
headerLabel.text = NSLocalizedString("weather_location", comment: "")
|
||||
private lazy var positionImage: UIImageView = {
|
||||
let imageView = UIImageView(image: .init(named: "world_old"))
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
|
||||
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var positionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var sunriseImage: UIImageView = {
|
||||
let imageView = UIImageView(image: .init(named: "sunrise"))
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
|
||||
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var sunriseTimeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var sunsetImage: UIImageView = {
|
||||
let imageView = UIImageView(image: .init(named: "sunset"))
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
|
||||
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var sunsetTimeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
return label
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
containerView.addSubview(positionImage)
|
||||
containerView.addSubview(positionLabel)
|
||||
containerView.addSubview(sunriseImage)
|
||||
containerView.addSubview(sunriseTimeLabel)
|
||||
containerView.addSubview(sunsetImage)
|
||||
containerView.addSubview(sunsetTimeLabel)
|
||||
|
||||
positionImage.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
positionImage.centerYAnchor.constraint(equalTo: positionLabel.centerYAnchor).isActive = true
|
||||
positionImage.trailingAnchor.constraint(equalTo: positionLabel.leadingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
positionLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
positionLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
sunriseImage.leadingAnchor.constraint(equalTo: positionImage.leadingAnchor).isActive = true
|
||||
sunriseImage.centerYAnchor.constraint(equalTo: sunriseTimeLabel.centerYAnchor).isActive = true
|
||||
sunriseImage.trailingAnchor.constraint(equalTo: sunriseTimeLabel.leadingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
sunriseTimeLabel.topAnchor.constraint(equalTo: positionLabel.bottomAnchor, constant: .cardVerticalSpacing.x2).isActive = true
|
||||
sunriseTimeLabel.trailingAnchor.constraint(equalTo: positionLabel.trailingAnchor).isActive = true
|
||||
|
||||
sunsetImage.leadingAnchor.constraint(equalTo: sunriseImage.leadingAnchor).isActive = true
|
||||
sunsetImage.centerYAnchor.constraint(equalTo: sunsetTimeLabel.centerYAnchor).isActive = true
|
||||
sunsetImage.trailingAnchor.constraint(equalTo: sunsetTimeLabel.leadingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
sunsetTimeLabel.topAnchor.constraint(equalTo: sunriseTimeLabel.bottomAnchor, constant: .cardVerticalSpacing.x2).isActive = true
|
||||
sunsetTimeLabel.trailingAnchor.constraint(equalTo: sunriseTimeLabel.trailingAnchor).isActive = true
|
||||
sunsetTimeLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardPadding.negative).isActive = true
|
||||
}
|
||||
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
positionLabel.text = "n.d."
|
||||
sunriseTimeLabel.text = "n.d."
|
||||
sunsetTimeLabel.text = "n.d."
|
||||
|
||||
guard let position = position else { return }
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
@objc
|
||||
func update(with position: CLLocation?) {
|
||||
guard let position else { return }
|
||||
|
||||
positionLabel.text = EQNUtility.coordinateString(coordinate: position.coordinate)
|
||||
|
||||
if let solar = Solar(coordinate: position.coordinate) {
|
||||
let timeZone = TimeZone.current.localizedName(for: .generic, locale: .current) ?? TimeZone.current.identifier
|
||||
if let sunrise = solar.sunrise {
|
||||
sunriseTimeLabel.text = dateFormatter.string(from: sunrise) + " \(timeZone)"
|
||||
}
|
||||
if let sunset = solar.sunset {
|
||||
sunsetTimeLabel.text = dateFormatter.string(from: sunset) + " \(timeZone)"
|
||||
}
|
||||
guard let solar = Solar(coordinate: position.coordinate) else { return }
|
||||
let timeZone = TimeZone.current.localizedName(for: .generic, locale: .current) ?? TimeZone.current.identifier
|
||||
if let sunrise = solar.sunrise {
|
||||
sunriseTimeLabel.text = dateFormatter.string(from: sunrise) + " \(timeZone)"
|
||||
}
|
||||
if let sunset = solar.sunset {
|
||||
sunsetTimeLabel.text = dateFormatter.string(from: sunset) + " \(timeZone)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+46
-22
@@ -8,37 +8,61 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class AlertsPriorityServiceTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
@objc var smartphoneNetwork: EQNReteSmartphone? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@objc
|
||||
class AlertsPriorityServiceTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
override var headerText: String { NSLocalizedString("inapp_list", comment: "") }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var descriptionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.Colors.darkGray
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var lastSubscriptionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.Colors.red
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
return label
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
@IBOutlet private weak var headerLabel: UILabel!
|
||||
@IBOutlet private weak var descriptionLabel: UILabel!
|
||||
@IBOutlet private weak var lastSubscriptionLabel: UILabel!
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
containerView.addSubview(descriptionLabel)
|
||||
containerView.addSubview(lastSubscriptionLabel)
|
||||
|
||||
descriptionLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
descriptionLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
descriptionLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
lastSubscriptionLabel.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: .cardVerticalSpacing/2.0).isActive = true
|
||||
lastSubscriptionLabel.leadingAnchor.constraint(equalTo: descriptionLabel.leadingAnchor).isActive = true
|
||||
lastSubscriptionLabel.trailingAnchor.constraint(equalTo: descriptionLabel.trailingAnchor).isActive = true
|
||||
lastSubscriptionLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardPadding.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
headerLabel.text = NSLocalizedString("inapp_list", comment: "")
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
containerView.backgroundColor = AppTheme.Colors.cardBackgroundRed
|
||||
descriptionLabel.text = NSLocalizedString("inapp_adv", comment: "")
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
guard let smartphoneNetwork = smartphoneNetwork else { return }
|
||||
// MARK: - Public
|
||||
|
||||
@objc
|
||||
func update(with smartphoneNetwork: EQNReteSmartphone?) {
|
||||
guard let smartphoneNetwork else { return }
|
||||
|
||||
lastSubscriptionLabel.text = subscriptionText(for: smartphoneNetwork.lastSubscriptionDiff)
|
||||
}
|
||||
|
||||
+77
-19
@@ -9,54 +9,112 @@
|
||||
import UIKit
|
||||
|
||||
|
||||
class AlertsSeismicNotificationCompactTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
@objc
|
||||
class AlertsSeismicNotificationCompactTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
typealias DefaultCompletion = () -> Void
|
||||
|
||||
@objc var onTapAlertTest: DefaultCompletion?
|
||||
@objc var onTapSimulator: DefaultCompletion?
|
||||
@objc var onTapHowItWorks: DefaultCompletion?
|
||||
@objc var onTapShareApp: DefaultCompletion?
|
||||
|
||||
override var isHeaderVisible: Bool { false }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var descriptionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.Colors.green
|
||||
label.font = .preferredFont(forTextStyle: .title3)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
@IBOutlet private weak var descriptionLabel: UILabel!
|
||||
@IBOutlet private weak var testAlertButton: UIButton!
|
||||
@IBOutlet private weak var simulatorAlertButton: UIButton!
|
||||
@IBOutlet private weak var howItWorksAlertButton: UIButton!
|
||||
@IBOutlet private weak var shareAppButton: UIButton!
|
||||
private lazy var testAlertButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(testAlertTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
private lazy var simulatorAlertButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(simulatorTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
private lazy var howItWorksAlertButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(howItWorksTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var shareAppButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(shareAppTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
containerView.addSubview(descriptionLabel)
|
||||
containerView.addSubview(testAlertButton)
|
||||
containerView.addSubview(simulatorAlertButton)
|
||||
containerView.addSubview(howItWorksAlertButton)
|
||||
containerView.addSubview(shareAppButton)
|
||||
|
||||
descriptionLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardPadding).isActive = true
|
||||
descriptionLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
descriptionLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
testAlertButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 40.0).isActive = true
|
||||
simulatorAlertButton.heightAnchor.constraint(equalTo: testAlertButton.heightAnchor).isActive = true
|
||||
howItWorksAlertButton.heightAnchor.constraint(equalTo: testAlertButton.heightAnchor).isActive = true
|
||||
shareAppButton.heightAnchor.constraint(equalTo: testAlertButton.heightAnchor).isActive = true
|
||||
|
||||
testAlertButton.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
testAlertButton.leadingAnchor.constraint(equalTo: descriptionLabel.leadingAnchor).isActive = true
|
||||
testAlertButton.trailingAnchor.constraint(equalTo: simulatorAlertButton.leadingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
simulatorAlertButton.trailingAnchor.constraint(equalTo: descriptionLabel.trailingAnchor).isActive = true
|
||||
simulatorAlertButton.centerYAnchor.constraint(equalTo: testAlertButton.centerYAnchor).isActive = true
|
||||
simulatorAlertButton.widthAnchor.constraint(equalTo: testAlertButton.widthAnchor).isActive = true
|
||||
|
||||
howItWorksAlertButton.topAnchor.constraint(equalTo: testAlertButton.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
howItWorksAlertButton.leadingAnchor.constraint(equalTo: testAlertButton.leadingAnchor).isActive = true
|
||||
howItWorksAlertButton.trailingAnchor.constraint(equalTo: shareAppButton.leadingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
shareAppButton.trailingAnchor.constraint(equalTo: descriptionLabel.trailingAnchor).isActive = true
|
||||
shareAppButton.centerYAnchor.constraint(equalTo: howItWorksAlertButton.centerYAnchor).isActive = true
|
||||
shareAppButton.widthAnchor.constraint(equalTo: howItWorksAlertButton.widthAnchor).isActive = true
|
||||
shareAppButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardPadding.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
containerView.backgroundColor = AppTheme.Colors.cardBackgroundGreen
|
||||
descriptionLabel.text = NSLocalizedString("main_nodetection", comment: "")
|
||||
testAlertButton.setLocalizedTitle(key: "main_alerttest", uppercased: true, emoji: "🚨")
|
||||
simulatorAlertButton.setLocalizedTitle(key: "main_simulator", uppercased: true, emoji: "⏱")
|
||||
howItWorksAlertButton.setLocalizedTitle(key: "main_how_it_work", uppercased: true, emoji: "💡")
|
||||
shareAppButton.setLocalizedTitle(key: "main_share_app", uppercased: true, emoji: "👥")
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction private func testAlertTapped() {
|
||||
@objc private func testAlertTapped(_ sender: UIButton) {
|
||||
onTapAlertTest?()
|
||||
}
|
||||
|
||||
@IBAction private func simulatorTapped() {
|
||||
@objc private func simulatorTapped(_ sender: UIButton) {
|
||||
onTapSimulator?()
|
||||
}
|
||||
|
||||
@IBAction private func howItWorksTapped() {
|
||||
@objc private func howItWorksTapped(_ sender: UIButton) {
|
||||
onTapHowItWorks?()
|
||||
}
|
||||
|
||||
@IBAction private func shareAppTapped() {
|
||||
@objc private func shareAppTapped(_ sender: UIButton) {
|
||||
onTapShareApp?()
|
||||
}
|
||||
}
|
||||
|
||||
+63
-29
@@ -8,48 +8,82 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class AlertsSmartphoneNetworkTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
@objc var smartphoneNetwork: EQNReteSmartphone? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@objc
|
||||
class AlertsSmartphoneNetworkTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
@objc var onTapButton: (() -> Void)?
|
||||
|
||||
override var headerText: String { NSLocalizedString("main_network", comment: "") }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var counterLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.Colors.green
|
||||
label.font = .preferredFont(forTextStyle: .largeTitle)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var descriptionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coverageButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(localCovergeTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
@IBOutlet private weak var headerLabel: UILabel!
|
||||
@IBOutlet private weak var smartphoneCounterLabel: UILabel!
|
||||
@IBOutlet private weak var coverageDescriptionLabel: UILabel!
|
||||
@IBOutlet private weak var localCoverageButton: UIButton!
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
containerView.addSubview(counterLabel)
|
||||
containerView.addSubview(descriptionLabel)
|
||||
containerView.addSubview(coverageButton)
|
||||
|
||||
counterLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
counterLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
counterLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
descriptionLabel.topAnchor.constraint(equalTo: counterLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
descriptionLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
descriptionLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
coverageButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 40.0).isActive = true
|
||||
coverageButton.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
coverageButton.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
coverageButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
coverageButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardPadding.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
headerLabel.text = NSLocalizedString("main_network", comment: "")
|
||||
coverageDescriptionLabel.text = NSLocalizedString("main_monitoring_currently2", comment: "")
|
||||
localCoverageButton.setLocalizedTitle(key: "main_coverage", uppercased: true, emoji: "🗺")
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
coverageButton.setLocalizedTitle(key: "main_coverage", uppercased: true, emoji: "🗺")
|
||||
descriptionLabel.text = NSLocalizedString("main_monitoring_currently2", comment: "")
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
guard let smartphoneNetwork = smartphoneNetwork else { return }
|
||||
|
||||
smartphoneCounterLabel.text = "\(smartphoneNetwork.counterSmartphones)"
|
||||
// MARK: - Public
|
||||
|
||||
@objc
|
||||
func update(with smartphoneNetwork: EQNReteSmartphone?) {
|
||||
guard let smartphoneNetwork else { return }
|
||||
counterLabel.text = "\(smartphoneNetwork.counterSmartphones)"
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction private func localCovergeTapped(_ sender: UIButton) {
|
||||
@objc private func localCovergeTapped(_ sender: UIButton) {
|
||||
onTapButton?()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,8 +98,8 @@ class PasquakesMapViewController: EQNBaseMapViewController {
|
||||
.first
|
||||
|
||||
// controlliamo che sia inferiore al raggio massimo impostato per le notifiche
|
||||
if let radiusLow = Double(EQNAllertaSismica.shared().raggioSismiLievi),
|
||||
let radiusStrong = Double(EQNAllertaSismica.shared().raggioSismiForti),
|
||||
if let radiusLow = Double(EQNSettingRealTimeAlert.shared.raggioSismiLievi),
|
||||
let radiusStrong = Double(EQNSettingRealTimeAlert.shared.raggioSismiForti),
|
||||
let nearestPastquake = nearestPastquake {
|
||||
let radius = max(radiusLow, radiusStrong)
|
||||
if abs(nearestPastquake.coordinate.distance(from: userPosition)) < radius {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#import "EQNMainTabBarController.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "EQNBaseViewController.h"
|
||||
#import "SettingsBaseViewController.h"
|
||||
#import "EQNManager.h"
|
||||
#import "ServerRequest.h"
|
||||
|
||||
@@ -20,9 +19,6 @@
|
||||
|
||||
@implementation EQNMainTabBarController
|
||||
|
||||
static NSString * const SegueIdentifierSettings = @"ShowSettings";
|
||||
static NSString * const SegueIdentifierLogs = @"ShowLogs";
|
||||
|
||||
#pragma mark - View Lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
@@ -41,6 +37,7 @@ static NSString * const SegueIdentifierLogs = @"ShowLogs";
|
||||
object:nil];
|
||||
|
||||
[self sincronizza];
|
||||
[self migrationV5_8];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
@@ -53,6 +50,23 @@ static NSString * const SegueIdentifierLogs = @"ShowLogs";
|
||||
self.tabBar.items[EQNTabBarSectionImpostazioni].title = [NSLocalizedString(@"drawer_main_settings", comment: "") capitalizedString];
|
||||
}
|
||||
|
||||
- (void)migrationV5_8
|
||||
{
|
||||
// forziamo il salvataggio delle impostazioni di notifica, perchè i vari valori devono essere migrati
|
||||
BOOL alreadyMigrated = [NSUserDefaults.standardUserDefaults boolForKey:NSUserDefaults.SaveSettingsNotificationMigrationV5_8];
|
||||
if (alreadyMigrated) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSLog(@"[MIGRATION] perform notification settings save");
|
||||
[SettingsBaseTableViewController saveSettingsWithCompletion:^(BOOL success) {
|
||||
if (success) {
|
||||
NSLog(@"[MIGRATION] settings saved");
|
||||
[NSUserDefaults.standardUserDefaults setBool:true forKey:NSUserDefaults.SaveSettingsNotificationMigrationV5_8];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Notification
|
||||
|
||||
- (void)serverRegistrationFailedNotification:(NSNotification *)notification
|
||||
@@ -119,7 +133,7 @@ static NSString * const SegueIdentifierLogs = @"ShowLogs";
|
||||
// if user switch from settings page, we need to force a settings save
|
||||
UIViewController *controller = [self getTopControllerFromController:tabBarController.selectedViewController];
|
||||
if ([controller isKindOfClass:[SettingsViewController class]]) {
|
||||
[SettingsBaseViewController saveSettings];
|
||||
[SettingsBaseTableViewController saveSettings];
|
||||
}
|
||||
|
||||
return YES;
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
//
|
||||
// SubscriptionDetailViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Busi Andrea on 29/07/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SafariServices
|
||||
import StoreKit
|
||||
|
||||
|
||||
class SubscriptionDetailViewController: UIViewController {
|
||||
|
||||
/// Enable this allows shake to enable the current subscription
|
||||
private static let ShakeToEnableSubscription = false
|
||||
|
||||
var product: SKProduct? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet private weak var containerView: UIView!
|
||||
@IBOutlet private weak var productTitleLabel: UILabel!
|
||||
@IBOutlet private weak var productImageView: UIImageView!
|
||||
@IBOutlet private weak var productDescriptionLabel: UILabel!
|
||||
@IBOutlet private weak var subscriptionDetailsLabel: UILabel!
|
||||
@IBOutlet private weak var openPrivacyButton: UIButton!
|
||||
@IBOutlet private weak var openTermsButton: UIButton!
|
||||
@IBOutlet private weak var purchaseRecapLabel: UILabel!
|
||||
@IBOutlet private weak var productPriceLabel: UILabel!
|
||||
@IBOutlet private weak var purchaseButton: UIButton!
|
||||
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handlePurchaseNotification(_:)),
|
||||
name: .EQNInAppPurchaseDidComplete,
|
||||
object: nil)
|
||||
|
||||
updateUI()
|
||||
setupUI()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupUI() {
|
||||
containerView.eqn_applyShadowAndRoundedCorners()
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
guard let product = product, isViewLoaded else { return }
|
||||
|
||||
productImageView.image = VersioneProProducts.image(for: product.productIdentifier)
|
||||
productTitleLabel.text = product.localizedTitle
|
||||
productDescriptionLabel.text = product.localizedDescription
|
||||
|
||||
var purchaseRecapString = ""
|
||||
var subscriptionDetailsString = ""
|
||||
switch product.productIdentifier {
|
||||
case VersioneProProducts.Identifier.Subscription10kMonthly,
|
||||
VersioneProProducts.Identifier.Subscription100kMonthly:
|
||||
purchaseRecapString = "inapp_monthly_payment"
|
||||
subscriptionDetailsString = "inapp_detail_description"
|
||||
case VersioneProProducts.Identifier.Subscription100kYearly,
|
||||
VersioneProProducts.Identifier.Subscription100kYearlyDiscounted,
|
||||
VersioneProProducts.Identifier.Subscription10kYearly,
|
||||
VersioneProProducts.Identifier.Subscription10kYearlyDiscounted:
|
||||
purchaseRecapString = "inapp_yearly_payment"
|
||||
subscriptionDetailsString = "inapp_detail_description"
|
||||
case VersioneProProducts.Identifier.Subscription10kPerpetual,
|
||||
VersioneProProducts.Identifier.Subscription100kPerpetual:
|
||||
purchaseRecapString = "inapp_lifetime_payment"
|
||||
subscriptionDetailsString = "inapp_lifetime_detail_description"
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
subscriptionDetailsLabel.text = NSLocalizedString(subscriptionDetailsString, comment: "")
|
||||
openPrivacyButton.setTitle(NSLocalizedString("network_pro_privacy_disclaimer", comment: ""), for: .normal)
|
||||
openTermsButton.setTitle(NSLocalizedString("network_pro_terms_conditions", comment: ""), for: .normal)
|
||||
|
||||
purchaseRecapLabel.text = "\(product.localizedDescription), \(NSLocalizedString(purchaseRecapString, comment: ""))"
|
||||
|
||||
priceFormatter.locale = product.priceLocale
|
||||
productPriceLabel.text = priceFormatter.string(from: product.price)
|
||||
purchaseButton.setTitle(NSLocalizedString("inapp_purchase", comment: ""), for: .normal)
|
||||
}
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
@objc func handlePurchaseNotification(_ notification: Notification) {
|
||||
navigationController?.popViewController(animated: true)
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func openExternalLinkTapped(_ sender: UIButton) {
|
||||
var linkUrl: URL?
|
||||
if sender == openPrivacyButton {
|
||||
linkUrl = URL(string: "\(EQNWebsiteAddress)/privacy/")
|
||||
} else if sender == openTermsButton {
|
||||
linkUrl = URL(string: "\(EQNWebsiteAddress)/terms-conditions/")
|
||||
|
||||
}
|
||||
|
||||
if let url = linkUrl {
|
||||
let controller = SFSafariViewController(url: url)
|
||||
present(controller, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func subscribeTapped(_ sender: UIButton) {
|
||||
guard let product = product else { return }
|
||||
|
||||
VersioneProProducts.store.buyProduct(product)
|
||||
}
|
||||
|
||||
// MARK: - Helper
|
||||
|
||||
private var priceFormatter: NumberFormatter = {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.formatterBehavior = .behavior10_4
|
||||
formatter.numberStyle = .currency
|
||||
return formatter
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
extension SubscriptionDetailViewController {
|
||||
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
|
||||
guard let product = product, event?.subtype == .motionShake, Self.ShakeToEnableSubscription else {
|
||||
return
|
||||
}
|
||||
|
||||
let alert = UIAlertController(title: "🧑💻", message: "Please select an action", preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "Reset all purchases", style: .default) { action in
|
||||
EQNPurchaseUtility.resetInAppPurchases()
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "Activate this subscription", style: .default) { action in
|
||||
EQNPurchaseUtility.simulateProPurchase(identifier: product.productIdentifier)
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
|
||||
present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
//
|
||||
// SubscriptionDetailsTableViewCell.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 18/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
class SubscriptionDetailsTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
var onTapPrivacy: () -> Void = { }
|
||||
var onTapTerms: () -> Void = { }
|
||||
var onTapPurchase: () -> Void = { }
|
||||
var onChangePlan: (_ type: EQNInAppProducts.Plan) -> Void = { _ in }
|
||||
|
||||
override var isHeaderVisible: Bool { false }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
lazy var planSegmentedControl: UISegmentedControl = {
|
||||
let control = UISegmentedControl(items: EQNInAppProducts.Plan.allCases.map(\.localizedTitle))
|
||||
control.translatesAutoresizingMaskIntoConstraints = false
|
||||
control.addTarget(self, action: #selector(onChangeSegmentedControl(_:)), for: .valueChanged)
|
||||
return control
|
||||
}()
|
||||
|
||||
lazy var productTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .title1)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var productImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: .init(named: "top_100k"))
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.heightAnchor.constraint(greaterThanOrEqualToConstant: 50.0).isActive = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
lazy var subscriptionDetailsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.textAlignment = .justified
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var openPrivacyButton: UIButton = {
|
||||
let button = UIButton(type: .system)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.addTarget(self, action: #selector(onTapOpenPrivacyButton(_:)), for: .touchUpInside)
|
||||
button.contentHorizontalAlignment = .leading
|
||||
return button
|
||||
}()
|
||||
|
||||
lazy var openTermsButton: UIButton = {
|
||||
let button = UIButton(type: .system)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.addTarget(self, action: #selector(onTapOpenTermsButton(_:)), for: .touchUpInside)
|
||||
button.contentHorizontalAlignment = .leading
|
||||
return button
|
||||
}()
|
||||
|
||||
lazy var purchaseRecapLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .headline)
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var productPriceLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .largeTitle)
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var purchaseButton: UIButton = {
|
||||
let button = UIButton(type: .system)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.addTarget(self, action: #selector(onTapPurchaseButton(_:)), for: .touchUpInside)
|
||||
button.titleLabel?.font = .preferredFont(forTextStyle: .headline)
|
||||
button.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
|
||||
button.backgroundColor = .systemGroupedBackground
|
||||
button.eqn_applyShadowAndRoundedCorners()
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
containerView.addSubview(planSegmentedControl)
|
||||
containerView.addSubview(productTitleLabel)
|
||||
containerView.addSubview(productImageView)
|
||||
containerView.addSubview(subscriptionDetailsLabel)
|
||||
containerView.addSubview(openPrivacyButton)
|
||||
containerView.addSubview(openTermsButton)
|
||||
containerView.addSubview(purchaseRecapLabel)
|
||||
containerView.addSubview(productPriceLabel)
|
||||
containerView.addSubview(purchaseButton)
|
||||
|
||||
let leading: NSLayoutXAxisAnchor = planSegmentedControl.leadingAnchor
|
||||
let trailing: NSLayoutXAxisAnchor = planSegmentedControl.trailingAnchor
|
||||
planSegmentedControl.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
planSegmentedControl.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
planSegmentedControl.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
productTitleLabel.topAnchor.constraint(equalTo: planSegmentedControl.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
productTitleLabel.leadingAnchor.constraint(equalTo: leading, constant: .cardPadding).isActive = true
|
||||
productTitleLabel.trailingAnchor.constraint(equalTo: trailing, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
productImageView.topAnchor.constraint(equalTo: productTitleLabel.bottomAnchor, constant: .cardVerticalSpacing.x2).isActive = true
|
||||
productImageView.leadingAnchor.constraint(equalTo: leading).isActive = true
|
||||
productImageView.trailingAnchor.constraint(equalTo: trailing).isActive = true
|
||||
|
||||
purchaseRecapLabel.topAnchor.constraint(equalTo: productImageView.bottomAnchor, constant: .cardVerticalSpacing.x2).isActive = true
|
||||
purchaseRecapLabel.leadingAnchor.constraint(equalTo: leading).isActive = true
|
||||
purchaseRecapLabel.trailingAnchor.constraint(equalTo: trailing).isActive = true
|
||||
productPriceLabel.topAnchor.constraint(equalTo: purchaseRecapLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
productPriceLabel.leadingAnchor.constraint(equalTo: leading).isActive = true
|
||||
productPriceLabel.trailingAnchor.constraint(equalTo: trailing).isActive = true
|
||||
|
||||
purchaseButton.topAnchor.constraint(equalTo: productPriceLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
purchaseButton.leadingAnchor.constraint(equalTo: leading).isActive = true
|
||||
purchaseButton.trailingAnchor.constraint(equalTo: trailing).isActive = true
|
||||
|
||||
subscriptionDetailsLabel.topAnchor.constraint(equalTo: purchaseButton.bottomAnchor, constant: .cardVerticalSpacing.x2).isActive = true
|
||||
subscriptionDetailsLabel.leadingAnchor.constraint(equalTo: leading).isActive = true
|
||||
subscriptionDetailsLabel.trailingAnchor.constraint(equalTo: trailing).isActive = true
|
||||
|
||||
openPrivacyButton.topAnchor.constraint(equalTo: subscriptionDetailsLabel.bottomAnchor, constant: .cardVerticalSpacing.x2).isActive = true
|
||||
openPrivacyButton.leadingAnchor.constraint(equalTo: leading).isActive = true
|
||||
openPrivacyButton.trailingAnchor.constraint(equalTo: trailing).isActive = true
|
||||
|
||||
openTermsButton.topAnchor.constraint(equalTo: openPrivacyButton.bottomAnchor, constant: .cardPadding).isActive = true
|
||||
openTermsButton.leadingAnchor.constraint(equalTo: leading).isActive = true
|
||||
openTermsButton.trailingAnchor.constraint(equalTo: trailing).isActive = true
|
||||
openTermsButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardVerticalSpacing.x2.negative).isActive = true
|
||||
}
|
||||
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
openPrivacyButton.setTitle(NSLocalizedString("network_pro_privacy_disclaimer", comment: ""), for: .normal)
|
||||
openTermsButton.setTitle(NSLocalizedString("network_pro_terms_conditions", comment: ""), for: .normal)
|
||||
purchaseButton.setTitle(NSLocalizedString("inapp_purchase", comment: ""), for: .normal)
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc private func onTapOpenPrivacyButton(_ sender: UIButton) {
|
||||
onTapPrivacy()
|
||||
}
|
||||
|
||||
@objc private func onTapOpenTermsButton(_ sender: UIButton) {
|
||||
onTapTerms()
|
||||
}
|
||||
|
||||
@objc private func onTapPurchaseButton(_ sender: UIButton) {
|
||||
onTapPurchase()
|
||||
}
|
||||
|
||||
@objc private func onChangeSegmentedControl(_ sender: UISegmentedControl) {
|
||||
let type: EQNInAppProducts.Plan = .from(index: sender.selectedSegmentIndex)
|
||||
onChangePlan(type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension EQNInAppProducts.Plan {
|
||||
var index: Int {
|
||||
switch self {
|
||||
case .monthly: 0
|
||||
case .yearly: 1
|
||||
case .perpetual: 2
|
||||
}
|
||||
}
|
||||
|
||||
static func from(index: Int) -> Self {
|
||||
switch index {
|
||||
case 0: .monthly
|
||||
case 1: .yearly
|
||||
default: .perpetual
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// SubscriptionDetailsViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 18/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import StoreKit
|
||||
import SafariServices
|
||||
import Shogun
|
||||
|
||||
|
||||
class SubscriptionDetailsViewController: UITableViewController {
|
||||
|
||||
/// Enable this allows shake to enable the current subscription
|
||||
private static let ShakeToEnableSubscription = false
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
private let products: [EQNInAppProducts]
|
||||
private var selectedProduct: EQNInAppProducts {
|
||||
didSet {
|
||||
onProductSelected()
|
||||
}
|
||||
}
|
||||
|
||||
private var priceFormatter: NumberFormatter = {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.formatterBehavior = .behavior10_4
|
||||
formatter.numberStyle = .currency
|
||||
return formatter
|
||||
}()
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
init(
|
||||
products: [EQNInAppProducts]
|
||||
) {
|
||||
self.products = products
|
||||
self.selectedProduct = products.first(where: { $0.plan == .monthly }) ?? products.first!
|
||||
super.init(style: .plain)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("Please use init(products:) instead.")
|
||||
}
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
configureUI()
|
||||
addObservers()
|
||||
}
|
||||
|
||||
private func addObservers() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handlePurchaseNotification(_:)),
|
||||
name: .EQNInAppPurchaseDidComplete,
|
||||
object: nil)
|
||||
}
|
||||
|
||||
private func configureUI() {
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 2000.0
|
||||
tableView.separatorStyle = .none
|
||||
tableView.backgroundColor = .systemGroupedBackground
|
||||
tableView.registerCell(for: SubscriptionDetailsTableViewCell.self)
|
||||
}
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
@objc private func handlePurchaseNotification(_ notification: Notification) {
|
||||
navigationController?.popViewController(animated: true)
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate & data source
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
1
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionDetailsTableViewCell.self, for: indexPath)
|
||||
cell.selectionStyle = .none
|
||||
cell.productTitleLabel.text = selectedProduct.product.localizedTitle
|
||||
cell.productImageView.image = selectedProduct.category.image
|
||||
|
||||
var purchaseRecapString = ""
|
||||
var subscriptionDetailsString = ""
|
||||
switch selectedProduct.productIdentifier {
|
||||
case EQNInAppProducts.Identifier.Subscription10kMonthly,
|
||||
EQNInAppProducts.Identifier.Subscription100kMonthly:
|
||||
purchaseRecapString = "inapp_monthly_payment"
|
||||
subscriptionDetailsString = "inapp_detail_description"
|
||||
case EQNInAppProducts.Identifier.Subscription100kYearly,
|
||||
EQNInAppProducts.Identifier.Subscription100kYearlyDiscounted,
|
||||
EQNInAppProducts.Identifier.Subscription10kYearly,
|
||||
EQNInAppProducts.Identifier.Subscription10kYearlyDiscounted:
|
||||
purchaseRecapString = "inapp_yearly_payment"
|
||||
subscriptionDetailsString = "inapp_detail_description"
|
||||
case EQNInAppProducts.Identifier.Subscription10kPerpetual,
|
||||
EQNInAppProducts.Identifier.Subscription100kPerpetual:
|
||||
purchaseRecapString = "inapp_lifetime_payment"
|
||||
subscriptionDetailsString = "inapp_lifetime_detail_description"
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
cell.subscriptionDetailsLabel.text = NSLocalizedString(subscriptionDetailsString, comment: "")
|
||||
cell.onTapPrivacy = { [weak self] in
|
||||
self?.openExternalLink("\(EQNWebsiteAddress)/privacy/")
|
||||
}
|
||||
cell.onTapTerms = { [weak self] in
|
||||
self?.openExternalLink("\(EQNWebsiteAddress)/terms-conditions/")
|
||||
}
|
||||
cell.onTapPurchase = { [weak self] in
|
||||
self?.purchaseSelectedProduct()
|
||||
}
|
||||
cell.onChangePlan = { [weak self] type in
|
||||
if let product = self?.productFromProductType(type) {
|
||||
self?.selectedProduct = product
|
||||
}
|
||||
}
|
||||
cell.planSegmentedControl.selectedSegmentIndex = selectedProduct.plan.index
|
||||
cell.purchaseRecapLabel.text = "\(selectedProduct.product.localizedDescription), \(NSLocalizedString(purchaseRecapString, comment: ""))"
|
||||
cell.productPriceLabel.text = priceFormatter.string(from: selectedProduct.product.price)
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func onProductSelected() {
|
||||
priceFormatter.locale = selectedProduct.product.priceLocale
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
private func openExternalLink(_ stringUrl: String) {
|
||||
if let url = URL(string: stringUrl) {
|
||||
let controller = SFSafariViewController(url: url)
|
||||
present(controller, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func purchaseSelectedProduct() {
|
||||
EQNInAppProducts.store.buyProduct(selectedProduct.product)
|
||||
}
|
||||
|
||||
private func productFromProductType(_ type: EQNInAppProducts.Plan) -> EQNInAppProducts? {
|
||||
let product: EQNInAppProducts?
|
||||
switch type {
|
||||
case .monthly:
|
||||
product = products.first { $0.plan == .monthly }
|
||||
case .yearly:
|
||||
product = products.first { $0.plan == .yearly }
|
||||
case .perpetual:
|
||||
product = products.first { $0.plan == .perpetual }
|
||||
}
|
||||
return product
|
||||
}
|
||||
}
|
||||
|
||||
extension SubscriptionDetailsViewController {
|
||||
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
|
||||
guard event?.subtype == .motionShake, Self.ShakeToEnableSubscription else {
|
||||
return
|
||||
}
|
||||
|
||||
let alert = UIAlertController(title: "🧑💻", message: "Please select an action", preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "Reset all purchases", style: .default) { action in
|
||||
EQNPurchaseUtility.resetInAppPurchases()
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "Activate this subscription", style: .default) { action in
|
||||
EQNPurchaseUtility.simulateProPurchase(identifier: self.selectedProduct.productIdentifier)
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
|
||||
present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
+68
-44
@@ -9,57 +9,81 @@
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
class SubscriptionProductTableViewCell: UITableViewCell {
|
||||
class SubscriptionProductTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
override var isHeaderVisible: Bool { false }
|
||||
override var isRightArrowVisbile: Bool { true }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var productImageView: UIImageView = {
|
||||
let imageView = UIImageView(frame: .zero)
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
return imageView
|
||||
}()
|
||||
|
||||
var product: SKProduct? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
var availability: EQNPurchaseAvailability? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
private lazy var productTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .headline)
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
@IBOutlet private weak var productImageView: UIImageView!
|
||||
@IBOutlet private weak var productTitleLabel: UILabel!
|
||||
@IBOutlet private weak var productDescriptionLabel: UILabel?
|
||||
@IBOutlet private weak var productInfoLabel: UILabel!
|
||||
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
// force an inset to have the same style of EQNBaseTableViewCell
|
||||
override var frame: CGRect {
|
||||
get {
|
||||
return super.frame
|
||||
}
|
||||
set (newFrame) {
|
||||
let inset: CGFloat = 8
|
||||
var frame = newFrame
|
||||
frame.origin.x += inset
|
||||
frame.size.width -= 2 * inset
|
||||
super.frame = frame
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateUI() {
|
||||
guard let product = product else { return }
|
||||
private lazy var productInfoLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.Colors.red
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
productImageView.image = VersioneProProducts.image(for: product.productIdentifier)
|
||||
productTitleLabel.text = product.localizedTitle
|
||||
productDescriptionLabel?.text = product.localizedDescription
|
||||
// MARK: - Internal
|
||||
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
let infoKey = VersioneProProducts.is100kSubscription(for: product.productIdentifier) ? "inapp_available_100k" : "inapp_available_10k"
|
||||
let counter = availability(for: product.productIdentifier)
|
||||
containerView.addSubview(productImageView)
|
||||
containerView.addSubview(productTitleLabel)
|
||||
containerView.addSubview(productInfoLabel)
|
||||
|
||||
productImageView.widthAnchor.constraint(equalToConstant: 80.0).isActive = true
|
||||
productImageView.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
|
||||
|
||||
productTitleLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
productTitleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
productImageView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
productImageView.trailingAnchor.constraint(equalTo: productTitleLabel.leadingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
productImageView.centerYAnchor.constraint(equalTo: productTitleLabel.centerYAnchor).isActive = true
|
||||
|
||||
productInfoLabel.topAnchor.constraint(equalTo: productTitleLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
productInfoLabel.leadingAnchor.constraint(equalTo: productImageView.leadingAnchor).isActive = true
|
||||
productInfoLabel.trailingAnchor.constraint(equalTo: productTitleLabel.trailingAnchor).isActive = true
|
||||
productInfoLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardVerticalSpacing.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func update(
|
||||
category: EQNInAppProducts.Category,
|
||||
availability: EQNPurchaseAvailability?
|
||||
) {
|
||||
productImageView.image = category.image
|
||||
productTitleLabel.text = category.localizedTitle
|
||||
|
||||
let infoKey = category == .top100k ? "inapp_available_100k" : "inapp_available_10k"
|
||||
let counter = availabilityCounter(for: category, availability: availability)
|
||||
productInfoLabel.text = String(format: NSLocalizedString(infoKey, comment: ""), counter)
|
||||
}
|
||||
|
||||
private func availability(for productIdentifier: String) -> Int {
|
||||
if VersioneProProducts.is100kSubscription(for: productIdentifier) {
|
||||
private func availabilityCounter(
|
||||
for category: EQNInAppProducts.Category,
|
||||
availability: EQNPurchaseAvailability?
|
||||
) -> Int {
|
||||
if category == .top100k {
|
||||
return availability?.top100kAvailable ?? 0
|
||||
}
|
||||
return availability?.top10kAvailable ?? 0
|
||||
|
||||
+47
-21
@@ -9,38 +9,64 @@
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
class SubscriptionsActiveTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
var product: SKProduct? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
class SubscriptionsActiveTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
override var headerText: String { NSLocalizedString("inapp_active", comment: "") }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var noSubscriptionsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
@IBOutlet private weak var headerLabel: UILabel!
|
||||
@IBOutlet private weak var noSubscriptionsLabel: UILabel!
|
||||
@IBOutlet private weak var activeSubscriptionImageView: UIImageView!
|
||||
private lazy var activeSubscriptionImageView: UIImageView = {
|
||||
let imageView = UIImageView(frame: .zero)
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
return imageView
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
let stackView = UIStackView(arrangedSubviews: [ activeSubscriptionImageView, noSubscriptionsLabel ])
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.alignment = .center
|
||||
stackView.distribution = .equalSpacing
|
||||
stackView.axis = .vertical
|
||||
containerView.addSubview(stackView)
|
||||
|
||||
activeSubscriptionImageView.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
|
||||
activeSubscriptionImageView.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
|
||||
|
||||
stackView.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
stackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
stackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
stackView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardVerticalSpacing.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
headerLabel.text = NSLocalizedString("inapp_active", comment: "")
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
noSubscriptionsLabel.text = NSLocalizedString("inapp_nosub", comment: "")
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
if let productIdentifier = product?.productIdentifier {
|
||||
// MARK: - Public
|
||||
|
||||
func update(with product: EQNInAppProducts?) {
|
||||
if let product {
|
||||
noSubscriptionsLabel.isHidden = true
|
||||
activeSubscriptionImageView.isHidden = false
|
||||
activeSubscriptionImageView.image = VersioneProProducts.image(for: productIdentifier)
|
||||
activeSubscriptionImageView.image = product.category.image
|
||||
} else {
|
||||
noSubscriptionsLabel.isHidden = false
|
||||
activeSubscriptionImageView.isHidden = true
|
||||
|
||||
+29
-10
@@ -8,21 +8,40 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class SubscriptionsDescriptionTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
@IBOutlet private weak var headerLabel: UILabel!
|
||||
@IBOutlet private weak var descriptionLabel: UILabel!
|
||||
class SubscriptionsDescriptionTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
override var headerText: String { NSLocalizedString("inapp_list", comment: "") }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var descriptionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .justified
|
||||
return label
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
containerView.addSubview(descriptionLabel)
|
||||
|
||||
descriptionLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
descriptionLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
descriptionLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
descriptionLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardVerticalSpacing.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
headerLabel.text = NSLocalizedString("inapp_list", comment: "")
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
descriptionLabel.text = NSLocalizedString("inapp_description", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
+40
-13
@@ -8,26 +8,53 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class SubscriptionsHeaderTableViewCell: UITableViewCell {
|
||||
|
||||
var isLoading = false {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
class SubscriptionsHeaderTableViewCell: UITableViewHeaderFooterView {
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var headerTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = UIFont.preferredFont(forTextStyle: .title2)
|
||||
label.textColor = AppTheme.Colors.darkGray
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var loadingActivityIndicator: UIActivityIndicatorView = {
|
||||
let spinner = UIActivityIndicatorView(style: .medium)
|
||||
spinner.translatesAutoresizingMaskIntoConstraints = false
|
||||
spinner.hidesWhenStopped = true
|
||||
return spinner
|
||||
}()
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
override init(reuseIdentifier: String?) {
|
||||
super.init(reuseIdentifier: reuseIdentifier)
|
||||
setupUI()
|
||||
}
|
||||
|
||||
var title: String? = nil {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
setupUI()
|
||||
}
|
||||
|
||||
@IBOutlet private weak var headerTitleLabel: UILabel!
|
||||
@IBOutlet private weak var loadingActivityIndicator: UIActivityIndicatorView!
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateUI() {
|
||||
private func setupUI() {
|
||||
contentView.addSubview(headerTitleLabel)
|
||||
contentView.addSubview(loadingActivityIndicator)
|
||||
|
||||
headerTitleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
|
||||
headerTitleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
loadingActivityIndicator.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
loadingActivityIndicator.centerYAnchor.constraint(equalTo: headerTitleLabel.centerYAnchor).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func update(isLoading: Bool, title: String?) {
|
||||
headerTitleLabel.text = title
|
||||
|
||||
if isLoading && title != nil {
|
||||
|
||||
@@ -10,38 +10,29 @@ import UIKit
|
||||
import StoreKit
|
||||
import Shogun
|
||||
|
||||
|
||||
@objc
|
||||
class SubscriptionsViewController: UITableViewController {
|
||||
|
||||
private static let SegueIdentifierSubscriptionDetail = "ShowSubscriptionDetail"
|
||||
private static let CellHeightDescription: CGFloat = 320.0
|
||||
|
||||
// sezioni
|
||||
private enum TableSection: CaseIterable {
|
||||
case active
|
||||
case description
|
||||
case monthly
|
||||
case yearly
|
||||
case perpetual
|
||||
case products
|
||||
|
||||
var sectionTitle: String? {
|
||||
switch self {
|
||||
case .monthly: return NSLocalizedString("inapp_monthly_subscriptions", comment: "")
|
||||
case .yearly: return NSLocalizedString("inapp_yearly_subscriptions", comment: "")
|
||||
case .perpetual: return NSLocalizedString("inapp_lifetime_subscriptions", comment: "")
|
||||
default: return nil
|
||||
case .products: NSLocalizedString("subscriptions_available", comment: "")
|
||||
default: nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let sections = TableSection.allCases
|
||||
|
||||
private var allProducts = [SKProduct]()
|
||||
private var monthlyProducts = [SKProduct]()
|
||||
private var yearlyProducts = [SKProduct]()
|
||||
private var perpetualProducts = [SKProduct]()
|
||||
/// All products retrieved from AppStore
|
||||
private var products = [EQNInAppProducts]()
|
||||
/// Product already bought by the user
|
||||
private var subscribedProduct: SKProduct?
|
||||
private var productSubscribed: EQNInAppProducts?
|
||||
/// Availability for subscriptions
|
||||
private var availability: EQNPurchaseAvailability?
|
||||
/// Tells if products are loading
|
||||
@@ -49,6 +40,13 @@ class SubscriptionsViewController: UITableViewController {
|
||||
/// Tells if a restore is in progress
|
||||
private var isRestorePurchase = false
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
@objc
|
||||
convenience init() {
|
||||
self.init(style: .plain)
|
||||
}
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
@@ -64,15 +62,7 @@ class SubscriptionsViewController: UITableViewController {
|
||||
loadData()
|
||||
checkAvailabilities()
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == Self.SegueIdentifierSubscriptionDetail,
|
||||
let controller = segue.destination as? SubscriptionDetailViewController,
|
||||
let product = sender as? SKProduct {
|
||||
controller.product = product
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func addObservers() {
|
||||
@@ -101,64 +91,36 @@ class SubscriptionsViewController: UITableViewController {
|
||||
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(closeTapped(_:)))
|
||||
navigationItem.leftBarButtonItem = doneButton
|
||||
}
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = Self.CellHeightDescription;
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
monthlyProducts.removeAll()
|
||||
yearlyProducts.removeAll()
|
||||
perpetualProducts.removeAll()
|
||||
|
||||
// creates list to show
|
||||
let isDiscountAvailable = checkDiscountPrice()
|
||||
allProducts.forEach { (product) in
|
||||
if isDiscountAvailable {
|
||||
if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kMonthly ||
|
||||
product.productIdentifier == VersioneProProducts.Identifier.Subscription100kMonthly {
|
||||
monthlyProducts.append(product)
|
||||
} else if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kYearlyDiscounted ||
|
||||
product.productIdentifier == VersioneProProducts.Identifier.Subscription100kYearlyDiscounted {
|
||||
yearlyProducts.append(product)
|
||||
}
|
||||
} else {
|
||||
if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kMonthly ||
|
||||
product.productIdentifier == VersioneProProducts.Identifier.Subscription100kMonthly {
|
||||
monthlyProducts.append(product)
|
||||
}
|
||||
else if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kYearly ||
|
||||
product.productIdentifier == VersioneProProducts.Identifier.Subscription100kYearly {
|
||||
yearlyProducts.append(product)
|
||||
}
|
||||
}
|
||||
// perpetual scribuscriptions doesn't have discounted version
|
||||
if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kPerpetual ||
|
||||
product.productIdentifier == VersioneProProducts.Identifier.Subscription100kPerpetual {
|
||||
perpetualProducts.append(product)
|
||||
}
|
||||
}
|
||||
|
||||
tableView.reloadData()
|
||||
tableView.estimatedRowHeight = 600.0
|
||||
tableView.separatorStyle = .none
|
||||
tableView.backgroundColor = .systemGroupedBackground
|
||||
tableView.registerCell(for: SubscriptionsActiveTableViewCell.self)
|
||||
tableView.registerCell(for: SubscriptionsDescriptionTableViewCell.self)
|
||||
tableView.registerCell(for: SubscriptionProductTableViewCell.self)
|
||||
tableView.registerHeaderFooterView(for: SubscriptionsHeaderTableViewCell.self)
|
||||
}
|
||||
|
||||
private func loadData() {
|
||||
isLoading = true
|
||||
|
||||
VersioneProProducts.store.requestProducts{ [weak self] success, products in
|
||||
EQNInAppProducts.store.requestProducts { [weak self] success, storeProducts in
|
||||
self?.isLoading = false
|
||||
|
||||
guard let self = self, let products = products, success == true else { return }
|
||||
guard let self = self, let storeProducts, success == true else { return }
|
||||
|
||||
let products = storeProducts.compactMap { EQNInAppProducts.from(product: $0) }
|
||||
|
||||
let purchased = products.filter { (product) -> Bool in
|
||||
let isPurchased = VersioneProProducts.store.isProductPurchased(product.productIdentifier)
|
||||
let isSubscription = VersioneProProducts.isSubscription(for: product.productIdentifier)
|
||||
let isPurchased = EQNInAppProducts.store.isProductPurchased(product.productIdentifier)
|
||||
let isSubscription = product.isSubscription
|
||||
return isPurchased && isSubscription
|
||||
}
|
||||
self.subscribedProduct = purchased.first
|
||||
self.allProducts = products.sorted(by: { $0.productIdentifier > $1.productIdentifier })
|
||||
|
||||
self.updateUI()
|
||||
self.productSubscribed = purchased.first
|
||||
self.products = products.sorted(by: { $0.productIdentifier > $1.productIdentifier })
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +133,7 @@ class SubscriptionsViewController: UITableViewController {
|
||||
EQNPurchaseUtility.availableSubscriptions { (availability) in
|
||||
DispatchQueue.main.async {
|
||||
self.availability = availability
|
||||
self.updateUI()
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,7 +142,7 @@ class SubscriptionsViewController: UITableViewController {
|
||||
|
||||
@objc func restoreTapped(_ sender: AnyObject) {
|
||||
isRestorePurchase = true
|
||||
VersioneProProducts.store.restorePurchases()
|
||||
EQNInAppProducts.store.restorePurchases()
|
||||
}
|
||||
|
||||
@objc func closeTapped(_ sender: AnyObject) {
|
||||
@@ -190,7 +152,7 @@ class SubscriptionsViewController: UITableViewController {
|
||||
// MARK: - Notifications
|
||||
|
||||
@objc func fail(_ notification: Notification){
|
||||
VersioneProProducts.store.loadPurchase()
|
||||
EQNInAppProducts.store.loadPurchase()
|
||||
}
|
||||
|
||||
@objc func handlePurchaseNotification(_ notification: Notification) {
|
||||
@@ -209,7 +171,7 @@ class SubscriptionsViewController: UITableViewController {
|
||||
present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
VersioneProProducts.store.loadPurchase()
|
||||
EQNInAppProducts.store.loadPurchase()
|
||||
loadData()
|
||||
}
|
||||
|
||||
@@ -228,12 +190,9 @@ class SubscriptionsViewController: UITableViewController {
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let tableSection = sections[section]
|
||||
if let cell = tableView.dequeueReusableCell(withIdentifier: "SectionHeaderCell") as? SubscriptionsHeaderTableViewCell {
|
||||
cell.title = tableSection.sectionTitle
|
||||
cell.isLoading = isLoading
|
||||
return cell
|
||||
}
|
||||
return nil
|
||||
let view = tableView.dequeueHeaderFooterView(cellIdentifiable: SubscriptionsHeaderTableViewCell.self)
|
||||
view.update(isLoading: isLoading, title: tableSection.sectionTitle)
|
||||
return view
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
@@ -249,96 +208,53 @@ class SubscriptionsViewController: UITableViewController {
|
||||
switch tableSection {
|
||||
case .active: return 1
|
||||
case .description: return 1
|
||||
case .monthly,
|
||||
.yearly,
|
||||
.perpetual:
|
||||
return availableProducts(for: tableSection).count
|
||||
case .products: return products.isEmpty ? 0 : 2
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
let tableSection = sections[indexPath.section]
|
||||
if tableSection == .description {
|
||||
// autolayout in description doesn't work 🤷♂️
|
||||
return Self.CellHeightDescription
|
||||
}
|
||||
return UITableView.automaticDimension
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
let tableSection = sections[indexPath.section]
|
||||
if tableSection == .active || tableSection == .description {
|
||||
return
|
||||
}
|
||||
|
||||
// add round borders to first and last row in products cells
|
||||
let cornerRadius = AppTheme.shared.cardCornerRadius
|
||||
var corners: UIRectCorner = []
|
||||
|
||||
if indexPath.row == 0 {
|
||||
corners.update(with: .topLeft)
|
||||
corners.update(with: .topRight)
|
||||
}
|
||||
|
||||
if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
|
||||
corners.update(with: .bottomLeft)
|
||||
corners.update(with: .bottomRight)
|
||||
}
|
||||
|
||||
let maskLayer = CAShapeLayer()
|
||||
maskLayer.path = UIBezierPath(roundedRect: cell.bounds,
|
||||
byRoundingCorners: corners,
|
||||
cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)).cgPath
|
||||
cell.layer.mask = maskLayer
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let tableSection = sections[indexPath.section]
|
||||
if tableSection == .active {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "ActiveSubscriptionsCell", for: indexPath) as! SubscriptionsActiveTableViewCell
|
||||
cell.product = subscribedProduct
|
||||
return cell
|
||||
}
|
||||
if tableSection == .description {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "DescriptionCell", for: indexPath) as! SubscriptionsDescriptionTableViewCell
|
||||
return cell
|
||||
}
|
||||
|
||||
let products = availableProducts(for: tableSection)
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "SubscriptionCell", for: indexPath) as! SubscriptionProductTableViewCell
|
||||
cell.product = products[indexPath.row]
|
||||
cell.availability = availability
|
||||
return cell
|
||||
switch tableSection {
|
||||
case .active:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionsActiveTableViewCell.self, for: indexPath)
|
||||
cell.selectionStyle = .none
|
||||
cell.update(with: productSubscribed)
|
||||
return cell
|
||||
case .description:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionsDescriptionTableViewCell.self, for: indexPath)
|
||||
cell.selectionStyle = .none
|
||||
return cell
|
||||
case .products:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionProductTableViewCell.self, for: indexPath)
|
||||
let category: EQNInAppProducts.Category = switch indexPath.row {
|
||||
case 0: .top10k
|
||||
case 1: .top100k
|
||||
default: .top100k
|
||||
}
|
||||
cell.update(category: category, availability: availability)
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
let tableSection = sections[indexPath.section]
|
||||
let products = availableProducts(for: tableSection)
|
||||
let products = availableProducts(for: indexPath)
|
||||
if !products.isEmpty {
|
||||
performSegue(withIdentifier: Self.SegueIdentifierSubscriptionDetail, sender: products[indexPath.row])
|
||||
let controller = SubscriptionDetailsViewController(products: products)
|
||||
navigationController?.pushViewController(controller, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private func availableProducts(for section: TableSection) -> [SKProduct] {
|
||||
switch section {
|
||||
case .monthly: return monthlyProducts
|
||||
case .yearly: return yearlyProducts
|
||||
case .perpetual: return perpetualProducts
|
||||
private func availableProducts(for indexPath: IndexPath) -> [EQNInAppProducts] {
|
||||
let section = sections[indexPath.section]
|
||||
switch (section, indexPath.row) {
|
||||
case (.products, 0): return products.filter { $0.isTop10k }
|
||||
case (.products, 1): return products.filter { $0.isTop100k }
|
||||
default: return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SubscriptionsViewController: StoryboardInitializable {
|
||||
static var storyboardName: String {
|
||||
"Main"
|
||||
}
|
||||
|
||||
static var storyboardControllerId: String {
|
||||
"subscriptionsController"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,46 +9,97 @@
|
||||
import UIKit
|
||||
import Shogun
|
||||
|
||||
class SegnalazioniLast24HoursCell: EQNBaseTableViewCell {
|
||||
@objc
|
||||
class SegnalazioniLast24HoursCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
@IBOutlet private weak var headerLabel: UILabel!
|
||||
@IBOutlet private weak var reportsLabel: UILabel!
|
||||
@IBOutlet private weak var reportsDescriptionLabel: UILabel!
|
||||
@objc var onTapTwitter: (() -> Void)?
|
||||
@objc var onTapMap: (() -> Void)?
|
||||
@objc var onTapTelegram: (() -> Void)?
|
||||
|
||||
override var headerText: String { NSLocalizedString("tab_manual", comment: "") }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var reportsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.Colors.red
|
||||
label.font = .preferredFont(forTextStyle: .largeTitle)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var reportsDescriptionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
@IBOutlet private weak var twitterButton: UIButton! {
|
||||
didSet {
|
||||
twitterButton.imageView?.contentMode = .scaleAspectFit
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var telegramButton: UIButton! {
|
||||
didSet {
|
||||
telegramButton.imageView?.contentMode = .scaleAspectFit
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var mapButton: UIButton!
|
||||
private lazy var twitterButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(twitterButtonTapped(_:)))
|
||||
button.imageView?.contentMode = .scaleAspectFit
|
||||
button.setImage(.init(named: "twitter_icon"), for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var mapButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(title: NSLocalizedString("official_button_map", comment: ""), target: self, action: #selector(mapButtonTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var telegramButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(telegramButtonTapped(_:)))
|
||||
button.imageView?.contentMode = .scaleAspectFit
|
||||
button.setImage(.init(named: "telegram_icon"), for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
// MARK: - Internal
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
containerView.addSubview(reportsLabel)
|
||||
containerView.addSubview(reportsDescriptionLabel)
|
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [twitterButton, mapButton, telegramButton])
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.axis = .horizontal
|
||||
stackView.spacing = .cardVerticalSpacing
|
||||
stackView.distribution = .fillEqually
|
||||
containerView.addSubview(stackView)
|
||||
|
||||
reportsLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardPadding).isActive = true
|
||||
reportsLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
reportsLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
reportsDescriptionLabel.topAnchor.constraint(equalTo: reportsLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
reportsDescriptionLabel.leadingAnchor.constraint(equalTo: reportsLabel.leadingAnchor).isActive = true
|
||||
reportsDescriptionLabel.trailingAnchor.constraint(equalTo: reportsLabel.trailingAnchor).isActive = true
|
||||
|
||||
stackView.heightAnchor.constraint(greaterThanOrEqualToConstant: 40.0).isActive = true
|
||||
stackView.topAnchor.constraint(equalTo: reportsDescriptionLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
stackView.leadingAnchor.constraint(equalTo: reportsDescriptionLabel.leadingAnchor).isActive = true
|
||||
stackView.trailingAnchor.constraint(equalTo: reportsDescriptionLabel.trailingAnchor).isActive = true
|
||||
stackView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardPadding.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
headerLabel.text = NSLocalizedString("tab_manual", comment: "").capitalized
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
reportsDescriptionLabel.text = NSLocalizedString("main_map", comment: "")
|
||||
mapButton.setTitle(NSLocalizedString("official_button_map", comment: ""), for: .normal)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
@objc func updateUI(for smartphoneNetwork: EQNReteSmartphone?) {
|
||||
guard let smartphoneNetwork = smartphoneNetwork else {
|
||||
return
|
||||
}
|
||||
@objc
|
||||
func update(with smartphoneNetwork: EQNReteSmartphone?) {
|
||||
guard let smartphoneNetwork = smartphoneNetwork else { return }
|
||||
|
||||
let reports = smartphoneNetwork.manual
|
||||
self.reportsLabel.text = "\(reports)"
|
||||
@@ -61,4 +112,18 @@ class SegnalazioniLast24HoursCell: EQNBaseTableViewCell {
|
||||
self.reportsLabel.textColor = UIColor(hex6: 0xff0000)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc private func twitterButtonTapped(_ sender: UIButton) {
|
||||
onTapTwitter?()
|
||||
}
|
||||
|
||||
@objc private func mapButtonTapped(_ sender: UIButton) {
|
||||
onTapMap?()
|
||||
}
|
||||
|
||||
@objc private func telegramButtonTapped(_ sender: UIButton) {
|
||||
onTapTelegram?()
|
||||
}
|
||||
}
|
||||
|
||||
+12
-62
@@ -28,35 +28,7 @@ class SegnalazioniMapViewController: EQNBaseMapViewController {
|
||||
private var filteredReports = [EQNSegnalazione]()
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
// app icon and name displayed on the screenshot
|
||||
private lazy var watermarkView: UIView = {
|
||||
let view = UIView()
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.isHidden = true
|
||||
|
||||
let logo = UIImageView(image: .init(named: "eq_icon_transparent"))
|
||||
logo.translatesAutoresizingMaskIntoConstraints = false
|
||||
logo.contentMode = .scaleAspectFit
|
||||
view.addSubview(logo)
|
||||
logo.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
|
||||
logo.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
||||
logo.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
||||
logo.widthAnchor.constraint(equalTo: logo.heightAnchor).isActive = true
|
||||
|
||||
let title = UILabel()
|
||||
title.translatesAutoresizingMaskIntoConstraints = false
|
||||
title.text = NSLocalizedString("app_name", comment: "") + " App"
|
||||
title.textColor = AppTheme.Colors.red
|
||||
title.font = .preferredFont(forTextStyle: .title3, weight: .semibold)
|
||||
view.addSubview(title)
|
||||
title.leadingAnchor.constraint(equalTo: logo.trailingAnchor, constant: 10.0).isActive = true
|
||||
title.centerYAnchor.constraint(equalTo: logo.centerYAnchor).isActive = true
|
||||
title.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var magnitudeLegendView: UIView = {
|
||||
let view = UIView()
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
@@ -95,16 +67,11 @@ class SegnalazioniMapViewController: EQNBaseMapViewController {
|
||||
|
||||
override func extraUI() {
|
||||
view.addSubview(magnitudeLegendView)
|
||||
view.addSubview(watermarkView)
|
||||
|
||||
magnitudeLegendView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
||||
magnitudeLegendView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
||||
magnitudeLegendView.heightAnchor.constraint(equalToConstant: 25.0).isActive = true
|
||||
magnitudeLegendView.topAnchor.constraint(equalTo: mapView.topAnchor).isActive = true
|
||||
|
||||
watermarkView.topAnchor.constraint(equalTo: mapView.topAnchor, constant: 10.0).isActive = true
|
||||
watermarkView.leadingAnchor.constraint(equalTo: mapView.leadingAnchor, constant: 10.0).isActive = true
|
||||
watermarkView.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
|
||||
}
|
||||
|
||||
override func configureUI() {
|
||||
@@ -153,7 +120,7 @@ class SegnalazioniMapViewController: EQNBaseMapViewController {
|
||||
.first
|
||||
|
||||
// controlliamo che sia inferiore al raggio impostato per le notifiche
|
||||
if let radius = Double(EQNNotificheSegnalazioniUtente.shared().distanzaPosizione),
|
||||
if let radius = Double(EQNSettingUserReportNotification.shared.distanzaMassima),
|
||||
let nearestCluser = nearestCluser,
|
||||
abs(nearestCluser.distance(from: userPosition)) < radius {
|
||||
centerLocation = nearestCluser
|
||||
@@ -191,33 +158,20 @@ class SegnalazioniMapViewController: EQNBaseMapViewController {
|
||||
|
||||
@objc private func onTapMapDetailStyleButton(_ sender: Any) {
|
||||
appPreferences.userReportExpandedView.toggle()
|
||||
loadDataSource()
|
||||
reloadMap()
|
||||
}
|
||||
|
||||
@objc private func onTapScreenshotButton(_ sender: Any) {
|
||||
let snapshot = createSnapshot()
|
||||
|
||||
let controller = UIActivityViewController(activityItems: [snapshot], applicationActivities: [])
|
||||
present(controller, animated: true)
|
||||
}
|
||||
|
||||
public func createSnapshot() -> UIImage {
|
||||
// mostriamo il watermark e nascondiamo la legenda
|
||||
watermarkView.isHidden = false
|
||||
magnitudeLegendView.isHidden = true
|
||||
|
||||
// riduciamo la porzione da salvare alla sola mappa (eliminiamo i filtri)
|
||||
let size = CGSize(width: view.bounds.width, height: mapView.bounds.maxY)
|
||||
let renderer = UIGraphicsImageRenderer(size: size)
|
||||
let image = renderer.image { ctx in
|
||||
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
|
||||
let screenshot = createSnapshot {
|
||||
// nascondiamo la legenda
|
||||
magnitudeLegendView.isHidden = true
|
||||
} restore: {
|
||||
// ri-visualizziamo la legenda
|
||||
magnitudeLegendView.isHidden = false
|
||||
}
|
||||
|
||||
// torniamo allo stato originale
|
||||
watermarkView.isHidden = true
|
||||
magnitudeLegendView.isHidden = false
|
||||
|
||||
return image
|
||||
let controller = UIActivityViewController(activityItems: [screenshot], applicationActivities: [])
|
||||
present(controller, animated: true)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -233,10 +187,10 @@ class SegnalazioniMapViewController: EQNBaseMapViewController {
|
||||
var cluster_code = 0
|
||||
var vector_cluster = [Int](repeating: 0, count: vector_latitude.count)
|
||||
for i in 0..<vector_latitude.count {
|
||||
let deltaMinute_i = getDeltaMinute(vector_date[i])
|
||||
let deltaMinute_i = EQNUtility.getDeltaMinute(vector_date[i])
|
||||
if vector_cluster[i] == 0 && deltaMinute_i <= minutes {
|
||||
for j in 0..<vector_latitude.count {
|
||||
let deltaMinute_j = getDeltaMinute(vector_date[j])
|
||||
let deltaMinute_j = EQNUtility.getDeltaMinute(vector_date[j])
|
||||
if i != j && deltaMinute_j <= minutes {
|
||||
if abs(vector_latitude[i] - vector_latitude[j]) < 4 && abs(vector_longitude[i] - vector_longitude[j]) < 4 && abs(deltaMinute_i - deltaMinute_j) <= 20 {
|
||||
if vector_cluster[j] > 0 {
|
||||
@@ -327,10 +281,6 @@ class SegnalazioniMapViewController: EQNBaseMapViewController {
|
||||
mapView.addOverlays(overlays)
|
||||
}
|
||||
|
||||
private func getDeltaMinute(_ date: Date) -> TimeInterval {
|
||||
Date().timeIntervalSince(date) / 60.0
|
||||
}
|
||||
|
||||
// MARK: - Map
|
||||
|
||||
override func setupAnnotationView(for annotation: MKAnnotation, on mapView: MKMapView) -> MKAnnotationView? {
|
||||
|
||||
@@ -7,49 +7,100 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Shogun
|
||||
|
||||
class SegnalazioniSendReportCell: EQNBaseTableViewCell {
|
||||
class SegnalazioniSendReportCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
private struct Report: Equatable {
|
||||
let magnitude: Int
|
||||
let text: String
|
||||
let color: UIColor
|
||||
|
||||
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.magnitude == rhs.magnitude
|
||||
}
|
||||
}
|
||||
|
||||
@objc var onTapReport: (_ magnitude: Int) -> Void = { _ in }
|
||||
|
||||
override var headerText: String { NSLocalizedString("main_feel", comment: "") }
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
@IBOutlet private weak var headerLabel: UILabel!
|
||||
@IBOutlet private weak var reportMercalli2: UILabel!
|
||||
@IBOutlet private weak var reportMercalli3: UILabel!
|
||||
@IBOutlet private weak var reportMercalli4: UILabel!
|
||||
@IBOutlet private weak var reportMercalli5: UILabel!
|
||||
@IBOutlet private weak var reportMercalli6: UILabel!
|
||||
@IBOutlet private weak var reportMercalli7: UILabel!
|
||||
@IBOutlet private weak var reportMercalli8: UILabel!
|
||||
@IBOutlet private weak var reportMercalli9: UILabel!
|
||||
@IBOutlet private weak var reportMercalli10: UILabel!
|
||||
@IBOutlet private weak var reportMercalli11: UILabel!
|
||||
@IBOutlet private weak var reportMercalli12: UILabel!
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
private let reports: [Report] = [
|
||||
.init(magnitude: 20, text: NSLocalizedString("mercalli_II", comment: ""), color: .init(named: "Mercalli 20")!),
|
||||
.init(magnitude: 30, text: NSLocalizedString("mercalli_III", comment: ""), color: .init(named: "Mercalli 30")!),
|
||||
.init(magnitude: 40, text: NSLocalizedString("mercalli_IV", comment: ""), color: .init(named: "Mercalli 40")!),
|
||||
.init(magnitude: 50, text: NSLocalizedString("mercalli_V", comment: ""), color: .init(named: "Mercalli 50")!),
|
||||
.init(magnitude: 60, text: NSLocalizedString("mercalli_VI", comment: ""), color: .init(named: "Mercalli 60")!),
|
||||
.init(magnitude: 70, text: NSLocalizedString("mercalli_VII", comment: ""), color: .init(named: "Mercalli 70")!),
|
||||
.init(magnitude: 80, text: NSLocalizedString("mercalli_VIII", comment: ""), color: .init(named: "Mercalli 80")!),
|
||||
.init(magnitude: 90, text: NSLocalizedString("mercalli_IX", comment: ""), color: .init(named: "Mercalli 90")!),
|
||||
.init(magnitude: 100, text: NSLocalizedString("mercalli_X", comment: ""), color: .init(named: "Mercalli 100")!),
|
||||
.init(magnitude: 110, text: NSLocalizedString("mercalli_XI", comment: ""), color: .init(named: "Mercalli 110")!),
|
||||
.init(magnitude: 120, text: NSLocalizedString("mercalli_XII", comment: ""), color: .init(named: "Mercalli 120")!)
|
||||
]
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// MARK: - Internal
|
||||
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
var previousView = topView
|
||||
reports.enumerated().forEach { index, report in
|
||||
let view = createContentView(magnitude: report.magnitude, text: report.text, color: report.color)
|
||||
containerView.addSubview(view)
|
||||
|
||||
view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
|
||||
view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
|
||||
|
||||
let padding: CGFloat = report == reports.first ? .cardPadding : 0
|
||||
view.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: padding).isActive = true
|
||||
|
||||
if report == reports.last {
|
||||
view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
|
||||
}
|
||||
|
||||
previousView = view
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
headerLabel.text = NSLocalizedString("main_feel", comment: "")
|
||||
reportMercalli2.text = NSLocalizedString("mercalli_II", comment: "")
|
||||
reportMercalli3.text = NSLocalizedString("mercalli_III", comment: "")
|
||||
reportMercalli4.text = NSLocalizedString("mercalli_IV", comment: "")
|
||||
reportMercalli5.text = NSLocalizedString("mercalli_V", comment: "")
|
||||
reportMercalli6.text = NSLocalizedString("mercalli_VI", comment: "")
|
||||
reportMercalli7.text = NSLocalizedString("mercalli_VII", comment: "")
|
||||
reportMercalli8.text = NSLocalizedString("mercalli_VIII", comment: "")
|
||||
reportMercalli9.text = NSLocalizedString("mercalli_IX", comment: "")
|
||||
reportMercalli10.text = NSLocalizedString("mercalli_X", comment: "")
|
||||
reportMercalli11.text = NSLocalizedString("mercalli_XI", comment: "")
|
||||
reportMercalli12.text = NSLocalizedString("mercalli_XII", comment: "")
|
||||
private func createContentView(
|
||||
magnitude: Int,
|
||||
text: String,
|
||||
color: UIColor
|
||||
) -> UIView {
|
||||
let view = UIView(frame: .zero)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.backgroundColor = color
|
||||
|
||||
let label = UILabel(frame: .zero)
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.numberOfLines = 0
|
||||
label.text = text
|
||||
|
||||
let button = UIButton(type: .system)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.backgroundColor = .clear
|
||||
button.tag = magnitude
|
||||
button.addTarget(self, action: #selector(onTapMagnitudeButton(_:)), for: .touchUpInside)
|
||||
|
||||
view.addSubview(label)
|
||||
view.addSubview(button)
|
||||
|
||||
// use a custom vertical spacing to make single lines bigger
|
||||
let verticalSpacing: CGFloat = 15.0
|
||||
label.topAnchor.constraint(equalTo: view.topAnchor, constant: verticalSpacing).isActive = true
|
||||
label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
label.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -verticalSpacing).isActive = true
|
||||
button.constraint(to: view)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
@@ -58,4 +109,9 @@ class SegnalazioniSendReportCell: EQNBaseTableViewCell {
|
||||
let magnitude = sender.tag
|
||||
onTapReport(magnitude)
|
||||
}
|
||||
|
||||
@objc private func onTapMagnitudeButton(_ sender: UIButton) {
|
||||
let magnitude = sender.tag
|
||||
onTapReport(magnitude)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
self.title = [NSLocalizedString(@"tab_manual", nil) capitalizedString];
|
||||
self.tableView.estimatedRowHeight = 500.0;
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
[self.tableView registerClass:[SegnalazioniLast24HoursCell class] forCellReuseIdentifier:@"Last24HCell"];
|
||||
[self.tableView registerClass:[SegnalazioniSendReportCell class] forCellReuseIdentifier:@"ReportEarthquakeCell"];
|
||||
}
|
||||
|
||||
- (void)refreshUI
|
||||
@@ -74,8 +76,17 @@
|
||||
{
|
||||
if (indexPath.row == 0) {
|
||||
SegnalazioniLast24HoursCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Last24HCell" forIndexPath:indexPath];
|
||||
EQNReteSmartphone *reteSmartPhone = [EQNManager defaultManager].rete_smartphone;
|
||||
[cell updateUIFor:reteSmartPhone];
|
||||
[cell updateWith:[EQNManager defaultManager].rete_smartphone];
|
||||
__weak SegnalazioniViewController *weakSelf = self;
|
||||
cell.onTapMap = ^{
|
||||
[weakSelf openMap];
|
||||
};
|
||||
cell.onTapTwitter = ^{
|
||||
[weakSelf openTwitter];
|
||||
};
|
||||
cell.onTapTelegram = ^{
|
||||
[weakSelf openTelegram];
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -88,21 +99,21 @@
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)openMapTapped:(id)sender
|
||||
- (void)openMap
|
||||
{
|
||||
SegnalazioniMapViewController *controller = [[SegnalazioniMapViewController alloc] init];
|
||||
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
|
||||
[self presentViewController:navController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (IBAction)openTwitterTapped:(id)sender
|
||||
- (void)openTwitter
|
||||
{
|
||||
NSURL *twitterUrl = [NSURL URLWithString:EQNTwitterProfileUrl];
|
||||
SFSafariViewController *controller = [[SFSafariViewController alloc] initWithURL:twitterUrl];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (IBAction)openTelegramTapped:(id)sender
|
||||
- (void)openTelegram
|
||||
{
|
||||
NSURL *telegramUrl = [NSURL URLWithString:EQNTelegramUrl];
|
||||
[[UIApplication sharedApplication] openURL:telegramUrl options:@{} completionHandler:nil];
|
||||
|
||||
+49
-74
@@ -52,8 +52,6 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
// MARK: - Internal
|
||||
|
||||
private static let DefaultVerticalSpacing: CGFloat = 6.0
|
||||
private static let DefaultBodyFont = UIFont.preferredFont(forTextStyle: .body)
|
||||
private static let DefaultBodyFontLight = UIFont.preferredFont(forTextStyle: .body, weight: .light)
|
||||
|
||||
/// Seismic to show
|
||||
private var seismic: EQNSisma?
|
||||
@@ -78,12 +76,17 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var titleImageView: UIImageView = {
|
||||
let imageView = UIImageView(frame: .zero)
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
return imageView
|
||||
private lazy var gradientView: UIImageView = {
|
||||
// Per gestire il gradiente, utilizziamo una image view in cui inseriamo un'immagine
|
||||
// creata ad-hoc con il gradiente desiderato.
|
||||
// Le prove fatte utilizzando una view normale sono fallite perchè al momento di
|
||||
// disegnare la view non abbiamo le misure corrette.
|
||||
let view = UIImageView(frame: .zero)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.contentMode = .scaleAspectFill
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
private lazy var placeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
@@ -95,8 +98,9 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
private lazy var networkLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.backgroundColor = UIColor.white.withAlphaComponent(0.5)
|
||||
label.textAlignment = .center
|
||||
label.textAlignment = .right
|
||||
label.font = .preferredFont(forTextStyle: .subheadline)
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
@@ -111,35 +115,40 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
private lazy var depthLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = Self.DefaultBodyFontLight
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var timeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = Self.DefaultBodyFontLight
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var distanceLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = Self.DefaultBodyFontLight
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coordinateLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = Self.DefaultBodyFontLight
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var populationLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = Self.DefaultBodyFontLight
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
@@ -147,8 +156,9 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.font = Self.DefaultBodyFont
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
@@ -156,8 +166,9 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.font = Self.DefaultBodyFont
|
||||
label.font = .preferredFont(forTextStyle: .body)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
@@ -195,7 +206,11 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8.0).isActive = true
|
||||
containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0).isActive = true
|
||||
containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4.0).isActive = true
|
||||
containerView.clipsToBounds = true
|
||||
|
||||
containerView.addSubview(gradientView)
|
||||
gradientView.constraint(to: containerView)
|
||||
|
||||
// this variable is used to keep track of the previous view, in order to attach proper constraints
|
||||
var previousView: UIView = containerView
|
||||
|
||||
@@ -230,16 +245,9 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
shareButton.setImage(UIImage(named: "share_icon"), for: .normal)
|
||||
shareButton.addTarget(self, action: #selector(shareTapped(_:)), for: .touchUpInside)
|
||||
|
||||
stackViewTitle.addArrangedSubview(titleImageView)
|
||||
stackViewTitle.addArrangedSubview(placeLabel)
|
||||
stackViewTitle.addArrangedSubview(networkLabel)
|
||||
stackViewTitle.addArrangedSubview(shareButton)
|
||||
|
||||
titleImageView.heightAnchor.constraint(equalToConstant: titleComponentsHeight).isActive = true
|
||||
titleImageView.widthAnchor.constraint(equalTo: titleImageView.heightAnchor).isActive = true
|
||||
networkLabel.heightAnchor.constraint(equalToConstant: 34.0).isActive = true
|
||||
networkLabel.setContentHuggingPriority(.init(800), for: .horizontal)
|
||||
networkLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
||||
placeLabel.setContentHuggingPriority(.init(200), for: .horizontal)
|
||||
placeLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
shareButton.widthAnchor.constraint(equalToConstant: titleComponentsHeight).isActive = true
|
||||
@@ -318,6 +326,13 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
previousView = separator3
|
||||
}
|
||||
|
||||
// network
|
||||
containerView.addSubview(networkLabel)
|
||||
networkLabel.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
|
||||
networkLabel.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
|
||||
networkLabel.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
|
||||
previousView = networkLabel
|
||||
|
||||
if informationTypes.contains(.buttons) {
|
||||
// buttons
|
||||
let stackViewButtons = UIStackView()
|
||||
@@ -326,11 +341,11 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
stackViewButtons.distribution = .fillEqually
|
||||
stackViewButtons.spacing = 4
|
||||
|
||||
let buttonMap = createRoundedButton(title: "🗺", action: #selector(mapTapped(_:)))
|
||||
let buttonMap = EQNRoundedButton.make(title: "🗺", target: self, action: #selector(mapTapped(_:)))
|
||||
stackViewButtons.addArrangedSubview(buttonMap)
|
||||
let buttonCalendar = createRoundedButton(title: "📆", action: #selector(calendarTapped(_:)))
|
||||
let buttonCalendar = EQNRoundedButton.make(title: "📆", target: self, action: #selector(calendarTapped(_:)))
|
||||
stackViewButtons.addArrangedSubview(buttonCalendar)
|
||||
let buttonSettings = createRoundedButton(title: "🔧", action: #selector(settingsTapped(_:)))
|
||||
let buttonSettings = EQNRoundedButton.make(title: "🔧", target: self, action: #selector(settingsTapped(_:)))
|
||||
stackViewButtons.addArrangedSubview(buttonSettings)
|
||||
|
||||
containerView.addSubview(stackViewButtons)
|
||||
@@ -353,7 +368,7 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
}
|
||||
|
||||
if (displayType == .mapExpanded) {
|
||||
let buttonClose = createRoundedButton(title: NSLocalizedString("official_close", comment: "").uppercased(), action: #selector(closeTapped(_:)))
|
||||
let buttonClose = EQNRoundedButton.make(title: NSLocalizedString("official_close", comment: "").uppercased(), target: self, action: #selector(closeTapped(_:)))
|
||||
|
||||
containerView.addSubview(buttonClose)
|
||||
buttonClose.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: Self.DefaultVerticalSpacing).isActive = true
|
||||
@@ -377,14 +392,15 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
|
||||
let viewModel = SeismicNetworkViewModel(seismic: seismic)
|
||||
|
||||
containerView.backgroundColor = colors?.startColor
|
||||
|
||||
let notified = couldBeNotified(for: seismic)
|
||||
titleImageView.image = notified ? UIImage(named: "bell") : UIImage(named: "bell_disabled")
|
||||
|
||||
if let colors = colors {
|
||||
gradientView.image = .gradient(from: colors.startColor, to: colors.endColor, with: .init(origin: .zero, size: .init(width: 400, height: 300)))
|
||||
} else {
|
||||
gradientView.image = nil
|
||||
}
|
||||
|
||||
// update seismic data
|
||||
placeLabel.text = viewModel.place
|
||||
networkLabel.text = viewModel.network + " " // add some padding
|
||||
networkLabel.text = String(format: NSLocalizedString("official_provider", comment: ""), viewModel.network)
|
||||
magnitudeLabel.textColor = colors?.textColor
|
||||
magnitudeLabel.text = viewModel.magnitude
|
||||
depthLabel.text = viewModel.depth
|
||||
@@ -499,48 +515,7 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
|
||||
return separator
|
||||
}
|
||||
|
||||
private func createRoundedButton(title: String, action: Selector) -> EQNRoundedButton {
|
||||
let button = EQNRoundedButton(frame: .zero)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.addTarget(self, action: action, for: .touchUpInside)
|
||||
button.setTitle(title, for: .normal)
|
||||
button.setTitleColor(AppTheme.Colors.darkGray, for: .normal)
|
||||
button.backgroundColor = UIColor.white.withAlphaComponent(0.5)
|
||||
return button
|
||||
}
|
||||
|
||||
/// Check if the user could be received a notification for this seismic
|
||||
private func couldBeNotified(for seismic: EQNSisma) -> Bool {
|
||||
let settings = EQNNotificheReteSismiche.shared()
|
||||
|
||||
if !settings.isAbilitato {
|
||||
return false
|
||||
}
|
||||
|
||||
if !settings.listaEnti.contains(seismic.provider) {
|
||||
return false
|
||||
}
|
||||
|
||||
var notified = true
|
||||
if let radius = Double(settings.distanzaPosizione), seismic.userDistance > radius {
|
||||
notified = false
|
||||
}
|
||||
if let magnitude = Double(settings.energiaSisma), seismic.magnitude.doubleValue < magnitude {
|
||||
notified = false
|
||||
}
|
||||
|
||||
if settings.isAbilitaVicini, seismic.userDistance < 50 {
|
||||
notified = true
|
||||
}
|
||||
|
||||
if settings.isTerremortiForti, let strongMagnitude = Double(settings.energiaTerremotiForti), seismic.magnitude.doubleValue >= strongMagnitude {
|
||||
notified = true
|
||||
}
|
||||
|
||||
return notified
|
||||
}
|
||||
|
||||
/// Determines the zoom for the map, based on the involved population
|
||||
private func mapSpanLongitude(population: Double) -> CLLocationDegrees {
|
||||
var zoom: CLLocationDegrees = 1
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
//
|
||||
// FiltersViewModel.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 22/03/21.
|
||||
// Copyright © 2021 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
struct FiltersViewModel {
|
||||
let magnitude: String
|
||||
let distance: String
|
||||
let timeframe: String
|
||||
|
||||
init() {
|
||||
let magnitudoMinima = EQNData.magitudoDebole(for: EQNSeismic.shared.magnitudoMinima)
|
||||
self.magnitude = Self.formattedMagnitude(magnitudoMinima.value)
|
||||
|
||||
let distanzaMassima = EQNData.raggioSisma(for: EQNSeismic.shared.distanzaMassima)
|
||||
self.distance = Self.formattedDistance(distanzaMassima.value)
|
||||
|
||||
let periodoTemporale = EQNData.periodoTemporale(for: EQNSeismic.shared.periodoTemporale)
|
||||
self.timeframe = Self.formattedTimeframe(periodoTemporale.value)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private static func formattedMagnitude(_ magnitude: String) -> String {
|
||||
return magnitude
|
||||
}
|
||||
|
||||
private static func formattedDistance(_ distance: String) -> String {
|
||||
if distance == EQNData.MaxRaggioSisma {
|
||||
return "∞"
|
||||
}
|
||||
return "\(distance)km"
|
||||
}
|
||||
|
||||
private static func formattedTimeframe(_ timeframe: String) -> String {
|
||||
let time = Int(timeframe) ?? 0
|
||||
if time < 60 {
|
||||
return "\(time)m"
|
||||
}
|
||||
return "\(time/60)h"
|
||||
}
|
||||
}
|
||||
+79
-115
@@ -16,13 +16,11 @@ protocol SeismicFiltersViewControllerDelegate: AnyObject {
|
||||
class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
private enum RowIdentifier: Int {
|
||||
case magnitudoMinima
|
||||
case sismiNelRaggio
|
||||
case distanzaMassima
|
||||
case periodoTemporale
|
||||
case sismiFortiAbilita
|
||||
case sismiFortiDistanza
|
||||
case sismiQualsiasiMagnitudo
|
||||
case modificaImpostazioni
|
||||
case magnitudoMinima
|
||||
case sismiRilevanti
|
||||
case sismiTutti
|
||||
}
|
||||
|
||||
weak var delegate: SeismicFiltersViewControllerDelegate?
|
||||
@@ -37,29 +35,20 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
|
||||
@IBOutlet private weak var closeButton: UIButton!
|
||||
|
||||
private var settings = [
|
||||
SettingItem(type: .slider, title: NSLocalizedString("filter_magnitude", comment: "")),
|
||||
SettingItem(type: .slider, title: NSLocalizedString("filter_distance", comment: "")),
|
||||
SettingItem(type: .slider, title: NSLocalizedString("filter_timeframe", comment: "")),
|
||||
SettingItem(type: .enable, title: NSLocalizedString("filter_strong", comment: "")),
|
||||
SettingItem(type: .slider, title: NSLocalizedString("options_strong_magnitude", comment: "")),
|
||||
SettingItem(type: .enable, title: NSLocalizedString("filter_near", comment: "")),
|
||||
SettingItem(type: .enable, title: NSLocalizedString("filter_reflect", comment: ""))
|
||||
SettingItem(type: .enable, title: NSLocalizedString("filter_show_area", comment: "")),
|
||||
SettingItem(type: .slider, title: ""),
|
||||
SettingItem(type: .slider, title: NSLocalizedString("filter_minimum_magnitude", comment: "")),
|
||||
SettingItem(type: .enable, title: NSLocalizedString("filter_show_relevant", comment: "")),
|
||||
SettingItem(type: .enable, title: NSLocalizedString("filter_show_all", comment: "")),
|
||||
]
|
||||
private let dataSourceMagnitudoMinima = EQNData.magitudoDeboli()
|
||||
private let dataSourceDistanzaMassima = EQNData.raggioSismi()
|
||||
private let dataSourcePeriodoTemporale = EQNData.periodiTemporali()
|
||||
private let dataSourceSismiForti = EQNData.magitudoForti()
|
||||
|
||||
private var initialMagnitudoMinima: EQNGenericValue?
|
||||
private var initialQualsiasiMagnitudo: Bool?
|
||||
private let initialFilterType = EQNSeismic.shared.filterOption
|
||||
private var currentFilterType = EQNSeismic.FilterType.inRadius
|
||||
private var currentMaximumDistance = EQNData.DefaultFilterRadius
|
||||
private var currentMinimumMagnitude = EQNData.DefaultFilterMagnitude
|
||||
|
||||
private var currentMagnitudoMinima = EQNData.DefaultMagitudoDebole
|
||||
private var currentDistanzaMassima = EQNData.DefaultRaggioSisma
|
||||
private var currentPeriodoTemporale = EQNData.DefaultPeriodoTemporale
|
||||
private var currentSismiFortiAbilitati = false
|
||||
private var currentSismiFortiDistanza = EQNData.DefaultMagitudoForte
|
||||
private var currentSismiQualsiasiMagnitudo = false
|
||||
private var currentModificaImpostazioni = false
|
||||
private let dataSourceMaximumDistance = EQNData.filterRadius
|
||||
private let dataSourceMinimumMagnitude = EQNData.filterMagnitude
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
@@ -86,19 +75,9 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
|
||||
}
|
||||
|
||||
private func loadDataSource() {
|
||||
currentMagnitudoMinima = EQNData.magitudoDebole(for: EQNSeismic.shared.magnitudoMinima)
|
||||
if initialMagnitudoMinima == nil {
|
||||
initialMagnitudoMinima = currentMagnitudoMinima
|
||||
}
|
||||
currentDistanzaMassima = EQNData.raggioSisma(for: EQNSeismic.shared.distanzaMassima)
|
||||
currentPeriodoTemporale = EQNData.periodoTemporale(for: EQNSeismic.shared.periodoTemporale)
|
||||
currentSismiFortiAbilitati = EQNSeismic.shared.sismiFortiAbilitati
|
||||
currentSismiFortiDistanza = EQNData.magitudoForte(for: EQNSeismic.shared.sismiFortiMagnitudo)
|
||||
currentSismiQualsiasiMagnitudo = EQNSeismic.shared.sismiQualsiasiAbilitati
|
||||
if initialQualsiasiMagnitudo == nil {
|
||||
initialQualsiasiMagnitudo = currentSismiQualsiasiMagnitudo
|
||||
}
|
||||
currentModificaImpostazioni = EQNSeismic.shared.modificaImpostazioniAbilitato
|
||||
currentFilterType = EQNSeismic.shared.filterOption
|
||||
currentMaximumDistance = EQNData.filterRadius(for: EQNSeismic.shared.maximumDistance)
|
||||
currentMinimumMagnitude = EQNData.filterMagnitude(for: EQNSeismic.shared.minimumMagnitude)
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate and data source
|
||||
@@ -108,45 +87,36 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
guard let identifier = RowIdentifier(rawValue: indexPath.row) else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
|
||||
let setting = settings[indexPath.row]
|
||||
let isLocationAvailable = EQNUser.default().lastPosition != nil
|
||||
|
||||
switch setting.type {
|
||||
case .slider:
|
||||
let cell = SettingSliderTableViewCell(style: .default, reuseIdentifier: nil)
|
||||
cell.titleLabel.text = setting.displayTitle
|
||||
|
||||
if indexPath.row == RowIdentifier.magnitudoMinima.rawValue {
|
||||
cell.configureSlider(with: dataSourceMagnitudoMinima, current: currentMagnitudoMinima)
|
||||
cell.valueChanged = { [unowned self] value in
|
||||
currentMagnitudoMinima = value
|
||||
EQNSeismic.shared.magnitudoMinima = value.value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
let isFilterInRadiusEnabled = currentFilterType == .inRadius && isLocationAvailable
|
||||
switch identifier {
|
||||
case .distanzaMassima:
|
||||
cell.isDisabled = !isFilterInRadiusEnabled
|
||||
cell.isUserInteractionEnabled = isFilterInRadiusEnabled
|
||||
cell.configureSlider(with: dataSourceMaximumDistance, current: currentMaximumDistance)
|
||||
cell.valueChanged = { [weak self] value in
|
||||
self?.onChangeMaximumDistance(value)
|
||||
}
|
||||
cell.dragEnded = { [unowned self] in
|
||||
showWarningAlertIfNeeded(for: currentMagnitudoMinima)
|
||||
}
|
||||
} else if indexPath.row == RowIdentifier.distanzaMassima.rawValue {
|
||||
cell.configureSlider(with: dataSourceDistanzaMassima, current: currentDistanzaMassima)
|
||||
cell.valueChanged = { [unowned self] value in
|
||||
currentDistanzaMassima = value
|
||||
EQNSeismic.shared.distanzaMassima = value.value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
}
|
||||
} else if indexPath.row == RowIdentifier.periodoTemporale.rawValue {
|
||||
cell.configureSlider(with: dataSourcePeriodoTemporale, current: currentPeriodoTemporale)
|
||||
cell.valueChanged = { [unowned self] value in
|
||||
currentPeriodoTemporale = value
|
||||
EQNSeismic.shared.periodoTemporale = value.value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
}
|
||||
} else if indexPath.row == RowIdentifier.sismiFortiDistanza.rawValue {
|
||||
cell.isDisabled = !currentSismiFortiAbilitati
|
||||
cell.configureSlider(with: dataSourceSismiForti, current: currentSismiFortiDistanza)
|
||||
cell.valueChanged = { [unowned self] value in
|
||||
currentSismiFortiDistanza = value
|
||||
EQNSeismic.shared.sismiFortiMagnitudo = value.value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
case .magnitudoMinima:
|
||||
cell.isDisabled = !isFilterInRadiusEnabled
|
||||
cell.isUserInteractionEnabled = isFilterInRadiusEnabled
|
||||
cell.configureSlider(with: dataSourceMinimumMagnitude, current: currentMinimumMagnitude)
|
||||
cell.valueChanged = { [weak self] value in
|
||||
self?.onChangeMinimumMagnitude(value)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return cell
|
||||
@@ -155,30 +125,31 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
|
||||
cell.titleLabel.text = setting.displayTitle
|
||||
cell.detailTextLabel?.text = setting.subtitle
|
||||
|
||||
if indexPath.row == RowIdentifier.sismiFortiAbilita.rawValue {
|
||||
cell.toggleSwitch.isOn = currentSismiFortiAbilitati
|
||||
cell.valueChanged = { [unowned self] value in
|
||||
currentSismiFortiAbilitati = value
|
||||
EQNSeismic.shared.sismiFortiAbilitati = value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
|
||||
loadDataSource()
|
||||
tableView.reloadData()
|
||||
switch identifier {
|
||||
case .sismiNelRaggio:
|
||||
let isCurrentFilter = currentFilterType == .inRadius
|
||||
cell.isDisabled = !isLocationAvailable
|
||||
cell.toggleSwitch.isOn = isCurrentFilter
|
||||
cell.valueChanged = { [weak self] enabled in
|
||||
self?.onChangeFilterOption(enabled, filter: .inRadius)
|
||||
}
|
||||
} else if indexPath.row == RowIdentifier.sismiQualsiasiMagnitudo.rawValue {
|
||||
cell.toggleSwitch.isOn = currentSismiQualsiasiMagnitudo
|
||||
cell.valueChanged = { [unowned self] value in
|
||||
currentSismiQualsiasiMagnitudo = value
|
||||
EQNSeismic.shared.sismiQualsiasiAbilitati = value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
cell.errorLabel.text = !isLocationAvailable ? NSLocalizedString("filter_nolocation", comment: "") : nil
|
||||
case .sismiRilevanti:
|
||||
let isCurrentFilter = currentFilterType == .positionRelevant
|
||||
cell.isDisabled = !isLocationAvailable
|
||||
cell.toggleSwitch.isOn = isCurrentFilter
|
||||
cell.valueChanged = { [weak self] enabled in
|
||||
self?.onChangeFilterOption(enabled, filter: .positionRelevant)
|
||||
}
|
||||
} else if indexPath.row == RowIdentifier.modificaImpostazioni.rawValue {
|
||||
cell.toggleSwitch.isOn = currentModificaImpostazioni
|
||||
cell.valueChanged = { [unowned self] value in
|
||||
currentModificaImpostazioni = value
|
||||
EQNSeismic.shared.modificaImpostazioniAbilitato = value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
cell.errorLabel.text = !isLocationAvailable ? NSLocalizedString("filter_nolocation", comment: "") : nil
|
||||
case .sismiTutti:
|
||||
let isCurrentFilter = currentFilterType == .worldWide
|
||||
cell.toggleSwitch.isOn = isCurrentFilter
|
||||
cell.valueChanged = { [weak self] enabled in
|
||||
self?.onChangeFilterOption(enabled, filter: .worldWide)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return cell
|
||||
@@ -191,41 +162,34 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
|
||||
|
||||
@IBAction func exitTapped(_ sender: UIButton) {
|
||||
// data needs to be re-downloaded if (or conditions):
|
||||
// a) new magnitude is lower than the previous one and new value is less than 2.0
|
||||
// b) show any near earthquake is active and value is changed
|
||||
if let initialMagnitude = Float(initialMagnitudoMinima?.value ?? "10.0"), let currentMagnitude = Float(currentMagnitudoMinima.value) {
|
||||
needsDataUpdate = currentMagnitude < 2.0 && initialMagnitude > currentMagnitude
|
||||
}
|
||||
if let initialQualsiasiMagnitudo = initialQualsiasiMagnitudo, currentSismiQualsiasiMagnitudo == true, initialQualsiasiMagnitudo != currentSismiQualsiasiMagnitudo {
|
||||
needsDataUpdate = true
|
||||
}
|
||||
|
||||
// a) filter type is changed
|
||||
needsDataUpdate = initialFilterType != currentFilterType
|
||||
delegate?.seismicFiltersControllerDidUpdateFilters(self)
|
||||
updateNotificationSettingsIfNeeded()
|
||||
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func showWarningAlertIfNeeded(for value: EQNGenericValue) {
|
||||
guard let magnitude = Double(value.value), magnitude < 2.0 else { return }
|
||||
private func onChangeFilterOption(_ enabled: Bool, filter: EQNSeismic.FilterType) {
|
||||
currentFilterType = filter
|
||||
EQNSeismic.shared.filterOption = filter
|
||||
EQNSeismic.shared.saveFilters()
|
||||
|
||||
let alert = UIAlertController(title: NSLocalizedString("attention", comment: ""), message: NSLocalizedString("options_low_magnitude", comment: ""), preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("main_understood", comment: ""), style: .default, handler: nil))
|
||||
present(alert, animated: true, completion: nil)
|
||||
loadDataSource()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
private func onChangeMaximumDistance(_ item: EQNGenericValue) {
|
||||
currentMaximumDistance = item
|
||||
EQNSeismic.shared.maximumDistance = item.value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
}
|
||||
|
||||
private func updateNotificationSettingsIfNeeded() {
|
||||
// if the switch is enabled, update also the settings notification
|
||||
guard currentModificaImpostazioni == true else { return }
|
||||
|
||||
// update notification settings with current filters
|
||||
EQNNotificheReteSismiche.shared().energiaSisma = EQNSeismic.shared.magnitudoMinima;
|
||||
EQNNotificheReteSismiche.shared().distanzaPosizione = EQNSeismic.shared.distanzaMassima
|
||||
EQNNotificheReteSismiche.shared().isAbilitaVicini = EQNSeismic.shared.sismiQualsiasiAbilitati
|
||||
EQNNotificheReteSismiche.shared().isTerremortiForti = EQNSeismic.shared.sismiFortiAbilitati
|
||||
EQNNotificheReteSismiche.shared().energiaTerremotiForti = EQNSeismic.shared.sismiFortiMagnitudo
|
||||
private func onChangeMinimumMagnitude(_ item: EQNGenericValue) {
|
||||
currentMinimumMagnitude = item
|
||||
EQNSeismic.shared.minimumMagnitude = item.value
|
||||
EQNSeismic.shared.saveFilters()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-12
@@ -11,23 +11,25 @@ import Foundation
|
||||
|
||||
struct SeismicNetworkViewModel {
|
||||
|
||||
var place: String
|
||||
var network: String
|
||||
var isPreliminary: Bool
|
||||
var magnitude: String
|
||||
var depth: String
|
||||
var time: String
|
||||
var distance: String
|
||||
var coordinate: String
|
||||
var population: String
|
||||
var smartphones: String
|
||||
var users: String
|
||||
let place: String
|
||||
let network: String
|
||||
let isPreliminary: Bool
|
||||
let magnitude: String
|
||||
let rawMagnitude: Double
|
||||
let depth: String
|
||||
let time: String
|
||||
let distance: String
|
||||
let coordinate: String
|
||||
let population: String
|
||||
let smartphones: String
|
||||
let users: String
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
init(seismic: EQNSisma) {
|
||||
self.place = seismic.place
|
||||
self.network = seismic.provider
|
||||
self.rawMagnitude = seismic.magnitude.doubleValue
|
||||
|
||||
let isPreliminary = seismic.preliminary.intValue > 0
|
||||
self.isPreliminary = isPreliminary
|
||||
@@ -38,7 +40,7 @@ struct SeismicNetworkViewModel {
|
||||
self.depth = ""
|
||||
} else {
|
||||
self.magnitude = String(format: "%.1f%@", seismic.magnitude.doubleValue, seismic.magnitudeType)
|
||||
self.depth = String(format: "%@ %.1f km", NSLocalizedString("official_depth", comment: ""), seismic.depth.doubleValue)
|
||||
self.depth = String(format: "%.1f km ↓", seismic.depth.doubleValue)
|
||||
}
|
||||
|
||||
// we need to check agains null values, because sometimes WS returns invalid dates
|
||||
|
||||
+116
-48
@@ -16,10 +16,27 @@ protocol SeismicNetworksMapDetailViewControllerDelegate: AnyObject {
|
||||
|
||||
class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
|
||||
private enum PinStyle: CaseIterable {
|
||||
case full
|
||||
case light
|
||||
case circle
|
||||
|
||||
func next() -> Self {
|
||||
let all = Self.allCases
|
||||
let idx = all.firstIndex(of: self)!
|
||||
let next = all.index(after: idx)
|
||||
return all[next == all.endIndex ? all.startIndex : next]
|
||||
}
|
||||
}
|
||||
|
||||
private var pinStyle: PinStyle = .full
|
||||
private let eqnSeismic = EQNSeismic.shared
|
||||
|
||||
// MARK: - State
|
||||
|
||||
override var isCloseButtonVisible: Bool { false }
|
||||
override var isFilterViewVisible: Bool {
|
||||
// a custom filter view id displayed
|
||||
// a custom filter view is displayed
|
||||
true
|
||||
}
|
||||
weak var delegate: SeismicNetworksMapDetailViewControllerDelegate?
|
||||
@@ -42,10 +59,7 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
seismicsFilterLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
||||
seismicsFilterLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0).isActive = true
|
||||
seismicsFilterLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0).isActive = true
|
||||
|
||||
// tap recognizer
|
||||
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(filtersTapped(_:)))
|
||||
view.addGestureRecognizer(tapRecognizer)
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
@@ -76,6 +90,24 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
fatalError("init(coder:) is not available, please use init(seismic:allSeismics:)")
|
||||
}
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func configureUI() {
|
||||
super.configureUI()
|
||||
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .done, primaryAction: .init(handler: { [weak self] _ in
|
||||
self?.dismiss(animated: true)
|
||||
}))
|
||||
navigationItem.rightBarButtonItems = [
|
||||
UIBarButtonItem(image: UIImage(named: "navbar-icon-screenshot"), primaryAction: .init(handler: { [weak self] _ in
|
||||
self?.shareScreenshot()
|
||||
})),
|
||||
UIBarButtonItem(image: UIImage(named: "navbar-icon-pin-arrow"), primaryAction: .init(handler: { [weak self] _ in
|
||||
self?.nextPinStyle()
|
||||
})),
|
||||
]
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func updateSeismics(_ seismics: [EQNSisma]) {
|
||||
@@ -84,7 +116,9 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
}
|
||||
|
||||
override func registerMapAnnotationViews() {
|
||||
mapView.register(EQNCustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.DoubleLineIdentifier)
|
||||
mapView.register(EQNSeismicAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNSeismicAnnotationView.IdentifierFull)
|
||||
mapView.register(EQNSeismicAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNSeismicAnnotationView.IdentifierLight)
|
||||
mapView.register(EQNSeismicAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNSeismicAnnotationView.IdentifierCircle)
|
||||
}
|
||||
|
||||
override func loadDataSource() {
|
||||
@@ -92,14 +126,14 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
|
||||
updateMap(with: annotations)
|
||||
|
||||
// if the given seismic is still in the data source, show circles
|
||||
// otherwise just remove any other circles already on the map
|
||||
if allSeismics.contains(seismic) {
|
||||
addCircles(for: seismic.coordinate)
|
||||
// if the filter is "in radius",
|
||||
// show a circle with selected radius
|
||||
if eqnSeismic.filterOption == .inRadius, let distance = Double(eqnSeismic.maximumDistance) {
|
||||
addCircle(center: EQNUser.default().lastPosition, radius: distance * 1_000)
|
||||
} else {
|
||||
addCircles(for: nil)
|
||||
addCircle(center: nil, radius: 0)
|
||||
}
|
||||
|
||||
|
||||
loadFiltersRecap()
|
||||
}
|
||||
|
||||
@@ -127,31 +161,60 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func loadFiltersRecap() {
|
||||
let filters = FiltersViewModel()
|
||||
|
||||
let recap = "\(NSLocalizedString("filter_filter", comment: "")): "
|
||||
+ "M≥\(filters.magnitude) "
|
||||
+ "D≤\(filters.distance) "
|
||||
+ "T≤\(filters.timeframe)"
|
||||
seismicsFilterLabel.text = recap
|
||||
override func zPriority(for annotation: MKAnnotation) -> MKAnnotationViewZPriority {
|
||||
guard let annotation = annotation as? EQNMapAnnotationSeismic else {
|
||||
return .min
|
||||
}
|
||||
|
||||
// il sisma cliccato dall'utente sta sopra a tutti
|
||||
if annotation.seismic == seismic {
|
||||
return .max
|
||||
}
|
||||
|
||||
// Ordiniamo le annotazioni in base all amagnitudo, quelle con valore maggiore devono stare sopra.
|
||||
// La `zPriority` viene calcolata utilizzando la posizione nella lista
|
||||
let index = mapAnnotations
|
||||
.compactMap { $0 as? EQNMapAnnotationSeismic }
|
||||
.sorted(by: { $0.seismic.magnitude.doubleValue < $1.seismic.magnitude.doubleValue })
|
||||
.firstIndex(where: { $0 == annotation })
|
||||
guard let index else {
|
||||
return .min
|
||||
}
|
||||
|
||||
let priority = Float(index) / Float(mapAnnotations.count)
|
||||
return .init(priority)
|
||||
}
|
||||
|
||||
private func addCircles(for location: CLLocation?) {
|
||||
// MARK: - Private
|
||||
|
||||
private func nextPinStyle() {
|
||||
pinStyle = pinStyle.next()
|
||||
reloadMap()
|
||||
}
|
||||
|
||||
private func loadFiltersRecap() {
|
||||
let filter = EQNSeismic.shared.filterOption
|
||||
|
||||
let text = switch filter {
|
||||
case .inRadius: NSLocalizedString("filter_area", comment: "")
|
||||
case .positionRelevant: NSLocalizedString("filter_relevant", comment: "")
|
||||
case .worldWide: NSLocalizedString("filter_all", comment: "")
|
||||
}
|
||||
seismicsFilterLabel.text = text
|
||||
}
|
||||
|
||||
private func addCircle(
|
||||
center location: CLLocation?,
|
||||
radius: Double
|
||||
) {
|
||||
// remove any previous circles
|
||||
mapView.removeOverlays(mapCircles)
|
||||
mapCircles.removeAll()
|
||||
|
||||
// aggiungiamo 3 cerchi concentrici per il punto specificato (se disponibile)
|
||||
// li inseriamo a a 50, 100 e 200 km.
|
||||
guard let location = location else { return }
|
||||
|
||||
let circles = [
|
||||
MKCircle(center: location.coordinate, radius: 25_000),
|
||||
MKCircle(center: location.coordinate, radius: 100_000),
|
||||
MKCircle(center: location.coordinate, radius: 200_000)
|
||||
MKCircle(center: location.coordinate, radius: radius),
|
||||
]
|
||||
|
||||
// !!note: is important to assign here the circles
|
||||
@@ -162,16 +225,13 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
mapView.addOverlays(circles)
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc override func filtersTapped(_ sender: UIGestureRecognizer) {
|
||||
let controller = SeismicFiltersViewController.makeViewController()
|
||||
controller.delegate = self
|
||||
controller.modalPresentationStyle = .overCurrentContext
|
||||
controller.modalTransitionStyle = .crossDissolve
|
||||
present(controller, animated: true, completion: nil)
|
||||
private func shareScreenshot() {
|
||||
let screenshot = createSnapshot()
|
||||
|
||||
let controller = UIActivityViewController(activityItems: [screenshot], applicationActivities: [])
|
||||
present(controller, animated: true)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Map
|
||||
|
||||
override func setupAnnotationView(for annotation: MKAnnotation, on mapView: MKMapView) -> MKAnnotationView? {
|
||||
@@ -179,15 +239,23 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
return nil
|
||||
}
|
||||
|
||||
let viewModel = SeismicNetworkViewModel(seismic: annotation.seismic)
|
||||
|
||||
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: EQNCustomAnnotationView.DoubleLineIdentifier, for: annotation) as! EQNCustomAnnotationView
|
||||
|
||||
annotationView.image = annotation.image
|
||||
annotationView.title = annotation.title
|
||||
annotationView.subtitle = viewModel.magnitude
|
||||
|
||||
return annotationView
|
||||
let isUserSelection = annotation.seismic == seismic
|
||||
switch pinStyle {
|
||||
case .full, .light:
|
||||
let identifier = pinStyle == .full ? EQNSeismicAnnotationView.IdentifierFull : EQNSeismicAnnotationView.IdentifierLight
|
||||
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation) as! EQNSeismicAnnotationView
|
||||
annotationView.title = annotation.title
|
||||
annotationView.subtitle = annotation.subtitle
|
||||
annotationView.magnitude = String(format: "M%.1f", annotation.seismic.magnitude.doubleValue)
|
||||
annotationView.magnitudeColor = annotation.textColor
|
||||
annotationView.isUserSelection = isUserSelection
|
||||
return annotationView
|
||||
case .circle:
|
||||
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: EQNSeismicAnnotationView.IdentifierCircle, for: annotation) as! EQNSeismicAnnotationView
|
||||
annotationView.image = annotation.image(height: EQNSeismicAnnotationView.CircleViewHeight,
|
||||
isUserSelection: isUserSelection)
|
||||
return annotationView
|
||||
}
|
||||
}
|
||||
|
||||
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
|
||||
@@ -196,8 +264,8 @@ class SeismicNetworksMapDetailViewController: EQNBaseMapViewController {
|
||||
}
|
||||
|
||||
let circle = MKCircleRenderer(overlay: circleOverlay)
|
||||
circle.strokeColor = AppTheme.Colors.darkGray
|
||||
circle.lineWidth = 1.0
|
||||
circle.strokeColor = AppTheme.Colors.red
|
||||
circle.lineWidth = 2.0
|
||||
return circle
|
||||
}
|
||||
}
|
||||
|
||||
+48
-47
@@ -19,14 +19,13 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
}
|
||||
|
||||
private static let SegueIdentifierFilters = "ShowFilters"
|
||||
private static let SegueIdentifierSettings = "ShowSettings"
|
||||
private static let SegueIdentifierSeismicNetworks = "ShowSeismicNetworks"
|
||||
private static let SegueIdentifierCardSettings = "ShowCardSettings"
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
@IBOutlet private weak var tableView: UITableView?
|
||||
@IBOutlet private weak var expandeCollapseButton: UIBarButtonItem!
|
||||
@IBOutlet private weak var sortButton: UIBarButtonItem!
|
||||
weak var currentMapController: SeismicNetworksMapDetailViewController?
|
||||
|
||||
/// The ad loader
|
||||
@@ -51,15 +50,9 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
super.viewDidLoad()
|
||||
|
||||
setupUI()
|
||||
checkForLocation()
|
||||
refreshUI()
|
||||
|
||||
// only the first time, show the popup for country selection
|
||||
let alreadyPresented = UserDefaults.standard.bool(forKey: EQNUserDefaultKeyOneShotShowCountry)
|
||||
if !alreadyPresented {
|
||||
performSegue(withIdentifier: Self.SegueIdentifierSettings, sender: nil)
|
||||
UserDefaults.standard.setValue(true, forKey: EQNUserDefaultKeyOneShotShowCountry)
|
||||
}
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveDownloadCompleteNotification(_:)), name: .EQNDownloadDataDidComplete, object: nil)
|
||||
}
|
||||
|
||||
@@ -74,9 +67,35 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
|
||||
tableView?.estimatedRowHeight = 300.0
|
||||
tableView?.rowHeight = UITableView.automaticDimension
|
||||
tableView?.register(SeismicNetworkTableViewCell.self, forCellReuseIdentifier: SeismicNetworkTableViewCell.Identifier)
|
||||
tableView?.register(SeismicNetworkAdvertiseTableViewCell.self, forCellReuseIdentifier: SeismicNetworkAdvertiseTableViewCell.Identifier)
|
||||
tableView?.registerCell(for: SeismicNetworkTableViewCell.self)
|
||||
tableView?.registerCell(for: SeismicNetworkAdvertiseTableViewCell.self)
|
||||
tableView?.emptyDataSetSource = self
|
||||
|
||||
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() {
|
||||
// check if a valid location is available,
|
||||
// otherwise change the filter settings
|
||||
if EQNUser.default().lastPosition == nil {
|
||||
EQNSeismic.shared.filterOption = .worldWide
|
||||
EQNSeismic.shared.saveFilters()
|
||||
}
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
@@ -85,14 +104,6 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
if let controller = segue.destination as? SeismicFiltersViewController {
|
||||
controller.delegate = self
|
||||
}
|
||||
case Self.SegueIdentifierSettings:
|
||||
if let controller = segue.destination as? SeismicSettingsViewController {
|
||||
controller.delegate = self
|
||||
}
|
||||
case Self.SegueIdentifierSeismicNetworks:
|
||||
if let navController = segue.destination as? UINavigationController, let controller = navController.viewControllers.first as? SeismicSettingsNetworksViewController {
|
||||
controller.delegate = self
|
||||
}
|
||||
case Self.SegueIdentifierCardSettings:
|
||||
if let controller = segue.destination as? SeismicCardSettingsViewController {
|
||||
controller.delegate = self
|
||||
@@ -106,7 +117,8 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
let seismics = getSeismics()
|
||||
let controller = SeismicNetworksMapDetailViewController(seismic: seismic, allSeismics: seismics)
|
||||
controller.delegate = self
|
||||
present(controller, animated: true, completion: nil)
|
||||
let navController = UINavigationController(rootViewController: controller)
|
||||
present(navController, animated: true, completion: nil)
|
||||
|
||||
self.currentMapController = controller
|
||||
}
|
||||
@@ -176,6 +188,14 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
return seismics
|
||||
}
|
||||
|
||||
private func changeSort(to sort: EQNSeismic.Sort) {
|
||||
EQNSeismic.shared.sort = sort
|
||||
EQNSeismic.shared.saveFilters()
|
||||
|
||||
setupSortMenu()
|
||||
refreshUI()
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func refreshDataTapped(_ sender: Any) {
|
||||
@@ -185,11 +205,7 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
@IBAction func openFilterTapped(_ sender: Any) {
|
||||
performSegue(withIdentifier: Self.SegueIdentifierFilters, sender: nil)
|
||||
}
|
||||
|
||||
@IBAction func openSettingsTapped(_ sender: Any) {
|
||||
performSegue(withIdentifier: Self.SegueIdentifierSettings, sender: nil)
|
||||
}
|
||||
|
||||
|
||||
@IBAction func collapseExpandTapped(_ sender: Any) {
|
||||
if informations.contains(.buttons) {
|
||||
informations.removeAll(where: { $0 == .buttons })
|
||||
@@ -211,7 +227,7 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
let row = rows[indexPath.row]
|
||||
switch row {
|
||||
case .seismic(let seismic):
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: SeismicNetworkTableViewCell.Identifier, for: indexPath) as! SeismicNetworkTableViewCell
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SeismicNetworkTableViewCell.self, for: indexPath)
|
||||
|
||||
var type = SeismicNetworkTableViewCell.DisplayType.normal
|
||||
if openMapIndexPath == indexPath {
|
||||
@@ -222,7 +238,7 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
cell.delegate = self
|
||||
return cell
|
||||
case .advertise(let nativeAd):
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: SeismicNetworkAdvertiseTableViewCell.Identifier, for: indexPath) as! SeismicNetworkAdvertiseTableViewCell
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SeismicNetworkAdvertiseTableViewCell.self, for: indexPath)
|
||||
cell.loadNativeAd(nativeAd)
|
||||
return cell
|
||||
}
|
||||
@@ -375,24 +391,6 @@ extension SeismicNetworksViewController: SeismicFiltersViewControllerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
extension SeismicNetworksViewController: SeismicSettingsViewControllerDelegate {
|
||||
func seismicSettingsControllerDidComplete(_ controller: SeismicSettingsViewController) {
|
||||
// riscarichiamo i dati, le reti selezionate potrebbero essere cambiate
|
||||
loadData(forced: true)
|
||||
}
|
||||
|
||||
func seismicSettingsControllerWillOpenProviders(_ controller: SeismicSettingsViewController) {
|
||||
performSegue(withIdentifier: Self.SegueIdentifierSeismicNetworks, sender: nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension SeismicNetworksViewController: SeismicSettingsNetworksViewControllerDelegate {
|
||||
func seismicSettingsNetworksControllerDidComplete(_ controller: SeismicSettingsNetworksViewController) {
|
||||
// riscarichiamo i dati, le reti selezionate potrebbero essere cambiate
|
||||
loadData(forced: true)
|
||||
}
|
||||
}
|
||||
|
||||
extension SeismicNetworksViewController: SeismicCardSettingsViewControllerDelegate {
|
||||
func seismicCardSettingsDidComplete(_ controller: SeismicCardSettingsViewController) {
|
||||
refreshUI()
|
||||
@@ -400,9 +398,12 @@ extension SeismicNetworksViewController: SeismicCardSettingsViewControllerDelega
|
||||
}
|
||||
|
||||
extension SeismicNetworksViewController: DZNEmptyDataSetSource {
|
||||
func title(forEmptyDataSet scrollView: UIScrollView!) -> NSAttributedString! {
|
||||
func title(forEmptyDataSet scrollView: UIScrollView) -> NSAttributedString? {
|
||||
let text = EQNSeismic.shared.filterOption == .positionRelevant
|
||||
? NSLocalizedString("filter_empty_relevant", comment: "")
|
||||
: NSLocalizedString("filter_empty_area", comment: "")
|
||||
let attributes = [ NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body) ]
|
||||
let string = NSAttributedString(string: NSLocalizedString("filter_empty", comment: ""), attributes: attributes)
|
||||
let string = NSAttributedString(string: text, attributes: attributes)
|
||||
return string
|
||||
}
|
||||
}
|
||||
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
//
|
||||
// SeismicSettingsNetworksViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Busi Andrea on 14/09/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
protocol SeismicSettingsNetworksViewControllerDelegate: AnyObject {
|
||||
func seismicSettingsNetworksControllerDidComplete(_ controller: SeismicSettingsNetworksViewController)
|
||||
}
|
||||
|
||||
class SeismicSettingsNetworksViewController: UITableViewController {
|
||||
|
||||
weak var delegate: SeismicSettingsNetworksViewControllerDelegate?
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private var networks = [EQNSeismicNetwork]()
|
||||
private var savedNetworks = [String]()
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
tableView.register(SettingDetailTableViewCell.self, forCellReuseIdentifier: SettingDetailTableViewCell.Identifier)
|
||||
tableView.register(SettingSectionHeaderView.self, forHeaderFooterViewReuseIdentifier: SettingSectionHeaderView.Identifier)
|
||||
|
||||
loadData()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func loadData() {
|
||||
networks = EQNData.seismicNetworks().sorted(by: { $0.acronym < $1.acronym })
|
||||
|
||||
// load saved selected networks or fill with all available networks
|
||||
let savedNetworks = EQNUserData.shared.seismicNetworksSelected()
|
||||
if !savedNetworks.isEmpty {
|
||||
self.savedNetworks = savedNetworks
|
||||
} else {
|
||||
self.savedNetworks = EQNData.seismicNetworkAcronyms()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Table view data source
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: SettingSectionHeaderView.Identifier) as! SettingSectionHeaderView
|
||||
headerView.titleLabel.text = NSLocalizedString("options_agencies", comment: "");
|
||||
return headerView
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
CGFloat(SettingSectionHeaderView.Height)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
networks.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let network = networks[indexPath.row]
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: SettingDetailTableViewCell.Identifier, for: indexPath) as! SettingDetailTableViewCell
|
||||
cell.textLabel?.text = "\(network.acronym) (\(network.country))"
|
||||
|
||||
if savedNetworks.contains(network.acronym) {
|
||||
cell.accessoryType = .checkmark
|
||||
} else {
|
||||
cell.accessoryType = .none
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
let network = networks[indexPath.row]
|
||||
if let index = savedNetworks.firstIndex(of: network.acronym) {
|
||||
savedNetworks.remove(at: index)
|
||||
} else {
|
||||
savedNetworks.append(network.acronym)
|
||||
}
|
||||
|
||||
// reload all rows with the given acronym
|
||||
let indexes = networks
|
||||
.enumerated()
|
||||
.filter { $0.element.acronym == network.acronym }
|
||||
.map { IndexPath(row: $0.offset, section: 0) }
|
||||
tableView.reloadRows(at: indexes, with: .automatic)
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func cancelTapped(_ sender: Any) {
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func saveTapped(_ sender: Any) {
|
||||
// save selected networks
|
||||
EQNUserData.shared.saveSelectedSeismicNetworks(savedNetworks)
|
||||
|
||||
// se solo un'ente è selezionato, salviamolo anche come nazione
|
||||
if savedNetworks.count == 1 {
|
||||
UserDefaults.standard.set(savedNetworks.first!, forKey: IMPOSTAZIONE_NAZIONE_RETI_SISMICHE)
|
||||
} else {
|
||||
UserDefaults.standard.removeObject(forKey: IMPOSTAZIONE_NAZIONE_RETI_SISMICHE)
|
||||
}
|
||||
|
||||
delegate?.seismicSettingsNetworksControllerDidComplete(self)
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
//
|
||||
// SeismicSettingsViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Busi Andrea on 13/09/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
protocol SeismicSettingsViewControllerDelegate: AnyObject {
|
||||
func seismicSettingsControllerDidComplete(_ controller: SeismicSettingsViewController)
|
||||
func seismicSettingsControllerWillOpenProviders(_ controller: SeismicSettingsViewController)
|
||||
}
|
||||
|
||||
|
||||
class SeismicSettingsViewController: UIViewController {
|
||||
|
||||
weak var delegate: SeismicSettingsViewControllerDelegate?
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@IBOutlet private weak var containerView: UIView!
|
||||
@IBOutlet private weak var titleLabel: UILabel!
|
||||
@IBOutlet private weak var countryTextField: UITextField!
|
||||
@IBOutlet private weak var confirmButton: UIButton!
|
||||
@IBOutlet private weak var otherwiseLabel: UILabel!
|
||||
@IBOutlet private weak var manageNetworksButton: UIButton!
|
||||
@IBOutlet private weak var cancelButton: UIButton!
|
||||
|
||||
|
||||
private let networks = EQNData.seismicNetworks().sorted(by: { $0.country < $1.country })
|
||||
private let picker = EQNGenericPickerViewController()
|
||||
private var selectedNetwork: EQNSeismicNetwork?
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setupUI()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupUI() {
|
||||
containerView.layer.cornerRadius = AppTheme.shared.cardCornerRadius
|
||||
containerView.layer.masksToBounds = true
|
||||
|
||||
// localize
|
||||
titleLabel.text = NSLocalizedString("official_select_country", comment: "")
|
||||
countryTextField.placeholder = NSLocalizedString("official_select_country_placeholder", comment: "")
|
||||
confirmButton.setLocalizedTitle(key: "official_select_confirm", uppercased: false)
|
||||
otherwiseLabel.text = NSLocalizedString("official_select_or", comment: "")
|
||||
manageNetworksButton.setLocalizedTitle(key: "official_select_networks", uppercased: false)
|
||||
cancelButton.setLocalizedTitle(key: "status_cancel", uppercased: false)
|
||||
|
||||
// load saved country (if exists)
|
||||
let savedCountry = UserDefaults.standard.object(forKey: IMPOSTAZIONE_NAZIONE_RETI_SISMICHE) as? String
|
||||
selectedNetwork = EQNData.seismic(for: savedCountry)
|
||||
|
||||
countryTextField.text = selectedNetwork?.country
|
||||
countryTextField.inputView = picker.view
|
||||
|
||||
let selectedIndex: Int? = selectedNetwork != nil ? networks.firstIndex(of: selectedNetwork!) : nil
|
||||
picker.configure(with: networks, selectedIndex: selectedIndex) { [unowned self] (network) in
|
||||
guard let network = network as? EQNSeismicNetwork else { return }
|
||||
|
||||
self.view.endEditing(true)
|
||||
self.selectedNetwork = network
|
||||
self.countryTextField.text = self.selectedNetwork?.country
|
||||
}
|
||||
picker.onCancel = { [unowned self] in
|
||||
self.view.endEditing(true)
|
||||
}
|
||||
}
|
||||
|
||||
private func performSave(for network: EQNSeismicNetwork) {
|
||||
// salviamo la sigla dell'ente selezionato
|
||||
UserDefaults.standard.set(network.acronym, forKey: IMPOSTAZIONE_NAZIONE_RETI_SISMICHE)
|
||||
|
||||
// gli enti selezionati conterranno solo l'ente della nazione selezionata
|
||||
let selectedNetworks = [network.acronym]
|
||||
EQNUserData.shared.saveSelectedSeismicNetworks(selectedNetworks)
|
||||
|
||||
// aggiorniamo le impostazioni di notifica
|
||||
EQNNotificheReteSismiche.shared().listaEnti = selectedNetworks
|
||||
EQNNotificheReteSismiche.shared().saveUserInfo()
|
||||
SettingsBaseViewController.saveSettings()
|
||||
|
||||
// informiamo il delegato
|
||||
delegate?.seismicSettingsControllerDidComplete(self)
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func confirmCountryTapped(_ sender: UIButton) {
|
||||
guard let network = selectedNetwork else {
|
||||
let alert = UIAlertController(title: NSLocalizedString("attention", comment: ""),
|
||||
message: NSLocalizedString("official_no_country_selected", comment: ""),
|
||||
preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: ""), style: .cancel, handler: { [unowned self] (action) in
|
||||
self.countryTextField.becomeFirstResponder()
|
||||
}))
|
||||
present(alert, animated: true, completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ask confirm to change settings for notifications
|
||||
let alert = UIAlertController(title: NSLocalizedString("attention", comment: ""),
|
||||
message: NSLocalizedString("official_select_message", comment: ""),
|
||||
preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("status_cancel", comment: ""), style: .cancel))
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("official_select_confirm", comment: ""), style: .default, handler: { [unowned self] (action) in
|
||||
self.performSave(for: network)
|
||||
}))
|
||||
present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func selectNetworksTapped(_ sender: UIButton) {
|
||||
delegate?.seismicSettingsControllerWillOpenProviders(self)
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func cancelTapped(_ sender: UIButton) {
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -11,27 +11,27 @@ import Foundation
|
||||
|
||||
class SettingDateTableViewCell: UITableViewCell {
|
||||
|
||||
@objc static let Identifier = "DateCell"
|
||||
static let Identifier = "DateCell"
|
||||
|
||||
@objc var isDisabled: Bool = false {
|
||||
var isDisabled: Bool = false {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
@objc var isPickerVisible: Bool = false {
|
||||
var isPickerVisible: Bool = false {
|
||||
didSet {
|
||||
if oldValue != isPickerVisible {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
}
|
||||
@objc private(set) var date = Date()
|
||||
@objc var valueChanged: ((Date) -> Void)?
|
||||
private(set) var date = Date()
|
||||
var valueChanged: ((Date) -> Void)?
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
@objc lazy var titleLabel: UILabel = {
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
@@ -40,7 +40,7 @@ class SettingDateTableViewCell: UITableViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
@objc lazy var valuesLabel: UILabel = {
|
||||
lazy var valuesLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
@@ -58,7 +58,7 @@ class SettingDateTableViewCell: UITableViewCell {
|
||||
return picker
|
||||
}()
|
||||
|
||||
@objc lazy var stackView: UIStackView = {
|
||||
lazy var stackView: UIStackView = {
|
||||
let stackView = UIStackView()
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.axis = .vertical
|
||||
@@ -81,7 +81,7 @@ class SettingDateTableViewCell: UITableViewCell {
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
@objc public func updateDate(_ date: Date) {
|
||||
public func updateDate(_ date: Date) {
|
||||
self.date = date
|
||||
datePicker.setDate(date, animated: true)
|
||||
}
|
||||
|
||||
+3
-4
@@ -10,17 +10,16 @@ import UIKit
|
||||
|
||||
class SettingDetailTableViewCell: UITableViewCell {
|
||||
|
||||
@objc static let Identifier = "DetailCell"
|
||||
static let Identifier = "DetailCell"
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// Initialization code
|
||||
}
|
||||
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-7
@@ -10,10 +10,10 @@ import UIKit
|
||||
|
||||
class SettingEnableTableViewCell: UITableViewCell {
|
||||
|
||||
@objc static let Identifier = "EnableCell"
|
||||
static let Identifier = "EnableCell"
|
||||
|
||||
@objc var valueChanged: ((Bool) -> Void)?
|
||||
@objc var isDisabled: Bool = false {
|
||||
var valueChanged: ((Bool) -> Void)?
|
||||
var isDisabled: Bool = false {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class SettingEnableTableViewCell: UITableViewCell {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
@objc lazy var titleLabel: UILabel = {
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
@@ -29,7 +29,7 @@ class SettingEnableTableViewCell: UITableViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
@objc lazy var descriptionLabel: UILabel = {
|
||||
lazy var descriptionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
@@ -37,7 +37,7 @@ class SettingEnableTableViewCell: UITableViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
@objc lazy var toggleSwitch: UISwitch = {
|
||||
lazy var toggleSwitch: UISwitch = {
|
||||
let toggle = UISwitch()
|
||||
toggle.setContentHuggingPriority(.required, for: .horizontal)
|
||||
toggle.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
@@ -45,6 +45,15 @@ class SettingEnableTableViewCell: UITableViewCell {
|
||||
return toggle
|
||||
}()
|
||||
|
||||
lazy var errorLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.font = UIFont.preferredFont(forTextStyle: .subheadline)
|
||||
label.textColor = AppTheme.Colors.red
|
||||
label.text = nil
|
||||
return label
|
||||
}()
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
@@ -75,6 +84,7 @@ class SettingEnableTableViewCell: UITableViewCell {
|
||||
|
||||
contentView.addSubview(stackView)
|
||||
contentView.addSubview(descriptionLabel)
|
||||
contentView.addSubview(errorLabel)
|
||||
|
||||
stackView.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor).isActive = true
|
||||
stackView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor).isActive = true
|
||||
@@ -83,7 +93,12 @@ class SettingEnableTableViewCell: UITableViewCell {
|
||||
descriptionLabel.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 8).isActive = true
|
||||
descriptionLabel.trailingAnchor.constraint(equalTo: stackView.trailingAnchor).isActive = true
|
||||
descriptionLabel.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true
|
||||
descriptionLabel.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor).isActive = true
|
||||
//descriptionLabel.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor).isActive = true
|
||||
|
||||
errorLabel.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 8.0).isActive = true
|
||||
errorLabel.trailingAnchor.constraint(equalTo: descriptionLabel.trailingAnchor).isActive = true
|
||||
errorLabel.leadingAnchor.constraint(equalTo: descriptionLabel.leadingAnchor).isActive = true
|
||||
errorLabel.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor).isActive = true
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
|
||||
+4
-4
@@ -11,9 +11,9 @@ import Foundation
|
||||
|
||||
class SettingMultivaluesTableViewCell: UITableViewCell {
|
||||
|
||||
@objc static let Identifier = "MultivaluesCell"
|
||||
static let Identifier = "MultivaluesCell"
|
||||
|
||||
@objc var isDisabled: Bool = false {
|
||||
var isDisabled: Bool = false {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class SettingMultivaluesTableViewCell: UITableViewCell {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
@objc lazy var titleLabel: UILabel = {
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
@@ -30,7 +30,7 @@ class SettingMultivaluesTableViewCell: UITableViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
@objc lazy var valuesLabel: UILabel = {
|
||||
lazy var valuesLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
|
||||
+3
-6
@@ -10,18 +10,17 @@ import UIKit
|
||||
|
||||
class SettingSectionHeaderView: UITableViewHeaderFooterView {
|
||||
|
||||
@objc static let Identifier = "SectionHeaderView"
|
||||
@objc static let Height = 50.0
|
||||
static let Identifier = "SectionHeaderView"
|
||||
static let Height = 50.0
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
@objc lazy var titleLabel: UILabel = {
|
||||
lazy var titleLabel: UILabel = {
|
||||
let titleLabel = UILabel()
|
||||
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
|
||||
titleLabel.textColor = AppTheme.Colors.lightBlue
|
||||
return titleLabel
|
||||
}()
|
||||
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
@@ -34,7 +33,6 @@ class SettingSectionHeaderView: UITableViewHeaderFooterView {
|
||||
super.init(coder: coder)
|
||||
setupUI()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@@ -45,6 +43,5 @@ class SettingSectionHeaderView: UITableViewHeaderFooterView {
|
||||
titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
|
||||
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
|
||||
titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -11,19 +11,19 @@ import Foundation
|
||||
|
||||
class SettingSegmentedTableViewCell: UITableViewCell {
|
||||
|
||||
@objc static let Identifier = "SegmentedCell"
|
||||
static let Identifier = "SegmentedCell"
|
||||
|
||||
@objc var isDisabled: Bool = false {
|
||||
var isDisabled: Bool = false {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@objc var valueChanged: ((EQNGenericValue) -> Void)?
|
||||
var valueChanged: ((EQNGenericValue) -> Void)?
|
||||
private var items = [EQNGenericValue]()
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
@objc lazy var titleLabel: UILabel = {
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
@@ -32,7 +32,7 @@ class SettingSegmentedTableViewCell: UITableViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
@objc lazy var segmentedControl: UISegmentedControl = {
|
||||
lazy var segmentedControl: UISegmentedControl = {
|
||||
let segmented = UISegmentedControl()
|
||||
segmented.translatesAutoresizingMaskIntoConstraints = false
|
||||
segmented.addTarget(self, action: #selector(segmentedControlChanged(_:)), for: .valueChanged)
|
||||
|
||||
+7
-7
@@ -10,21 +10,21 @@ import UIKit
|
||||
|
||||
class SettingSliderTableViewCell: UITableViewCell {
|
||||
|
||||
@objc static let Identifier = "SliderCell"
|
||||
static let Identifier = "SliderCell"
|
||||
|
||||
@objc var isDisabled: Bool = false {
|
||||
var isDisabled: Bool = false {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@objc var valueChanged: ((EQNGenericValue) -> Void)?
|
||||
@objc var dragEnded: (() -> Void)?
|
||||
var valueChanged: ((EQNGenericValue) -> Void)?
|
||||
var dragEnded: (() -> Void)?
|
||||
private var items = [EQNGenericValue]()
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
@objc lazy var titleLabel: UILabel = {
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
@@ -33,7 +33,7 @@ class SettingSliderTableViewCell: UITableViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
@objc lazy var valueLabel: UILabel = {
|
||||
lazy var valueLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
@@ -42,7 +42,7 @@ class SettingSliderTableViewCell: UITableViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
@objc lazy var slider: UISlider = {
|
||||
lazy var slider: UISlider = {
|
||||
let slider = UISlider()
|
||||
slider.isContinuous = true
|
||||
slider.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// SettingsBaseTableViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 10/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
class SettingsBaseTableViewController: UITableViewController {
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
if isMovingFromParent {
|
||||
Self.saveSettings()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Class
|
||||
|
||||
@objc class func saveSettings() {
|
||||
saveSettings { _ in
|
||||
// nope
|
||||
}
|
||||
}
|
||||
|
||||
@objc class func saveSettings(
|
||||
completion: @escaping (_ success: Bool) -> Void
|
||||
) {
|
||||
|
||||
let url = EQNGeneratoreURLServer.urlInvioImpostazioniNotifiche()
|
||||
ServerRequest.default().inviaInformazioniAlServer(with: url, richiesta: .impostazioniNotifiche) { _ in
|
||||
print("[SETTINGS] Settings saved successfully")
|
||||
completion(true)
|
||||
} failure: { error in
|
||||
print("[SETTINGS] Settings saved failed. Error: \(error?.localizedDescription ?? "n.d.")")
|
||||
completion(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// SettingsBaseViewController.h
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Busi Andrea on 30/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SettingsBaseViewController : UITableViewController
|
||||
|
||||
+ (void)saveSettings;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,42 +0,0 @@
|
||||
//
|
||||
// SettingsBaseViewController.m
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Busi Andrea on 30/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SettingsBaseViewController.h"
|
||||
#import "ServerRequest.h"
|
||||
#import "EQNGeneratoreURLServer.h"
|
||||
|
||||
@interface SettingsBaseViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation SettingsBaseViewController
|
||||
|
||||
#pragma mark - View Lifecycle
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// when controller is dismissed, save settings
|
||||
if (self.isMovingFromParentViewController) {
|
||||
[SettingsBaseViewController saveSettings];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
+ (void)saveSettings
|
||||
{
|
||||
[[ServerRequest defaultServerConnectionSingleton] inviaInformazioniAlServerWithURL:[EQNGeneratoreURLServer urlInvioImpostazioniNotifiche] richiesta:EQNTipoChiamataImpostazioniNotifiche success:^(id result){
|
||||
NSLog(@"Settings saved successfully");
|
||||
} failure:^(NSError *error){
|
||||
NSLog(@"Settings saved failed. Error: %@", error.localizedDescription);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// AletaSismiTableViewController.h
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi 25/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "SettingsBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SettingsRealTimeAlertsViewController : SettingsBaseViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
-165
@@ -1,165 +0,0 @@
|
||||
//
|
||||
// AletaSismiTableViewController.m
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi 25/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SettingsRealTimeAlertsViewController.h"
|
||||
#import "EQNAllertaSismica.h"
|
||||
@import UserNotifications;
|
||||
|
||||
@interface SettingsRealTimeAlertsViewController () <UITextFieldDelegate>
|
||||
|
||||
@property (nonatomic, strong) NSArray<SettingItem *> *settings;
|
||||
|
||||
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
|
||||
|
||||
@property (nonatomic, assign) BOOL notificationEnabled;
|
||||
@property (nonatomic, assign) BOOL criticalAlertsEnabled;
|
||||
@end
|
||||
|
||||
@implementation SettingsRealTimeAlertsViewController
|
||||
|
||||
typedef NS_ENUM(NSInteger, RowIdentifier) {
|
||||
RowIdentifierAbilitaNotifiche = 0,
|
||||
RowIdentifierAbilitaCriticalAlerts
|
||||
};
|
||||
|
||||
#pragma mark - Accessories
|
||||
|
||||
- (NSDateFormatter *)dateFormatter
|
||||
{
|
||||
if (!_dateFormatter) {
|
||||
_dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[_dateFormatter setDateFormat:@"HH:mm"];
|
||||
}
|
||||
return _dateFormatter;
|
||||
}
|
||||
|
||||
#pragma mark - View Lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self setupUI];
|
||||
|
||||
self.settings = @[
|
||||
[[SettingItem alloc] initWithType:SettingTypeEnable title:NSLocalizedString(@"options_notification_enable_alarm", @"")],
|
||||
[[SettingItem alloc] initWithType:SettingTypeEnable title:NSLocalizedString(@"critical_alerts_setting", @"")]
|
||||
];
|
||||
|
||||
[self loadDataSource];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)setupUI
|
||||
{
|
||||
self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeNever;
|
||||
|
||||
self.tableView.estimatedRowHeight = 200.0;
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
[self.tableView registerClass:[SettingSectionHeaderView class] forHeaderFooterViewReuseIdentifier:SettingSectionHeaderView.Identifier];
|
||||
[self.tableView registerClass:[SettingEnableTableViewCell class] forCellReuseIdentifier:SettingEnableTableViewCell.Identifier];
|
||||
[self.tableView registerClass:[SettingSliderTableViewCell class] forCellReuseIdentifier:SettingSliderTableViewCell.Identifier];
|
||||
[self.tableView registerClass:[SettingMultivaluesTableViewCell class] forCellReuseIdentifier:SettingMultivaluesTableViewCell.Identifier];
|
||||
[self.tableView registerClass:[SettingSegmentedTableViewCell class] forCellReuseIdentifier:SettingSegmentedTableViewCell.Identifier];
|
||||
[self.tableView registerClass:[SettingDateTableViewCell class] forCellReuseIdentifier:SettingDateTableViewCell.Identifier];
|
||||
}
|
||||
|
||||
- (void)loadDataSource
|
||||
{
|
||||
self.notificationEnabled = [EQNAllertaSismica sharedInstance].isAbilitato;
|
||||
self.criticalAlertsEnabled = [EQNAllertaSismica sharedInstance].isCriticalAlertsEnabled;
|
||||
|
||||
[[EQNAllertaSismica sharedInstance] saveUserInfo];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.settings.count;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
SettingSectionHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SettingSectionHeaderView.Identifier];
|
||||
headerView.titleLabel.text = NSLocalizedString(@"options_alarms", @"");
|
||||
return headerView;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
return SettingSectionHeaderView.Height;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
SettingItem *setting = self.settings[indexPath.row];
|
||||
|
||||
if (setting.type == SettingTypeEnable) {
|
||||
SettingEnableTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingEnableTableViewCell.Identifier forIndexPath:indexPath];
|
||||
cell.titleLabel.text = setting.displayTitle;
|
||||
cell.descriptionLabel.text = setting.subtitle;
|
||||
|
||||
if (indexPath.row == RowIdentifierAbilitaNotifiche) {
|
||||
cell.toggleSwitch.on = self.notificationEnabled;
|
||||
cell.valueChanged = ^(BOOL enabled) {
|
||||
self.notificationEnabled = enabled;
|
||||
[EQNAllertaSismica sharedInstance].isAbilitato = self.notificationEnabled;
|
||||
[[EQNAllertaSismica sharedInstance] saveUserInfo];
|
||||
[self.tableView reloadData];
|
||||
};
|
||||
} else if (indexPath.row == RowIdentifierAbilitaCriticalAlerts) {
|
||||
cell.toggleSwitch.on = self.criticalAlertsEnabled;
|
||||
cell.valueChanged = ^(BOOL enabled) {
|
||||
if (enabled) {
|
||||
[self askForCriticalAlertsPermission];
|
||||
}
|
||||
|
||||
self.criticalAlertsEnabled = enabled;
|
||||
[EQNAllertaSismica sharedInstance].isCriticalAlertsEnabled = self.criticalAlertsEnabled;
|
||||
[[EQNAllertaSismica sharedInstance] saveUserInfo];
|
||||
[self.tableView reloadData];
|
||||
};
|
||||
}
|
||||
|
||||
return cell;
|
||||
} else if (setting.type == SettingTypeSegmented) {
|
||||
SettingSegmentedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingSegmentedTableViewCell.Identifier forIndexPath:indexPath];
|
||||
cell.titleLabel.text = setting.displayTitle;
|
||||
return cell;
|
||||
} else if (setting.type == SettingTypeSlider) {
|
||||
SettingSliderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingSliderTableViewCell.Identifier forIndexPath:indexPath];
|
||||
cell.titleLabel.text = setting.displayTitle;
|
||||
return cell;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)updateSismicToNotify:(EQNGenericValue *)seismic
|
||||
{
|
||||
[EQNAllertaSismica sharedInstance].sismiDaNotificare = seismic.value;
|
||||
[[EQNAllertaSismica sharedInstance] saveUserInfo];
|
||||
|
||||
[self loadDataSource];
|
||||
}
|
||||
|
||||
- (void)askForCriticalAlertsPermission
|
||||
{
|
||||
UNAuthorizationOptions authOptions = UNAuthorizationOptionCriticalAlert;
|
||||
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError *error) {
|
||||
// nope
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// SettingsRealTimeAlertsViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 10/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Shogun
|
||||
|
||||
class SettingsRealTimeAlertsViewController: SettingsBaseTableViewController {
|
||||
|
||||
private enum RowIdentifier: Int {
|
||||
case abilitaNotifiche
|
||||
case abilitaCriticalAlerts
|
||||
}
|
||||
|
||||
private var isNotificationEnabled = false
|
||||
private var isCriticalAlertsEnabled = false
|
||||
|
||||
private let settings: [SettingItem] = [
|
||||
.init(type: .enable, title: NSLocalizedString("options_notification_enable_alarm", comment: "")),
|
||||
.init(type: .enable, title: NSLocalizedString("critical_alerts_setting", comment: ""))
|
||||
]
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setupUI()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
loadDataSource()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupUI() {
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
|
||||
tableView.estimatedRowHeight = 200.0
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.registerHeaderFooterView(for: SettingSectionHeaderView.self)
|
||||
tableView.registerCell(for: SettingEnableTableViewCell.self)
|
||||
}
|
||||
|
||||
private func loadDataSource() {
|
||||
let saved = EQNSettingRealTimeAlert.shared
|
||||
|
||||
isNotificationEnabled = saved.isAbilitato
|
||||
isCriticalAlertsEnabled = saved.isCriticalAlertsEnabled
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate and data source
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let view = tableView.dequeueHeaderFooterView(cellIdentifiable: SettingSectionHeaderView.self)
|
||||
view.titleLabel.text = NSLocalizedString("options_alarms", comment: "")
|
||||
return view
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
SettingSectionHeaderView.Height
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return settings.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
guard let identifier = RowIdentifier(rawValue: indexPath.row) else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
|
||||
let setting = settings[indexPath.row]
|
||||
switch setting.type {
|
||||
case .enable:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingEnableTableViewCell.self, for: indexPath)
|
||||
cell.titleLabel.text = setting.displayTitle
|
||||
cell.descriptionLabel.text = setting.subtitle
|
||||
|
||||
switch identifier {
|
||||
case .abilitaNotifiche:
|
||||
cell.toggleSwitch.isOn = isNotificationEnabled
|
||||
cell.valueChanged = { [weak self] enabled in
|
||||
self?.onChangeNotificationEnabled(enabled)
|
||||
}
|
||||
case .abilitaCriticalAlerts:
|
||||
cell.toggleSwitch.isOn = isCriticalAlertsEnabled
|
||||
cell.valueChanged = { [weak self] enabled in
|
||||
self?.onChangeCriticalAlertsEnabled(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
return cell
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func onChangeNotificationEnabled(_ enabled: Bool) {
|
||||
isNotificationEnabled = enabled
|
||||
EQNSettingRealTimeAlert.shared.isAbilitato = isNotificationEnabled
|
||||
EQNSettingRealTimeAlert.shared.saveUserInfo()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
private func onChangeCriticalAlertsEnabled(_ enabled: Bool) {
|
||||
isCriticalAlertsEnabled = enabled
|
||||
EQNSettingRealTimeAlert.shared.isCriticalAlertsEnabled = isCriticalAlertsEnabled
|
||||
EQNSettingRealTimeAlert.shared.saveUserInfo()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// SettingsSeismicNetworkAlertsViewController.h
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi 25/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "SettingsBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SettingsSeismicNetworkAlertsViewController : SettingsBaseViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
-258
@@ -1,258 +0,0 @@
|
||||
//
|
||||
// SettingsSeismicNetworkAlertsViewController.m
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi 25/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SettingsSeismicNetworkAlertsViewController.h"
|
||||
#import "EQNNotificheReteSismiche.h"
|
||||
|
||||
@interface SettingsSeismicNetworkAlertsViewController ()
|
||||
|
||||
@property (nonatomic, strong) NSArray<SettingItem *> *settings;
|
||||
@property (nonatomic, strong) NSArray<EQNGenericValue *> *dataSourceRaggioSisma;
|
||||
@property (nonatomic, strong) NSArray<EQNGenericValue *> *dataSourceMagnitudoDeboli;
|
||||
@property (nonatomic, strong) NSArray<EQNGenericValue *> *dataSourceMagnitudoForti;
|
||||
|
||||
@property (nonatomic, assign) BOOL notificationEnabled;
|
||||
@property (nonatomic, assign) BOOL notificationNearEarthquakeEnabled;
|
||||
@property (nonatomic, assign) BOOL notificationStrongEarthquakeEnabled;
|
||||
|
||||
@property (nonatomic, strong) EQNGenericValue *currentUserPositionRadius;
|
||||
@property (nonatomic, strong) EQNGenericValue *currentSeismicEnergy;
|
||||
@property (nonatomic, strong) EQNGenericValue *currentStrongEarthquakeDistance;
|
||||
@end
|
||||
|
||||
@implementation SettingsSeismicNetworkAlertsViewController
|
||||
|
||||
static NSString * const SegueIdentifierListaEnti = @"ShowListaEnti";
|
||||
|
||||
|
||||
typedef NS_ENUM(NSInteger, RowIdentifier) {
|
||||
RowIdentifierAbilitaNotifiche = 0,
|
||||
RowIdentifierRetiSismiche,
|
||||
RowIdentifierRaggioPosizione,
|
||||
RowIdentifierEnergiaSisma,
|
||||
RowIdentifierTerremotiVicini,
|
||||
RowIdentifierTerremotiForti,
|
||||
RowIdentifierTerremotiFortiDistanza
|
||||
};
|
||||
|
||||
#pragma mark - View Lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self setupUI];
|
||||
|
||||
self.settings = @[
|
||||
[[SettingItem alloc] initWithType:SettingTypeEnable title:NSLocalizedString(@"options_notification_enable_official", @"")],
|
||||
[[SettingItem alloc] initWithType:SettingTypeMultiValues title:NSLocalizedString(@"options_agencies", @"") segue:SegueIdentifierListaEnti],
|
||||
[[SettingItem alloc] initWithType:SettingTypeSlider title:NSLocalizedString(@"options_radius", @"")],
|
||||
[[SettingItem alloc] initWithType:SettingTypeSlider title:NSLocalizedString(@"options_energy", @"")],
|
||||
[[SettingItem alloc] initWithType:SettingTypeEnable title:NSLocalizedString(@"options_near", @"") subtitle:NSLocalizedString(@"options_near_alert", @"")],
|
||||
[[SettingItem alloc] initWithType:SettingTypeEnable title:NSLocalizedString(@"options_strong", @"") subtitle:NSLocalizedString(@"options_strong_alert", @"")],
|
||||
[[SettingItem alloc] initWithType:SettingTypeSlider title:NSLocalizedString(@"options_strong_magnitude", @"")]
|
||||
];
|
||||
|
||||
self.dataSourceMagnitudoDeboli = [EQNData magitudoDeboli];
|
||||
self.dataSourceRaggioSisma = [EQNData raggioSismi];
|
||||
self.dataSourceMagnitudoForti = [EQNData magitudoForti];
|
||||
|
||||
[self loadDataSource];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
[self loadDataSource];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)setupUI
|
||||
{
|
||||
self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeNever;
|
||||
|
||||
self.tableView.estimatedRowHeight = 200.0;
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
[self.tableView registerClass:[SettingSectionHeaderView class] forHeaderFooterViewReuseIdentifier:SettingSectionHeaderView.Identifier];
|
||||
[self.tableView registerClass:[SettingEnableTableViewCell class] forCellReuseIdentifier:SettingEnableTableViewCell.Identifier];
|
||||
[self.tableView registerClass:[SettingSliderTableViewCell class] forCellReuseIdentifier:SettingSliderTableViewCell.Identifier];
|
||||
[self.tableView registerClass:[SettingMultivaluesTableViewCell class] forCellReuseIdentifier:SettingMultivaluesTableViewCell.Identifier];
|
||||
}
|
||||
|
||||
- (void)loadDataSource
|
||||
{
|
||||
self.notificationEnabled = [EQNNotificheReteSismiche sharedInstance].isAbilitato;
|
||||
self.notificationNearEarthquakeEnabled = [EQNNotificheReteSismiche sharedInstance].isAbilitaVicini;
|
||||
self.notificationStrongEarthquakeEnabled = [EQNNotificheReteSismiche sharedInstance].isTerremortiForti;
|
||||
|
||||
// raggio dalla tua posizione
|
||||
EQNGenericValue *raggioSisma = [EQNData raggioSismaFor:[EQNNotificheReteSismiche sharedInstance].distanzaPosizione];
|
||||
self.currentUserPositionRadius = raggioSisma;
|
||||
|
||||
// energia sisma
|
||||
EQNGenericValue *energiaSisma = [EQNData magitudoDeboleFor:[EQNNotificheReteSismiche sharedInstance].energiaSisma];
|
||||
self.currentSeismicEnergy = energiaSisma;
|
||||
|
||||
// terremoti forti
|
||||
EQNGenericValue *terremotiForti = [EQNData magitudoForteFor:[EQNNotificheReteSismiche sharedInstance].energiaTerremotiForti];
|
||||
self.currentStrongEarthquakeDistance = terremotiForti;
|
||||
|
||||
// enti
|
||||
if (![EQNNotificheReteSismiche sharedInstance].listaEnti) {
|
||||
[EQNNotificheReteSismiche sharedInstance].listaEnti = [EQNData.seismicNetworkAcronyms copy];
|
||||
}
|
||||
|
||||
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
SettingSectionHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SettingSectionHeaderView.Identifier];
|
||||
headerView.titleLabel.text = NSLocalizedString(@"options_notification_official", @"titolo impostazioni notifiche");
|
||||
return headerView;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
return SettingSectionHeaderView.Height;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.settings.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
SettingItem *setting = self.settings[indexPath.row];
|
||||
|
||||
if (setting.type == SettingTypeEnable) {
|
||||
SettingEnableTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingEnableTableViewCell.Identifier forIndexPath:indexPath];
|
||||
cell.titleLabel.text = setting.displayTitle;
|
||||
cell.descriptionLabel.text = setting.subtitle;
|
||||
|
||||
if (indexPath.row == RowIdentifierAbilitaNotifiche) {
|
||||
cell.toggleSwitch.on = self.notificationEnabled;
|
||||
cell.valueChanged = ^(BOOL enabled) {
|
||||
self.notificationEnabled = enabled;
|
||||
[EQNNotificheReteSismiche sharedInstance].isAbilitato = self.notificationEnabled;
|
||||
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
|
||||
[self.tableView reloadData];
|
||||
};
|
||||
} else if (indexPath.row == RowIdentifierTerremotiVicini) {
|
||||
cell.toggleSwitch.on = self.notificationNearEarthquakeEnabled;
|
||||
cell.isDisabled = !self.notificationEnabled;
|
||||
cell.valueChanged = ^(BOOL enabled) {
|
||||
self.notificationNearEarthquakeEnabled = enabled;
|
||||
[EQNNotificheReteSismiche sharedInstance].isAbilitaVicini = self.notificationNearEarthquakeEnabled;
|
||||
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
|
||||
[self.tableView reloadData];
|
||||
};
|
||||
} else if (indexPath.row == RowIdentifierTerremotiForti) {
|
||||
cell.toggleSwitch.on = self.notificationStrongEarthquakeEnabled;
|
||||
cell.isDisabled = !self.notificationEnabled;
|
||||
cell.valueChanged = ^(BOOL enabled) {
|
||||
self.notificationStrongEarthquakeEnabled = enabled;
|
||||
[EQNNotificheReteSismiche sharedInstance].isTerremortiForti = self.notificationStrongEarthquakeEnabled;
|
||||
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
|
||||
[self.tableView reloadData];
|
||||
};
|
||||
}
|
||||
|
||||
return cell;
|
||||
} else if (setting.type == SettingTypeMultiValues) {
|
||||
SettingMultivaluesTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingMultivaluesTableViewCell.Identifier forIndexPath:indexPath];
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
cell.isDisabled = !self.notificationEnabled;
|
||||
cell.userInteractionEnabled = self.notificationEnabled;
|
||||
cell.titleLabel.text = setting.title;
|
||||
|
||||
if (indexPath.row == RowIdentifierRetiSismiche) {
|
||||
cell.valuesLabel.text = [self stringOfSelectedNetworks];
|
||||
}
|
||||
|
||||
return cell;
|
||||
} else if (setting.type == SettingTypeSlider) {
|
||||
SettingSliderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingSliderTableViewCell.Identifier forIndexPath:indexPath];
|
||||
cell.titleLabel.text = setting.displayTitle;
|
||||
|
||||
if (indexPath.row == RowIdentifierRaggioPosizione) {
|
||||
cell.isDisabled = !self.notificationEnabled;
|
||||
[cell configureSliderWith:self.dataSourceRaggioSisma current:self.currentUserPositionRadius];
|
||||
cell.valueChanged = ^(EQNGenericValue *item) {
|
||||
[self updateUserPositionRadius:item];
|
||||
};
|
||||
} else if (indexPath.row == RowIdentifierEnergiaSisma) {
|
||||
cell.isDisabled = !self.notificationEnabled;
|
||||
[cell configureSliderWith:self.dataSourceMagnitudoDeboli current:self.currentSeismicEnergy];
|
||||
cell.valueChanged = ^(EQNGenericValue *item) {
|
||||
[self updateSeismicEnergy:item];
|
||||
};
|
||||
} else if (indexPath.row == RowIdentifierTerremotiFortiDistanza) {
|
||||
cell.isDisabled = !self.notificationEnabled || !self.notificationStrongEarthquakeEnabled;
|
||||
[cell configureSliderWith:self.dataSourceMagnitudoForti current:self.currentStrongEarthquakeDistance];
|
||||
cell.valueChanged = ^(EQNGenericValue *item) {
|
||||
[self updateStrongEarthquakeEnergy:item];
|
||||
};
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
SettingItem *setting = self.settings[indexPath.row];
|
||||
if (setting.segue != nil) {
|
||||
[self performSegueWithIdentifier:setting.segue sender:nil];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)updateUserPositionRadius:(EQNGenericValue *)radius
|
||||
{
|
||||
[EQNNotificheReteSismiche sharedInstance].distanzaPosizione = radius.value;
|
||||
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
|
||||
|
||||
[self loadDataSource];
|
||||
}
|
||||
|
||||
- (void)updateSeismicEnergy:(EQNGenericValue *)energy
|
||||
{
|
||||
[EQNNotificheReteSismiche sharedInstance].energiaSisma = energy.value;
|
||||
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
|
||||
|
||||
[self loadDataSource];
|
||||
}
|
||||
|
||||
- (void)updateStrongEarthquakeEnergy:(EQNGenericValue *)energy
|
||||
{
|
||||
[EQNNotificheReteSismiche sharedInstance].energiaTerremotiForti = energy.value;
|
||||
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
|
||||
|
||||
[self loadDataSource];
|
||||
}
|
||||
|
||||
- (NSString *)stringOfSelectedNetworks
|
||||
{
|
||||
NSArray *networks = [EQNNotificheReteSismiche sharedInstance].listaEnti;
|
||||
networks = [networks sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
|
||||
return [networks componentsJoinedByString:@", "];
|
||||
}
|
||||
|
||||
@end
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// SettingsSeismicNetworkNotificationsFilterViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 06/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Shogun
|
||||
|
||||
class SettingsSeismicNetworkNotificationsFilterViewController: UITableViewController {
|
||||
|
||||
private let filters: [EQNSettingSeismicNetworkNotification.FilterType] = [.soloRilevanti, .condizionati]
|
||||
private var currentFilter = EQNSettingSeismicNetworkNotification.shared.filtro
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
convenience init() {
|
||||
self.init(style: .insetGrouped)
|
||||
}
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setupUI()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupUI() {
|
||||
tableView.estimatedRowHeight = 200.0
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.registerHeaderFooterView(for: SettingSectionHeaderView.self)
|
||||
tableView.registerCell(for: SettingDetailTableViewCell.self)
|
||||
}
|
||||
|
||||
// MARK: - Table view data source
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let view = tableView.dequeueHeaderFooterView(cellIdentifiable: SettingSectionHeaderView.self)
|
||||
view.titleLabel.text = NSLocalizedString("options_official_type", comment: "")
|
||||
return view
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
SettingSectionHeaderView.Height
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return filters.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let filter = filters[indexPath.row]
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingDetailTableViewCell.self, for: indexPath)
|
||||
cell.textLabel?.text = filter.displayName
|
||||
cell.textLabel?.numberOfLines = 0
|
||||
cell.accessoryType = currentFilter == filter ? .checkmark : .none
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let filter = filters[indexPath.row]
|
||||
|
||||
EQNSettingSeismicNetworkNotification.shared.filtro = filter
|
||||
EQNSettingSeismicNetworkNotification.shared.saveUserInfo()
|
||||
|
||||
navigationController?.popViewController(animated: true)
|
||||
}
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
//
|
||||
// SettingsSeismicNetworkNotificationsViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 06/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Shogun
|
||||
|
||||
class SettingsSeismicNetworkNotificationsViewController: SettingsBaseTableViewController {
|
||||
|
||||
private enum RowIdentifier: Int {
|
||||
case abilitaNotifiche
|
||||
case filtroNotifiche
|
||||
case magnitudoMinima
|
||||
case distanzaMassima
|
||||
}
|
||||
|
||||
private static let SegueFilters = "ShowFilters"
|
||||
|
||||
private var isNotificationEnabled = false
|
||||
private var currentFilter: EQNSettingSeismicNetworkNotification.FilterType = .soloRilevanti
|
||||
private var currentMinimumMagnitude = EQNData.DefaultSettingSeismicNetworkNotificationMagitude
|
||||
private var currentMaximumDistance = EQNData.DefaultSettingSeismicNetworkNotificationRadius
|
||||
private let dataSourceMinimumMagnitude = EQNData.settingSeismicNetworkNotificationMagnitudes
|
||||
private let dataSourceMaximumDistance = EQNData.settingSeismicNetworkNotificationRadius
|
||||
|
||||
private let settings: [SettingItem] = [
|
||||
.init(type: .enable, title: NSLocalizedString("options_notification_enable_official", comment: "")),
|
||||
.init(type: .multiValues, title: NSLocalizedString("options_official_type", comment: ""), segue: SegueFilters),
|
||||
.init(type: .slider, title: NSLocalizedString("options_official_minmag", comment: "")),
|
||||
.init(type: .slider, title: NSLocalizedString("options_official_maxdist", comment: ""))
|
||||
]
|
||||
|
||||
// MARK: - View Liefcycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setupUI()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
loadDataSource()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupUI() {
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
|
||||
tableView.estimatedRowHeight = 200.0
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.registerHeaderFooterView(for: SettingSectionHeaderView.self)
|
||||
tableView.registerCell(for: SettingEnableTableViewCell.self)
|
||||
tableView.registerCell(for: SettingSliderTableViewCell.self)
|
||||
tableView.registerCell(for: SettingMultivaluesTableViewCell.self)
|
||||
}
|
||||
|
||||
private func loadDataSource() {
|
||||
let saved = EQNSettingSeismicNetworkNotification.shared
|
||||
|
||||
isNotificationEnabled = saved.isAbilitato
|
||||
|
||||
// filtro notifiche
|
||||
currentFilter = saved.filtro
|
||||
|
||||
// magnitudo minima
|
||||
let magnitudoMinima = EQNData.getSettingSeismicNetworkNotificationMagnitudes(for: saved.magnitudoMinima)
|
||||
currentMinimumMagnitude = magnitudoMinima
|
||||
|
||||
// raggio dalla tua posizione
|
||||
let distanzaMassima = EQNData.getSettingSeismicNetworkNotificationRadius(for: saved.distanzaMassima)
|
||||
currentMaximumDistance = distanzaMassima
|
||||
}
|
||||
|
||||
// MARK: - Table view data source
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let view = tableView.dequeueHeaderFooterView(cellIdentifiable: SettingSectionHeaderView.self)
|
||||
view.titleLabel.text = NSLocalizedString("options_notification_official", comment: "")
|
||||
return view
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
SettingSectionHeaderView.Height
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return settings.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
guard let identifier = RowIdentifier(rawValue: indexPath.row) else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
|
||||
let setting = settings[indexPath.row]
|
||||
switch setting.type {
|
||||
case .enable:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingEnableTableViewCell.self, for: indexPath)
|
||||
cell.titleLabel.text = setting.displayTitle
|
||||
cell.descriptionLabel.text = setting.subtitle
|
||||
|
||||
switch identifier {
|
||||
case .abilitaNotifiche:
|
||||
cell.toggleSwitch.isOn = isNotificationEnabled
|
||||
cell.valueChanged = { [weak self] enabled in
|
||||
self?.onChangeNotificationEnabled(enabled)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return cell
|
||||
case .multiValues:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingMultivaluesTableViewCell.self, for: indexPath)
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
cell.titleLabel.text = setting.title
|
||||
|
||||
switch identifier {
|
||||
case .filtroNotifiche:
|
||||
cell.isDisabled = !isNotificationEnabled
|
||||
cell.isUserInteractionEnabled = isNotificationEnabled
|
||||
cell.valuesLabel.text = currentFilter.displayName
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return cell
|
||||
|
||||
case .slider:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingSliderTableViewCell.self, for: indexPath)
|
||||
cell.titleLabel.text = setting.displayTitle
|
||||
|
||||
let filtersEnabled = isNotificationEnabled && currentFilter == .condizionati
|
||||
switch identifier {
|
||||
case .magnitudoMinima:
|
||||
cell.isDisabled = !filtersEnabled
|
||||
cell.configureSlider(with: dataSourceMinimumMagnitude, current: currentMinimumMagnitude)
|
||||
cell.valueChanged = { [weak self] item in
|
||||
self?.onChangeMinimumMagnitude(item)
|
||||
}
|
||||
case .distanzaMassima:
|
||||
cell.isDisabled = !filtersEnabled
|
||||
cell.configureSlider(with: dataSourceMaximumDistance, current: currentMaximumDistance)
|
||||
cell.valueChanged = { [weak self] item in
|
||||
self?.onChangeMaximumDistance(item)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return cell
|
||||
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let setting = settings[indexPath.row]
|
||||
switch setting.segue {
|
||||
case Self.SegueFilters:
|
||||
let controller = SettingsSeismicNetworkNotificationsFilterViewController()
|
||||
navigationController?.pushViewController(controller, animated: true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func onChangeNotificationEnabled(_ enabled: Bool) {
|
||||
isNotificationEnabled = enabled
|
||||
EQNSettingSeismicNetworkNotification.shared.isAbilitato = isNotificationEnabled
|
||||
EQNSettingSeismicNetworkNotification.shared.saveUserInfo()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
private func onChangeMinimumMagnitude(_ item: EQNGenericValue) {
|
||||
EQNSettingSeismicNetworkNotification.shared.magnitudoMinima = item.value
|
||||
EQNSettingSeismicNetworkNotification.shared.saveUserInfo()
|
||||
|
||||
loadDataSource()
|
||||
}
|
||||
|
||||
private func onChangeMaximumDistance(_ item: EQNGenericValue) {
|
||||
EQNSettingSeismicNetworkNotification.shared.distanzaMassima = item.value
|
||||
EQNSettingSeismicNetworkNotification.shared.saveUserInfo()
|
||||
|
||||
loadDataSource()
|
||||
}
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
//
|
||||
// SettingsSeismicNetworksViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Busi Andrea on 26/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SettingsSeismicNetworksViewController: UITableViewController {
|
||||
|
||||
var networks = [EQNSeismicNetwork]()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
tableView.register(SettingDetailTableViewCell.self, forCellReuseIdentifier: SettingDetailTableViewCell.Identifier)
|
||||
tableView.register(SettingSectionHeaderView.self, forHeaderFooterViewReuseIdentifier: SettingSectionHeaderView.Identifier)
|
||||
|
||||
networks = EQNData.seismicNetworks().sorted(by: { $0.acronym < $1.acronym })
|
||||
}
|
||||
|
||||
// MARK: - Table view data source
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: SettingSectionHeaderView.Identifier) as! SettingSectionHeaderView
|
||||
headerView.titleLabel.text = NSLocalizedString("options_agencies", comment: "");
|
||||
return headerView
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
CGFloat(SettingSectionHeaderView.Height)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
networks.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let network = networks[indexPath.row]
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: SettingDetailTableViewCell.Identifier, for: indexPath) as! SettingDetailTableViewCell
|
||||
cell.textLabel?.text = "\(network.acronym) (\(network.country))"
|
||||
|
||||
if EQNNotificheReteSismiche.shared().listaEnti.contains(network.acronym) {
|
||||
cell.accessoryType = .checkmark
|
||||
} else {
|
||||
cell.accessoryType = .none
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
let network = networks[indexPath.row]
|
||||
|
||||
var savedNetworks = EQNNotificheReteSismiche.shared().listaEnti
|
||||
if let index = savedNetworks.firstIndex(where: { $0 == network.acronym }) {
|
||||
savedNetworks.remove(at: index)
|
||||
} else {
|
||||
savedNetworks.append(network.acronym)
|
||||
}
|
||||
|
||||
EQNNotificheReteSismiche.shared().listaEnti = savedNetworks
|
||||
EQNNotificheReteSismiche.shared().saveUserInfo()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// SettingsUserReportAlertsViewController.h
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi 25/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "SettingsBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SettingsUserReportAlertsViewController : SettingsBaseViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
-119
@@ -1,119 +0,0 @@
|
||||
//
|
||||
// SettingsUserReportAlertsViewController.m
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi 25/08/2020.
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SettingsUserReportAlertsViewController.h"
|
||||
#import "EQNNotificheSegnalazioniUtente.h"
|
||||
|
||||
@interface SettingsUserReportAlertsViewController ()
|
||||
|
||||
@property (nonatomic, strong) NSArray<SettingItem *> *settings;
|
||||
@property (nonatomic, assign) BOOL notificationsEnabled;
|
||||
@property (nonatomic, strong) EQNGenericValue *currentRadius;
|
||||
@end
|
||||
|
||||
@implementation SettingsUserReportAlertsViewController
|
||||
|
||||
#pragma mark - View Lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self setupUI];
|
||||
|
||||
self.settings = @[
|
||||
[[SettingItem alloc] initWithType:SettingTypeEnable title:NSLocalizedString(@"options_notification_enable_manual", @"")],
|
||||
[[SettingItem alloc] initWithType:SettingTypeSlider title:NSLocalizedString(@"options_radius", @"")]
|
||||
];
|
||||
|
||||
[self updateUI];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)setupUI
|
||||
{
|
||||
self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeNever;
|
||||
|
||||
self.tableView.estimatedRowHeight = 100.0;
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
[self.tableView registerClass:[SettingSectionHeaderView class] forHeaderFooterViewReuseIdentifier:SettingSectionHeaderView.Identifier];
|
||||
[self.tableView registerClass:[SettingEnableTableViewCell class] forCellReuseIdentifier:SettingEnableTableViewCell.Identifier];
|
||||
[self.tableView registerClass:[SettingSliderTableViewCell class] forCellReuseIdentifier:SettingSliderTableViewCell.Identifier];
|
||||
}
|
||||
|
||||
- (void)updateUI
|
||||
{
|
||||
self.notificationsEnabled = [EQNNotificheSegnalazioniUtente sharedInstance].isAbilitato;
|
||||
|
||||
EQNGenericValue *distanzaPosizione = [EQNData raggioSismaFor:[EQNNotificheSegnalazioniUtente sharedInstance].distanzaPosizione];
|
||||
self.currentRadius = distanzaPosizione;
|
||||
[[EQNNotificheSegnalazioniUtente sharedInstance] saveUserInfo];
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)updateRadius:(EQNGenericValue *)radius
|
||||
{
|
||||
self.currentRadius = radius;
|
||||
[EQNNotificheSegnalazioniUtente sharedInstance].distanzaPosizione = radius.value;
|
||||
[[EQNNotificheSegnalazioniUtente sharedInstance] saveUserInfo];
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
SettingSectionHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SettingSectionHeaderView.Identifier];
|
||||
headerView.titleLabel.text = NSLocalizedString(@"options_notification_manual", @"titolo impostazioni notifiche");
|
||||
return headerView;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
return SettingSectionHeaderView.Height;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.settings.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
SettingItem *setting = self.settings[indexPath.row];
|
||||
|
||||
if (setting.type == SettingTypeEnable) {
|
||||
SettingEnableTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingEnableTableViewCell.Identifier forIndexPath:indexPath];
|
||||
cell.toggleSwitch.on = self.notificationsEnabled;
|
||||
cell.titleLabel.text = setting.displayTitle;
|
||||
cell.descriptionLabel.text = setting.subtitle;
|
||||
cell.valueChanged = ^(BOOL enabled) {
|
||||
self.notificationsEnabled = enabled;
|
||||
[EQNNotificheSegnalazioniUtente sharedInstance].isAbilitato = self.notificationsEnabled;
|
||||
[[EQNNotificheSegnalazioniUtente sharedInstance] saveUserInfo];
|
||||
[self.tableView reloadData];
|
||||
};
|
||||
return cell;
|
||||
} else if (setting.type == SettingTypeSlider) {
|
||||
SettingSliderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingSliderTableViewCell.Identifier forIndexPath:indexPath];
|
||||
cell.isDisabled = !self.notificationsEnabled;
|
||||
cell.titleLabel.text = setting.displayTitle;
|
||||
[cell configureSliderWith:[EQNData raggioSismi] current:self.currentRadius];
|
||||
cell.valueChanged = ^(EQNGenericValue *item) {
|
||||
[self updateRadius:item];
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// SettingsUserReportNotificationsViewController.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 10/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Shogun
|
||||
|
||||
class SettingsUserReportNotificationsViewController: SettingsBaseTableViewController {
|
||||
|
||||
private enum RowIdentifier: Int {
|
||||
case abilitaNotifiche
|
||||
case distanzaMassima
|
||||
}
|
||||
|
||||
private var isNotificationEnabled = false
|
||||
private var currentMaximumDistance = EQNData.DefaultSettingUserReportNotificationRadius
|
||||
private let dataSourceMaximumDistance = EQNData.settingUserReportNotificationRadius
|
||||
|
||||
private let settings: [SettingItem] = [
|
||||
.init(type: .enable, title: NSLocalizedString("options_notification_enable_manual", comment: "")),
|
||||
.init(type: .slider, title: NSLocalizedString("options_radius", comment: ""))
|
||||
]
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setupUI()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
loadDataSource()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupUI() {
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
|
||||
tableView.estimatedRowHeight = 200.0
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.registerHeaderFooterView(for: SettingSectionHeaderView.self)
|
||||
tableView.registerCell(for: SettingEnableTableViewCell.self)
|
||||
tableView.registerCell(for: SettingSliderTableViewCell.self)
|
||||
}
|
||||
|
||||
private func loadDataSource() {
|
||||
let saved = EQNSettingUserReportNotification.shared
|
||||
|
||||
isNotificationEnabled = saved.isAbilitato
|
||||
|
||||
let distanzaMassima = EQNData.getSettingUserReportNotificationRadius(for: saved.distanzaMassima)
|
||||
currentMaximumDistance = distanzaMassima
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate and data source
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let view = tableView.dequeueHeaderFooterView(cellIdentifiable: SettingSectionHeaderView.self)
|
||||
view.titleLabel.text = NSLocalizedString("options_notification_manual", comment: "")
|
||||
return view
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
SettingSectionHeaderView.Height
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return settings.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
guard let identifier = RowIdentifier(rawValue: indexPath.row) else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
|
||||
let setting = settings[indexPath.row]
|
||||
switch setting.type {
|
||||
case .enable:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingEnableTableViewCell.self, for: indexPath)
|
||||
cell.titleLabel.text = setting.displayTitle
|
||||
cell.descriptionLabel.text = setting.subtitle
|
||||
|
||||
switch identifier {
|
||||
case .abilitaNotifiche:
|
||||
cell.toggleSwitch.isOn = isNotificationEnabled
|
||||
cell.valueChanged = { [weak self] enabled in
|
||||
self?.onChangeNotificationEnabled(enabled)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return cell
|
||||
|
||||
case .slider:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingSliderTableViewCell.self, for: indexPath)
|
||||
cell.titleLabel.text = setting.displayTitle
|
||||
|
||||
switch identifier {
|
||||
case .distanzaMassima:
|
||||
cell.isDisabled = !isNotificationEnabled
|
||||
cell.configureSlider(with: dataSourceMaximumDistance, current: currentMaximumDistance)
|
||||
cell.valueChanged = { [weak self] item in
|
||||
self?.onChangeMaximumDistance(item)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return cell
|
||||
|
||||
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func onChangeNotificationEnabled(_ enabled: Bool) {
|
||||
isNotificationEnabled = enabled
|
||||
EQNSettingUserReportNotification.shared.isAbilitato = isNotificationEnabled
|
||||
EQNSettingUserReportNotification.shared.saveUserInfo()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
private func onChangeMaximumDistance(_ item: EQNGenericValue) {
|
||||
EQNSettingUserReportNotification.shared.distanzaMassima = item.value
|
||||
EQNSettingUserReportNotification.shared.saveUserInfo()
|
||||
|
||||
loadDataSource()
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ class EQNBaseMapViewController: EQNBaseViewController, MKMapViewDelegate {
|
||||
// MARK: - Internal
|
||||
|
||||
/// Annotations displayed on the map
|
||||
private var mapAnnotations = [MKAnnotation]()
|
||||
private(set) var mapAnnotations = [MKAnnotation]()
|
||||
/// If `true`, the initial filter has been already evaluated
|
||||
private var initialFilterEvaluated = false
|
||||
|
||||
@@ -104,6 +104,34 @@ class EQNBaseMapViewController: EQNBaseViewController, MKMapViewDelegate {
|
||||
return label
|
||||
}()
|
||||
|
||||
// app icon and name displayed on the screenshot
|
||||
private lazy var watermarkView: UIView = {
|
||||
let view = UIView()
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
let logo = UIImageView(image: .init(named: "eq_icon_transparent"))
|
||||
logo.translatesAutoresizingMaskIntoConstraints = false
|
||||
logo.contentMode = .scaleAspectFit
|
||||
view.addSubview(logo)
|
||||
logo.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
|
||||
logo.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
||||
logo.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
||||
logo.widthAnchor.constraint(equalTo: logo.heightAnchor).isActive = true
|
||||
|
||||
let title = UILabel()
|
||||
title.translatesAutoresizingMaskIntoConstraints = false
|
||||
title.text = NSLocalizedString("app_name", comment: "") + " App"
|
||||
title.textColor = AppTheme.Colors.red
|
||||
title.font = .preferredFont(forTextStyle: .title3, weight: .semibold)
|
||||
view.addSubview(title)
|
||||
title.leadingAnchor.constraint(equalTo: logo.trailingAnchor, constant: 10.0).isActive = true
|
||||
title.centerYAnchor.constraint(equalTo: logo.centerYAnchor).isActive = true
|
||||
title.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
init() {
|
||||
@@ -155,6 +183,18 @@ class EQNBaseMapViewController: EQNBaseViewController, MKMapViewDelegate {
|
||||
extraUI()
|
||||
}
|
||||
|
||||
private func addWatermarkView() {
|
||||
view.addSubview(watermarkView)
|
||||
|
||||
watermarkView.topAnchor.constraint(equalTo: mapView.topAnchor, constant: 10.0).isActive = true
|
||||
watermarkView.leadingAnchor.constraint(equalTo: mapView.leadingAnchor, constant: 10.0).isActive = true
|
||||
watermarkView.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
|
||||
}
|
||||
|
||||
private func removeWatermarkView() {
|
||||
watermarkView.removeFromSuperview()
|
||||
}
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
@@ -238,6 +278,12 @@ class EQNBaseMapViewController: EQNBaseViewController, MKMapViewDelegate {
|
||||
elaborateMapCenter()
|
||||
}
|
||||
|
||||
func reloadMap() {
|
||||
// remove and re-add annotations, to force redrawn
|
||||
mapView.removeAnnotations(mapAnnotations)
|
||||
mapView.addAnnotations(mapAnnotations)
|
||||
}
|
||||
|
||||
/// Changes the center coordinate of the map to a given location
|
||||
func setMapCenter(for location: CLLocation, span: MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: 8, longitudeDelta: 8)) {
|
||||
let region = MKCoordinateRegion(center: location.coordinate, span: span)
|
||||
@@ -249,6 +295,31 @@ class EQNBaseMapViewController: EQNBaseViewController, MKMapViewDelegate {
|
||||
// nope, subclass will implement logic
|
||||
}
|
||||
|
||||
func zPriority(for annotation: MKAnnotation) -> MKAnnotationViewZPriority {
|
||||
// subclass will impelement its own logic to define annotation priority
|
||||
.min
|
||||
}
|
||||
|
||||
func createSnapshot(
|
||||
prepare: () -> Void = { },
|
||||
restore: () -> Void = { }
|
||||
) -> UIImage {
|
||||
prepare()
|
||||
addWatermarkView()
|
||||
|
||||
// riduciamo la porzione da salvare alla sola mappa (eliminiamo i filtri)
|
||||
let size = CGSize(width: view.bounds.width, height: mapView.bounds.maxY)
|
||||
let renderer = UIGraphicsImageRenderer(size: size)
|
||||
let image = renderer.image { ctx in
|
||||
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
|
||||
}
|
||||
|
||||
restore()
|
||||
removeWatermarkView()
|
||||
|
||||
return image
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateUI() {
|
||||
@@ -286,6 +357,7 @@ class EQNBaseMapViewController: EQNBaseViewController, MKMapViewDelegate {
|
||||
}
|
||||
|
||||
let annotationView = setupAnnotationView(for: annotation, on: mapView)
|
||||
annotationView?.zPriority = zPriority(for: annotation)
|
||||
return annotationView
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ class AlertSimulatorViewController: UIViewController, MKMapViewDelegate {
|
||||
}
|
||||
|
||||
private func navigateToSubscriptions() {
|
||||
let controller = SubscriptionsViewController.makeViewController()
|
||||
let controller = SubscriptionsViewController()
|
||||
let navigationController = UINavigationController(rootViewController: controller)
|
||||
present(navigationController, animated: true)
|
||||
}
|
||||
|
||||
@@ -6,16 +6,12 @@
|
||||
#import "Costanti.h"
|
||||
#import "EQNUser.h"
|
||||
#import "EQNManager.h"
|
||||
#import "EQNNotificheReteSismiche.h"
|
||||
#import "EQNNotificheSegnalazioniUtente.h"
|
||||
#import "EQNSisma.h"
|
||||
#import "EQNBaseViewController.h"
|
||||
#import "SettingsBaseViewController.h"
|
||||
#import "EQNGeneratoreURLServer.h"
|
||||
#import "ServerRequest.h"
|
||||
#import "EQNSegnalazione.h"
|
||||
#import "EQNPastquakes.h"
|
||||
#import "EQNAllertaSismica.h"
|
||||
|
||||
#import "GADTTemplateView.h"
|
||||
#import "GADTMediumTemplateView.h"
|
||||
|
||||
@@ -26,3 +26,14 @@ extension NSDate {
|
||||
return (self as Date).isBeforeInterval(interval)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension CGFloat {
|
||||
var negative: CGFloat {
|
||||
-self
|
||||
}
|
||||
|
||||
var x2: CGFloat {
|
||||
self*2.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ public class EQNUserDefaultsCommand: EQNCommandProtocol {
|
||||
|
||||
migrationV5_3()
|
||||
migrationV5_4()
|
||||
migrationV5_8()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -78,4 +79,40 @@ public class EQNUserDefaultsCommand: EQNCommandProtocol {
|
||||
|
||||
userDefaults.set(true, forKey: UserDefaults.AppMigrationV5_4)
|
||||
}
|
||||
|
||||
private func migrationV5_8() {
|
||||
let migrationPerformed = UserDefaults.standard.bool(forKey: UserDefaults.AppMigrationV5_8)
|
||||
if migrationPerformed {
|
||||
print("[EQNUserDefaultsCommand] Migration v5.8 already performed")
|
||||
return
|
||||
}
|
||||
|
||||
// delete old notification settings
|
||||
let userDefaults = UserDefaults.standard
|
||||
[
|
||||
"NOTIFICHE_ATTIVA_RETI_SISMICHE_VICINE", "NOTIFICHE_ATTIVA_RETI_TERREMOTI_FORTI",
|
||||
"NOTIFICHE_ATTIVA_RETI_ENERGIA_FORTI", "NOTIFICHE_ATTIVA_RETI_LISTA_ENTI"
|
||||
].forEach { key in
|
||||
userDefaults.removeObject(forKey: key)
|
||||
}
|
||||
|
||||
// delete old filter values
|
||||
[
|
||||
"EQN_ETA_MASSIMA", "EQN_SISMI_FORTI_ABILITATI", "EQN_SISMI_FORTI",
|
||||
"EQN_SISMI_QUALSIASI_MAGNITUDO", "EQN_SISMI_MODIFICA_IMPOSTAZIONI"
|
||||
].forEach { key in
|
||||
userDefaults.removeObject(forKey: key)
|
||||
}
|
||||
|
||||
// delete old "real time alert" settings
|
||||
[
|
||||
"NOTIFICHE_ALLERA_SISMICA_IMPOSTA_VOLUME", "NOTIFICHE_ALLERA_SISMICA_TESTA_ALLARME",
|
||||
"NOTIFICHE_ALLERA_SISMICA_ABILITA_INTERVALLO", "NOTIFICHE_ALLERA_SISMICA_ORA_INIZIO",
|
||||
"NOTIFICHE_ALLERA_SISMICA_ORA_INIZIO"
|
||||
].forEach { key in
|
||||
userDefaults.removeObject(forKey: key)
|
||||
}
|
||||
|
||||
userDefaults.set(true, forKey: UserDefaults.AppMigrationV5_8)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,89 +10,121 @@ import Foundation
|
||||
|
||||
|
||||
@objc class EQNData: NSObject {
|
||||
@objc public static let MaxRaggioSisma = "100000"
|
||||
@objc public static let DefaultRaggioSisma = EQNGenericValue(value:MaxRaggioSisma, display:"radius_any_distance")
|
||||
@objc public static let DefaultMagitudoDebole = EQNGenericValue(value:"2.0", display:"official_magnitude_value_20")
|
||||
@objc public static let DefaultMagitudoForte = EQNGenericValue(value:"5.5", display:"official_magnitude_value_55")
|
||||
@objc public static let DefaultPeriodoTemporale = EQNGenericValue(value: "1440", display: "report_timeframe_one_day")
|
||||
static let MaxRaggioSisma = "100000"
|
||||
static let DefaultSettingSeismicNetworkNotificationRadius = EQNGenericValue(value:"500", display:"500 km")
|
||||
static let DefaultSettingSeismicNetworkNotificationMagitude = EQNGenericValue(value:"2.0", display:"official_magnitude_value_20")
|
||||
static let DefaultSettingUserReportNotificationRadius = EQNGenericValue(value:"1000", display:"1000 km")
|
||||
static let DefaultFilterRadius = EQNGenericValue(value:"250", display:"250 km")
|
||||
static let DefaultFilterMagnitude = EQNGenericValue(value:"0.0", display:"official_magnitude_value_00")
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
@objc class func raggioSismi() -> [EQNGenericValue] {
|
||||
[
|
||||
EQNGenericValue(value:"50", display:"50 km"),
|
||||
EQNGenericValue(value:"100", display:"100 km"),
|
||||
EQNGenericValue(value:"200", display:"200 km"),
|
||||
EQNGenericValue(value:"300", display:"300 km"),
|
||||
EQNGenericValue(value:"400", display:"400 km"),
|
||||
EQNGenericValue(value:"500", display:"500 km"),
|
||||
EQNGenericValue(value:"600", display:"600 km"),
|
||||
EQNGenericValue(value:"800", display:"800 km"),
|
||||
EQNGenericValue(value:"1000", display:"1000 km"),
|
||||
EQNGenericValue(value:"2000", display:"2000 km"),
|
||||
EQNGenericValue(value:"4000", display:"4000 km"),
|
||||
EQNGenericValue(value:Self.MaxRaggioSisma, display:"radius_any_distance"),
|
||||
]
|
||||
}
|
||||
// Distances for "seismic network notifications"
|
||||
static let settingSeismicNetworkNotificationRadius: [EQNGenericValue] = [
|
||||
EQNGenericValue(value:"100", display:"100 km"),
|
||||
EQNGenericValue(value:"250", display:"250 km"),
|
||||
EQNGenericValue(value:"500", display:"500 km"),
|
||||
EQNGenericValue(value:"1000", display:"1000 km")
|
||||
]
|
||||
|
||||
// Magnitudes for "seismic network notifications"
|
||||
static let settingSeismicNetworkNotificationMagnitudes: [EQNGenericValue] = [
|
||||
EQNGenericValue(value:"0.0", display:"0.0"),
|
||||
EQNGenericValue(value:"0.5", display:"0.5"),
|
||||
EQNGenericValue(value:"1.0", display:"1.0"),
|
||||
EQNGenericValue(value:"1.5", display:"1.5"),
|
||||
EQNGenericValue(value:"2.0", display:"2.0"),
|
||||
EQNGenericValue(value:"2.5", display:"2.5"),
|
||||
EQNGenericValue(value:"3.0", display:"3.0"),
|
||||
EQNGenericValue(value:"3.5", display:"3.5"),
|
||||
EQNGenericValue(value:"4.0", display:"4.0"),
|
||||
EQNGenericValue(value:"4.5", display:"4.5"),
|
||||
EQNGenericValue(value:"5.0", display:"5.0"),
|
||||
EQNGenericValue(value:"5.5", display:"5.5")
|
||||
]
|
||||
|
||||
// Distances for "user report notifications"
|
||||
static let settingUserReportNotificationRadius: [EQNGenericValue] = [
|
||||
EQNGenericValue(value:"100", display:"100 km"),
|
||||
EQNGenericValue(value:"250", display:"250 km"),
|
||||
EQNGenericValue(value:"500", display:"500 km"),
|
||||
EQNGenericValue(value:"1000", display:"1000 km")
|
||||
]
|
||||
|
||||
// Misure raggio utilizzate nei filtri
|
||||
static let filterRadius: [EQNGenericValue] = [
|
||||
EQNGenericValue(value:"100", display:"100 km"),
|
||||
EQNGenericValue(value:"250", display:"250 km"),
|
||||
EQNGenericValue(value:"500", display:"500 km"),
|
||||
EQNGenericValue(value:"750", display:"750 km"),
|
||||
EQNGenericValue(value:"1000", display:"1000 km"),
|
||||
EQNGenericValue(value:"1500", display:"1500 km"),
|
||||
EQNGenericValue(value:"2000", display:"2000 km")
|
||||
]
|
||||
|
||||
// Magnitudo utilizzate nei filtri
|
||||
static let filterMagnitude: [EQNGenericValue] = [
|
||||
EQNGenericValue(value:"0.0", display:"0.0"),
|
||||
EQNGenericValue(value:"1.0", display:"1.0"),
|
||||
EQNGenericValue(value:"2.0", display:"2.0"),
|
||||
EQNGenericValue(value:"3.0", display:"3.0"),
|
||||
EQNGenericValue(value:"4.0", display:"4.0"),
|
||||
EQNGenericValue(value:"5.0", display:"5.0"),
|
||||
EQNGenericValue(value:"6.0", display:"6.0")
|
||||
]
|
||||
|
||||
/// Returns the EQNGenericValue for the given value, or the default one
|
||||
/// - Parameter value: Sisma value to search
|
||||
/// - Parameter value: Sisma radius to search
|
||||
/// - Returns: Found value or default
|
||||
@objc class func raggioSisma(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = Self.raggioSismi().first(where: { $0.value == value }) {
|
||||
@objc(getSettingSeismicNetworkAlertRadiusForValue:)
|
||||
class func getSettingSeismicNetworkNotificationRadius(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = settingSeismicNetworkNotificationRadius.first(where: { $0.value == value }) {
|
||||
return genericValue
|
||||
}
|
||||
return Self.DefaultRaggioSisma
|
||||
}
|
||||
|
||||
@objc class func magitudoDeboli() -> [EQNGenericValue] {
|
||||
[
|
||||
EQNGenericValue(value:"0.0", display:"official_magnitude_value_00"),
|
||||
EQNGenericValue(value:"0.5", display:"official_magnitude_value_05"),
|
||||
EQNGenericValue(value:"1.0", display:"official_magnitude_value_10"),
|
||||
EQNGenericValue(value:"1.5", display:"official_magnitude_value_15"),
|
||||
EQNGenericValue(value:"2.0", display:"official_magnitude_value_20"),
|
||||
EQNGenericValue(value:"2.5", display:"official_magnitude_value_25"),
|
||||
EQNGenericValue(value:"3.0", display:"official_magnitude_value_30"),
|
||||
EQNGenericValue(value:"3.5", display:"official_magnitude_value_35"),
|
||||
EQNGenericValue(value:"4.0", display:"official_magnitude_value_40"),
|
||||
EQNGenericValue(value:"4.5", display:"official_magnitude_value_45"),
|
||||
EQNGenericValue(value:"5.0", display:"official_magnitude_value_50"),
|
||||
EQNGenericValue(value:"5.5", display:"official_magnitude_value_55")
|
||||
]
|
||||
return DefaultSettingSeismicNetworkNotificationRadius
|
||||
}
|
||||
|
||||
/// Returns the EQNGenericValue for the given value, or the default one
|
||||
/// - Parameter value: Magnitudo value to search
|
||||
/// - Returns: Found value or default
|
||||
@objc class func magitudoDebole(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = Self.magitudoDeboli().first(where: { $0.value == value }) {
|
||||
class func getSettingSeismicNetworkNotificationMagnitudes(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = settingSeismicNetworkNotificationMagnitudes.first(where: { $0.value == value }) {
|
||||
return genericValue
|
||||
}
|
||||
return Self.DefaultMagitudoDebole
|
||||
}
|
||||
|
||||
@objc class func magitudoForti() -> [EQNGenericValue] {
|
||||
[
|
||||
EQNGenericValue(value:"5.5", display:"official_magnitude_value_55"),
|
||||
EQNGenericValue(value:"6.0", display:"official_magnitude_value_60"),
|
||||
EQNGenericValue(value:"6.5", display:"official_magnitude_value_65"),
|
||||
EQNGenericValue(value:"7.0", display:"official_magnitude_value_70"),
|
||||
EQNGenericValue(value:"7.5", display:"official_magnitude_value_75")
|
||||
]
|
||||
return DefaultSettingSeismicNetworkNotificationMagitude
|
||||
}
|
||||
|
||||
/// Returns the EQNGenericValue for the given value, or the default one
|
||||
/// - Parameter value: Magnitudo value to search
|
||||
/// - Parameter value: Sisma radius to search
|
||||
/// - Returns: Found value or default
|
||||
@objc class func magitudoForte(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = Self.magitudoForti().first(where: { $0.value == value }) {
|
||||
class func getSettingUserReportNotificationRadius(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = settingUserReportNotificationRadius.first(where: { $0.value == value }) {
|
||||
return genericValue
|
||||
}
|
||||
return Self.DefaultMagitudoForte
|
||||
return DefaultSettingUserReportNotificationRadius
|
||||
}
|
||||
|
||||
@objc class func seismicNetworks() -> [EQNSeismicNetwork] {
|
||||
/// Returns the EQNGenericValue for the given value, or the default one
|
||||
/// - Parameter value: Sisma radius to search
|
||||
/// - Returns: Found value or default
|
||||
class func filterRadius(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = filterRadius.first(where: { $0.value == value }) {
|
||||
return genericValue
|
||||
}
|
||||
return DefaultFilterRadius
|
||||
}
|
||||
|
||||
/// Returns the EQNGenericValue for the given value, or the default one
|
||||
/// - Parameter value: Magnitudo value to search
|
||||
/// - Returns: Found value or default
|
||||
class func filterMagnitude(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = filterMagnitude.first(where: { $0.value == value }) {
|
||||
return genericValue
|
||||
}
|
||||
return DefaultFilterMagnitude
|
||||
}
|
||||
|
||||
class func seismicNetworks() -> [EQNSeismicNetwork] {
|
||||
[
|
||||
EQNSeismicNetwork(acronym: "USGS", country: NSLocalizedString("configuration_countries_united_states", comment: ""), extended: ""),
|
||||
EQNSeismicNetwork(acronym: "INGV", country: NSLocalizedString("configuration_countries_italy", comment: ""), extended: ""),
|
||||
@@ -120,37 +152,16 @@ import Foundation
|
||||
]
|
||||
}
|
||||
|
||||
@objc class func seismicNetworkAcronyms() -> [String] {
|
||||
class func seismicNetworkAcronyms() -> [String] {
|
||||
Self.seismicNetworks().map { $0.acronym }
|
||||
}
|
||||
|
||||
@objc class func seismicNetworkCountries() -> [String] {
|
||||
class func seismicNetworkCountries() -> [String] {
|
||||
Self.seismicNetworks().map { $0.country }
|
||||
}
|
||||
|
||||
@objc class func seismic(for acronym: String?) -> EQNSeismicNetwork? {
|
||||
class func seismic(for acronym: String?) -> EQNSeismicNetwork? {
|
||||
guard let acronym = acronym else { return nil }
|
||||
return Self.seismicNetworks().first(where: { $0.acronym == acronym })
|
||||
}
|
||||
|
||||
@objc class func periodiTemporali() -> [EQNGenericValue] {
|
||||
[
|
||||
EQNGenericValue(value: "10", display: "10 minuti"),
|
||||
EQNGenericValue(value: "60", display: "report_timeframe_one_hour"),
|
||||
EQNGenericValue(value: "120", display: "report_timeframe_two_hours"),
|
||||
EQNGenericValue(value: "360", display: "report_timeframe_six_hours"),
|
||||
EQNGenericValue(value: "720", display: "report_timeframe_twelve_hours"),
|
||||
EQNGenericValue(value: "1440", display: "report_timeframe_one_day")
|
||||
]
|
||||
}
|
||||
|
||||
/// Returns the EQNGenericValue for the given value, or the default one
|
||||
/// - Parameter value: Temporal unit value to search
|
||||
/// - Returns: Found value or default
|
||||
@objc class func periodoTemporale(for value: String?) -> EQNGenericValue {
|
||||
if let value = value, let genericValue = Self.periodiTemporali().first(where: { $0.value == value }) {
|
||||
return genericValue
|
||||
}
|
||||
return Self.DefaultPeriodoTemporale
|
||||
}
|
||||
}
|
||||
|
||||
+103
-34
@@ -27,10 +27,110 @@
|
||||
/// THE SOFTWARE.
|
||||
|
||||
import Foundation
|
||||
import StoreKit
|
||||
|
||||
public struct VersioneProProducts {
|
||||
public struct EQNInAppProducts {
|
||||
|
||||
public enum Identifier {
|
||||
enum Plan: CaseIterable {
|
||||
case monthly
|
||||
case yearly
|
||||
case perpetual
|
||||
|
||||
var localizedTitle: String {
|
||||
switch self {
|
||||
case .monthly: NSLocalizedString("subscription_plan_monthly", comment: "")
|
||||
case .yearly: NSLocalizedString("subscription_plan_yearly", comment: "")
|
||||
case .perpetual: NSLocalizedString("subscription_plan_perpetual", comment: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Category {
|
||||
case pro
|
||||
case top10k
|
||||
case top100k
|
||||
|
||||
var image: UIImage? {
|
||||
switch self {
|
||||
case .pro: nil
|
||||
case .top10k: UIImage(named: "top_10k")
|
||||
case .top100k: UIImage(named: "top_100k")
|
||||
}
|
||||
}
|
||||
|
||||
var localizedTitle: String {
|
||||
switch self {
|
||||
case .pro: return NSLocalizedString("network_pro", comment: "")
|
||||
case .top10k: return "Top 10k"
|
||||
case .top100k: return "Top 100k"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let plan: Plan
|
||||
let category: Category
|
||||
let isDiscounted: Bool
|
||||
let product: SKProduct
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
private init(plan: Plan, category: Category, isDiscounted: Bool, product: SKProduct) {
|
||||
self.plan = plan
|
||||
self.category = category
|
||||
self.isDiscounted = isDiscounted
|
||||
self.product = product
|
||||
}
|
||||
|
||||
// MARK: - Accessories
|
||||
|
||||
var isTop10k: Bool {
|
||||
category == .top10k
|
||||
}
|
||||
|
||||
var isTop100k: Bool {
|
||||
category == .top100k
|
||||
}
|
||||
|
||||
var isSubscription: Bool {
|
||||
category != .pro
|
||||
}
|
||||
|
||||
var productIdentifier: String {
|
||||
product.productIdentifier
|
||||
}
|
||||
|
||||
// MARK: - Static
|
||||
|
||||
static func from(product: SKProduct) -> EQNInAppProducts? {
|
||||
switch product.productIdentifier {
|
||||
case Identifier.ProVersionFullPrice:
|
||||
.init(plan: .perpetual, category: .pro, isDiscounted: false, product: product)
|
||||
case Identifier.ProVersionDiscounted:
|
||||
.init(plan: .perpetual, category: .pro, isDiscounted: true, product: product)
|
||||
|
||||
case Identifier.Subscription10kMonthly:
|
||||
.init(plan: .monthly, category: .top10k, isDiscounted: false, product: product)
|
||||
case Identifier.Subscription10kYearly:
|
||||
.init(plan: .yearly, category: .top10k, isDiscounted: false, product: product)
|
||||
case Identifier.Subscription10kYearlyDiscounted:
|
||||
.init(plan: .yearly, category: .top10k, isDiscounted: true, product: product)
|
||||
case Identifier.Subscription10kPerpetual:
|
||||
.init(plan: .perpetual, category: .top10k, isDiscounted: false, product: product)
|
||||
|
||||
case Identifier.Subscription100kMonthly:
|
||||
.init(plan: .monthly, category: .top100k, isDiscounted: false, product: product)
|
||||
case Identifier.Subscription100kYearly:
|
||||
.init(plan: .yearly, category: .top100k, isDiscounted: false, product: product)
|
||||
case Identifier.Subscription100kYearlyDiscounted:
|
||||
.init(plan: .yearly, category: .top100k, isDiscounted: true, product: product)
|
||||
case Identifier.Subscription100kPerpetual:
|
||||
.init(plan: .perpetual, category: .top100k, isDiscounted: false, product: product)
|
||||
default:
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
enum Identifier {
|
||||
static let ProVersionFullPrice = "com.finazzi.distquake.ProPrezzoPieno"
|
||||
static let ProVersionDiscounted = "com.finazzi.distquake.VersioneProScontata"
|
||||
|
||||
@@ -66,40 +166,9 @@ public struct VersioneProProducts {
|
||||
static let identifiersForTop100k: Set<ProductIdentifier> = [
|
||||
Subscription100kMonthly, Subscription100kYearly, Subscription100kYearlyDiscounted, Subscription100kPerpetual
|
||||
]
|
||||
|
||||
static let identifierForSubscriptions: Set<ProductIdentifier> = [
|
||||
Subscription10kMonthly, Subscription100kMonthly,
|
||||
Subscription10kYearly, Subscription10kYearlyDiscounted,
|
||||
Subscription100kYearly, Subscription100kYearlyDiscounted,
|
||||
Subscription10kPerpetual, Subscription100kPerpetual
|
||||
]
|
||||
}
|
||||
|
||||
static func isSubscription(for identifier: String) -> Bool {
|
||||
Identifier.identifierForSubscriptions.contains(identifier)
|
||||
}
|
||||
|
||||
static func is10kSubscription(for identifier: String) -> Bool {
|
||||
Identifier.identifiersForTop10k.contains(identifier)
|
||||
}
|
||||
|
||||
static func is100kSubscription(for identifier: String) -> Bool {
|
||||
Identifier.identifiersForTop100k.contains(identifier)
|
||||
}
|
||||
|
||||
static func image(for productIdentifier: String) -> UIImage? {
|
||||
if is100kSubscription(for: productIdentifier){
|
||||
return UIImage(named: "top_100k")
|
||||
}
|
||||
|
||||
if is10kSubscription(for: productIdentifier) {
|
||||
return UIImage(named: "top_10k")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
public static let store = IAPHelper(productIds: VersioneProProducts.Identifier.identifiers)
|
||||
public static let store = IAPHelper(productIds: EQNInAppProducts.Identifier.identifiers)
|
||||
}
|
||||
|
||||
func resourceNameForProductIdentifier(_ productIdentifier: String) -> String? {
|
||||
@@ -120,19 +120,15 @@
|
||||
|
||||
- (void)scaricaReteSismica
|
||||
{
|
||||
// L'endpoint per lo scaricamento dei dati prende due parametri: pro per il provider selezionato, mag per la
|
||||
// magnitudo minima. Se l'utente ha selezionato più di un provider, inviamo ALL. Mentre la magnitudo
|
||||
// deve avere sempre una cifra decimale (es 2.0).
|
||||
|
||||
NSString *filterProvider = @"";
|
||||
NSArray<NSString *> *networks = [EQNUserData.sharedData seismicNetworksSelected];
|
||||
if (networks.count == 1) {
|
||||
filterProvider = [networks firstObject];
|
||||
} else {
|
||||
filterProvider = @"ALL";
|
||||
}
|
||||
// L'endpoint per lo scaricamento dei dati prende due parametri:
|
||||
// - `pro` per il provider selezionato,
|
||||
// - `mag` per la magnitudo minima.
|
||||
// Dalla v5.8 non esiste più la selezione delle reti, quindi passiamo sempre "ALL".
|
||||
// Per la magnitudo minima, invece, passiamo 0 per i filtri "raggio" e "rilevanti,
|
||||
// altrimenti passiamo 2 per il filtro "mondo"
|
||||
|
||||
NSString *filterMagnitude = [EQNSeismic shared].magnitudoMinima;
|
||||
NSString *filterProvider = @"ALL";
|
||||
NSString *filterMagnitude = [EQNSeismic shared].filterOption == FilterTypeWorldWide ? @"2.0" : @"0.0";
|
||||
|
||||
NSString *queryString = [NSString stringWithFormat:@"?pro=%@&mag=%@", filterProvider, filterMagnitude];
|
||||
NSString *urlString = [NSString stringWithFormat:EQNServerUrlDownloadRetiSismiche, queryString];
|
||||
|
||||
@@ -57,21 +57,21 @@ public class EQNPurchaseUtility: NSObject {
|
||||
/// Check if user has bought pro app version
|
||||
/// Pro version is enabled also if a yearly subscription is enabled
|
||||
@objc public static func isProVersionEnabled() -> Bool {
|
||||
VersioneProProducts.Identifier.identifierForProVersion.reduce(false) { (result, identifier) -> Bool in
|
||||
EQNInAppProducts.Identifier.identifierForProVersion.reduce(false) { (result, identifier) -> Bool in
|
||||
return result || UserDefaults.standard.bool(forKey: identifier)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if user has bought Top 10k subscription
|
||||
@objc public static func isTop10kEnabled() -> Bool {
|
||||
VersioneProProducts.Identifier.identifiersForTop10k.reduce(false) { (result, identifier) -> Bool in
|
||||
EQNInAppProducts.Identifier.identifiersForTop10k.reduce(false) { (result, identifier) -> Bool in
|
||||
return result || UserDefaults.standard.bool(forKey: identifier)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if user has bought Top 100k subscription
|
||||
@objc public static func isTop100kEnabled() -> Bool {
|
||||
VersioneProProducts.Identifier.identifiersForTop100k.reduce(false) { (result, identifier) -> Bool in
|
||||
EQNInAppProducts.Identifier.identifiersForTop100k.reduce(false) { (result, identifier) -> Bool in
|
||||
return result || UserDefaults.standard.bool(forKey: identifier)
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class EQNPurchaseUtility: NSObject {
|
||||
/// Remove saved in-app purchases flags.
|
||||
/// Used only during development
|
||||
@objc public static func resetInAppPurchases() {
|
||||
VersioneProProducts.Identifier.identifiers.forEach { (identifier) in
|
||||
EQNInAppProducts.Identifier.identifiers.forEach { (identifier) in
|
||||
UserDefaults.standard.removeObject(forKey: identifier)
|
||||
}
|
||||
NotificationCenter.default.post(name: .EQNInAppPurchaseDidComplete, object: nil)
|
||||
|
||||
@@ -11,31 +11,36 @@ import Foundation
|
||||
|
||||
@objc class EQNSeismic: NSObject {
|
||||
|
||||
@objc enum FilterType: Int {
|
||||
case inRadius
|
||||
case positionRelevant
|
||||
case worldWide
|
||||
}
|
||||
|
||||
enum Sort: Int {
|
||||
case time
|
||||
case position
|
||||
case magnitude
|
||||
}
|
||||
|
||||
@objc static let shared = EQNSeismic()
|
||||
|
||||
@objc var magnitudoMinima: String
|
||||
@objc var distanzaMassima: String
|
||||
@objc var periodoTemporale: String
|
||||
@objc var sismiFortiAbilitati: Bool
|
||||
@objc var sismiFortiMagnitudo: String
|
||||
@objc var sismiQualsiasiAbilitati: Bool
|
||||
@objc var modificaImpostazioniAbilitato: Bool
|
||||
@objc var filterOption: FilterType
|
||||
var sort: Sort
|
||||
var maximumDistance: String
|
||||
@objc var minimumMagnitude: String
|
||||
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
override init() {
|
||||
Self.migrateOldDistanza()
|
||||
Self.migrateOldPeriodo()
|
||||
Self.migrate_v5_8()
|
||||
|
||||
let defaults = UserDefaults.standard
|
||||
magnitudoMinima = defaults.object(forKey: UserDefaults.SeismicMagnitudoMinima, or: EQNData.DefaultMagitudoDebole.value)
|
||||
distanzaMassima = defaults.object(forKey: UserDefaults.SeismicDistanzaMassima, or: EQNData.DefaultRaggioSisma.value)
|
||||
periodoTemporale = defaults.object(forKey: UserDefaults.SeismicEtaMassima, or: EQNData.DefaultPeriodoTemporale.value)
|
||||
sismiFortiAbilitati = defaults.object(forKey: UserDefaults.SeismicSismiFortiAbilitati, or: false)
|
||||
sismiFortiMagnitudo = defaults.object(forKey: UserDefaults.SeismicSismiForti, or: EQNData.DefaultMagitudoForte.value)
|
||||
sismiQualsiasiAbilitati = defaults.object(forKey: UserDefaults.SeismicSismiQualsiasiMagnitudo, or: false)
|
||||
modificaImpostazioniAbilitato = defaults.object(forKey: UserDefaults.SeismicModificaImpostazioni, or: true)
|
||||
filterOption = defaults.enumObject(forKey: UserDefaults.SeismicFilterOption, or: .positionRelevant)
|
||||
sort = defaults.enumObject(forKey: UserDefaults.SeismicSort, or: .time)
|
||||
maximumDistance = defaults.object(forKey: UserDefaults.SeismicDistanzaMassima, or: EQNData.DefaultFilterRadius.value)
|
||||
minimumMagnitude = defaults.object(forKey: UserDefaults.SeismicMagnitudoMinima, or: EQNData.DefaultFilterMagnitude.value)
|
||||
|
||||
super.init()
|
||||
}
|
||||
@@ -44,114 +49,136 @@ import Foundation
|
||||
// MARK: - Public
|
||||
|
||||
public func saveFilters() {
|
||||
UserDefaults.standard.set(magnitudoMinima, forKey: UserDefaults.SeismicMagnitudoMinima)
|
||||
UserDefaults.standard.set(distanzaMassima, forKey: UserDefaults.SeismicDistanzaMassima)
|
||||
UserDefaults.standard.set(periodoTemporale, forKey: UserDefaults.SeismicEtaMassima)
|
||||
UserDefaults.standard.set(sismiFortiMagnitudo, forKey: UserDefaults.SeismicSismiForti)
|
||||
UserDefaults.standard.set(sismiFortiAbilitati, forKey: UserDefaults.SeismicSismiFortiAbilitati)
|
||||
UserDefaults.standard.set(sismiQualsiasiAbilitati, forKey: UserDefaults.SeismicSismiQualsiasiMagnitudo)
|
||||
UserDefaults.standard.set(modificaImpostazioniAbilitato, forKey: UserDefaults.SeismicModificaImpostazioni)
|
||||
let defaults = UserDefaults.standard
|
||||
defaults.set(filterOption.rawValue, forKey: UserDefaults.SeismicFilterOption)
|
||||
defaults.set(sort.rawValue, forKey: UserDefaults.SeismicSort)
|
||||
defaults.set(maximumDistance, forKey: UserDefaults.SeismicDistanzaMassima)
|
||||
defaults.set(minimumMagnitude, forKey: UserDefaults.SeismicMagnitudoMinima)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private static func migrateOldDistanza() {
|
||||
guard let savedValue = UserDefaults.standard.object(forKey: UserDefaults.SeismicDistanzaMassima) as? String else {
|
||||
print("[EQNSeismic] Distanza massima: nessun valore da convertire")
|
||||
private class func migrate_v5_8() {
|
||||
let defaults = UserDefaults.standard
|
||||
let alreadyMigrated = defaults.bool(forKey: UserDefaults.SismicFiltersMigrationV5_8)
|
||||
if alreadyMigrated {
|
||||
return
|
||||
}
|
||||
|
||||
if savedValue.lowercased() == NSLocalizedString("radius_any_distance", comment: "").lowercased() {
|
||||
print("[EQNSeismic] Distanza massima: trovato qualsiasi distanza, salvo valore")
|
||||
UserDefaults.standard.set("100000", forKey: UserDefaults.SeismicDistanzaMassima)
|
||||
} else {
|
||||
print("[EQNSeismic] Distanza massima: valore da non convertire (value: \(savedValue))")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static func migrateOldPeriodo() {
|
||||
guard let savedValue = UserDefaults.standard.object(forKey: UserDefaults.SeismicEtaMassima) as? String else {
|
||||
print("[EQNSeismic] Età massima: nessun valore da convertire");
|
||||
return
|
||||
if let savedMagnitude = defaults.object(forKey: UserDefaults.SeismicMagnitudoMinima) as? String {
|
||||
let minMagnitude = switch savedMagnitude {
|
||||
case "0.0": "0.0"
|
||||
case "0.5", "1.0": "1.0"
|
||||
case "1.5", "2.0": "2.0"
|
||||
case "2.5", "3.0": "3.0"
|
||||
case "3.5", "4.0": "4.0"
|
||||
case "4.5", "5.0": "5.0"
|
||||
case "5.5", "6.0": "6.0"
|
||||
default: "0.0"
|
||||
}
|
||||
defaults.set(minMagnitude, forKey: UserDefaults.SeismicMagnitudoMinima)
|
||||
}
|
||||
|
||||
var convertedValue: String?
|
||||
if savedValue.lowercased() == NSLocalizedString("report_timeframe_one_day", comment: "").lowercased() {
|
||||
convertedValue = "1440"
|
||||
} else if savedValue.lowercased() == NSLocalizedString("report_timeframe_twelve_hours", comment: "").lowercased() {
|
||||
convertedValue = "720"
|
||||
} else if savedValue.lowercased() == NSLocalizedString("report_timeframe_six_hours", comment: "").lowercased() {
|
||||
convertedValue = "360"
|
||||
} else if savedValue.lowercased() == NSLocalizedString("report_timeframe_two_hours", comment: "").lowercased() {
|
||||
convertedValue = "120"
|
||||
} else if savedValue.lowercased() == NSLocalizedString("report_timeframe_one_hour", comment: "").lowercased() {
|
||||
convertedValue = "60"
|
||||
} else if savedValue.lowercased() == NSLocalizedString("report_timeframe_ten_minutes", comment: "").lowercased() {
|
||||
convertedValue = "10"
|
||||
if let savedDistance = defaults.object(forKey: UserDefaults.SeismicDistanzaMassima) as? String {
|
||||
let maxDistance = switch savedDistance {
|
||||
case "50", "100": "100"
|
||||
case "200", "300": "250"
|
||||
case "400", "500", "600": "500"
|
||||
case "800": "750"
|
||||
case "1000": "1000"
|
||||
default:
|
||||
// 2000, 4000, qualsiasi distanza
|
||||
"2000"
|
||||
}
|
||||
defaults.set(maxDistance, forKey: UserDefaults.SeismicDistanzaMassima)
|
||||
}
|
||||
|
||||
if let convertedValue = convertedValue {
|
||||
print("[EQNSeismic] Età massima: salvo valore convertito (old: \(savedValue) - new: \(convertedValue)")
|
||||
UserDefaults.standard.set(convertedValue, forKey: UserDefaults.SeismicEtaMassima)
|
||||
} else {
|
||||
print("[EQNSeismic] Età massima: valore già convertito")
|
||||
}
|
||||
defaults.set(true, forKey: UserDefaults.SismicFiltersMigrationV5_8)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Class
|
||||
|
||||
@objc func filterSeismicList(_ list: [EQNSisma]) -> [EQNSisma] {
|
||||
// enti abilitati
|
||||
var networks = EQNUserData.shared.seismicNetworksSelected()
|
||||
if networks.isEmpty {
|
||||
networks = EQNData.seismicNetworkAcronyms()
|
||||
}
|
||||
networks = networks.map { $0.lowercased() }
|
||||
|
||||
// filtri
|
||||
let filterDistance = Double(distanzaMassima)
|
||||
let filterMagnitude = Double(magnitudoMinima)
|
||||
let filterShowNear = sismiQualsiasiAbilitati
|
||||
let filterShowNearRadius: Double = 50.0
|
||||
let filterStrongEarthquake = Double(sismiFortiMagnitudo)
|
||||
let filterStrongEarthquakeEnabled = sismiFortiAbilitati
|
||||
let filterTime = Double(periodoTemporale)
|
||||
let filter_radius = Double(maximumDistance)
|
||||
let filter_min_magnitude = Double(minimumMagnitude)
|
||||
|
||||
// filter seismic list
|
||||
var filtered = [EQNSisma]()
|
||||
for seismic in list {
|
||||
for (i, seismic) in list.enumerated() {
|
||||
var keep = true
|
||||
|
||||
if !networks.contains(seismic.provider.lowercased()) {
|
||||
keep = false
|
||||
}
|
||||
let latitude = seismic.coordinate.coordinate.latitude
|
||||
let longitude = seismic.coordinate.coordinate.longitude
|
||||
let provider = seismic.provider.uppercased()
|
||||
|
||||
// filtro distanza massima
|
||||
if let filterDistance = filterDistance, seismic.userDistance > filterDistance {
|
||||
keep = false
|
||||
}
|
||||
|
||||
// filtro magnitudo minima e mostra sismi di qualsiasi magnitudo
|
||||
if let filterMagnitude = filterMagnitude, seismic.magnitude.doubleValue < filterMagnitude {
|
||||
if !filterShowNear {
|
||||
keep = false
|
||||
} else {
|
||||
if seismic.userDistance > filterShowNearRadius {
|
||||
keep = false
|
||||
//Ricerca di sismi duplicati in lista
|
||||
for j in -3...3 {
|
||||
if (j != 0) && (i + j > 0) && (i+j < list.count) {
|
||||
let seismic_j = list[i+j]
|
||||
let latitude_j = seismic_j.coordinate.coordinate.latitude
|
||||
let longitude_j = seismic_j.coordinate.coordinate.longitude
|
||||
let provider_j = seismic_j.provider.uppercased()
|
||||
|
||||
let delta_lat = abs(latitude - latitude_j)
|
||||
let delta_lon = abs(longitude - longitude_j)
|
||||
let delta_time = abs(EQNUtility.getDeltaMinute(seismic.date ?? Date()) - EQNUtility.getDeltaMinute(seismic_j.date ?? Date()))
|
||||
let ratio = seismic.magnitude.doubleValue/seismic_j.magnitude.doubleValue
|
||||
|
||||
if ratio > 0.8 && ratio < 1.2 && delta_lat < 0.5 && delta_lon < 0.5 && delta_time <= 2 {
|
||||
if provider == "EMSC" {
|
||||
keep = false
|
||||
}
|
||||
if provider == "USGS" && !(provider_j == "EMSC") {
|
||||
keep = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// filtro sismi forti
|
||||
if let filterStrongEarthquake = filterStrongEarthquake, seismic.provider == "EMSC" && filterStrongEarthquakeEnabled && seismic.magnitude.doubleValue > filterStrongEarthquake {
|
||||
keep = true
|
||||
}
|
||||
|
||||
// filtro tempo
|
||||
if let filterTime = filterTime, seismic.timeDifference > filterTime {
|
||||
keep = false
|
||||
|
||||
if keep {
|
||||
let distance = seismic.userDistance
|
||||
let magnitude = seismic.magnitude.doubleValue
|
||||
|
||||
if filterOption == .inRadius {
|
||||
//filtro basato su magnitudo e raggio
|
||||
if let filter_radius, let filter_min_magnitude, distance > filter_radius || magnitude < filter_min_magnitude {
|
||||
keep = false
|
||||
}
|
||||
} else if filterOption == .positionRelevant {
|
||||
//filtro sismi significativi
|
||||
|
||||
if magnitude < 7.0 && distance > 2000 {
|
||||
keep = false
|
||||
} else if magnitude < 6.5 && distance > 1600 {
|
||||
keep = false
|
||||
} else if magnitude < 6.0 && distance > 1300 {
|
||||
keep = false
|
||||
} else if magnitude < 5.5 && distance > 1000 {
|
||||
keep = false
|
||||
} else if magnitude < 5.0 && distance > 700 {
|
||||
keep = false
|
||||
} else if magnitude < 4.5 && distance > 500 {
|
||||
keep = false
|
||||
} else if magnitude < 4.0 && distance > 350 {
|
||||
keep = false
|
||||
} else if magnitude < 3.5 && distance > 200 {
|
||||
keep = false
|
||||
} else if magnitude < 3.0 && distance > 125 {
|
||||
keep = false
|
||||
} else if magnitude < 2.5 && distance > 70 {
|
||||
keep = false
|
||||
} else if magnitude < 2.0 && distance > 35 {
|
||||
keep = false
|
||||
} else if magnitude < 1.5 && distance > 20 {
|
||||
keep = false
|
||||
}
|
||||
} else {
|
||||
//filtro che mostra tutti i sismi a livello mondiale di magnitudo>=2
|
||||
if magnitude < 2 {
|
||||
keep = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if keep {
|
||||
@@ -159,6 +186,29 @@ import Foundation
|
||||
}
|
||||
}
|
||||
|
||||
switch sort {
|
||||
case .time:
|
||||
filtered.sort(by: { seismic1, seismic2 in
|
||||
guard let date1 = seismic1.date else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard let date2 = seismic2.date else {
|
||||
return true
|
||||
}
|
||||
|
||||
return date1 > date2
|
||||
})
|
||||
case .position:
|
||||
filtered.sort { seismic1, seismic2 in
|
||||
seismic1.userDistance < seismic2.userDistance
|
||||
}
|
||||
case .magnitude:
|
||||
filtered.sort { seismic1, seismic2 in
|
||||
seismic1.magnitude.doubleValue > seismic2.magnitude.doubleValue
|
||||
}
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,13 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (token == nil) {
|
||||
NSLog(@"[EQNUser] Firebase token is null, abort registration");
|
||||
self.registrationInProgress = NO;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:EQNServerRegistrationDidFailNotification object:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
self.registrationInProgress = YES;
|
||||
NSURL *url = [EQNGeneratoreURLServer urlRegistrazioneFirebaseToken:token existingUserId:userId];
|
||||
[[ServerRequest defaultServerConnectionSingleton] inviaInformazioniAlServerWithURL:url richiesta:EQNTipoChiamataRegistrazione success:^(id result) {
|
||||
|
||||
@@ -61,4 +61,9 @@ extension EQNUtility {
|
||||
class func formattedDate(from date: Date) -> String {
|
||||
Self.dateFormatter.string(from: date)
|
||||
}
|
||||
|
||||
/// Convert a date to minutes
|
||||
class func getDeltaMinute(_ date: Date) -> TimeInterval {
|
||||
Date().timeIntervalSince(date) / 60.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@
|
||||
// Copyright © 2021 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import MapKit
|
||||
|
||||
|
||||
class EQNMapAnnotationSeismic: NSObject, MKAnnotation {
|
||||
|
||||
var coordinate: CLLocationCoordinate2D
|
||||
var title: String?
|
||||
var image: UIImage?
|
||||
let coordinate: CLLocationCoordinate2D
|
||||
let title: String?
|
||||
let subtitle: String?
|
||||
let textColor: UIColor
|
||||
|
||||
let seismic: EQNSisma
|
||||
|
||||
@@ -22,58 +23,60 @@ class EQNMapAnnotationSeismic: NSObject, MKAnnotation {
|
||||
|
||||
init(seismic: EQNSisma) {
|
||||
self.seismic = seismic
|
||||
self.coordinate = CLLocationCoordinate2D(latitude: seismic.coordinate.coordinate.latitude, longitude: seismic.coordinate.coordinate.longitude)
|
||||
self.image = Self.image(for: seismic)
|
||||
self.coordinate = CLLocationCoordinate2D(latitude: seismic.coordinate.coordinate.latitude,
|
||||
longitude: seismic.coordinate.coordinate.longitude)
|
||||
self.title = seismic.provider
|
||||
if let date = seismic.date {
|
||||
self.title = EQNUtility.formattedTimeDifference(from: date)
|
||||
self.subtitle = EQNUtility.formattedTimeDifference(from: date)
|
||||
} else {
|
||||
self.subtitle = nil
|
||||
}
|
||||
self.textColor = Self.textColor(for: seismic)
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
func image(
|
||||
height: CGFloat,
|
||||
isUserSelection: Bool
|
||||
) -> UIImage? {
|
||||
let color = Self.imageColor(for: seismic)
|
||||
let borderColor = isUserSelection ? AppTheme.Colors.red : AppTheme.Colors.darkGray
|
||||
return UIImage.circle(diameter: height, color: color, borderWidth: 2.0, borderColor: borderColor)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private class func image(for seismic: EQNSisma) -> UIImage? {
|
||||
private class func textColor(for seismic: EQNSisma) -> UIColor {
|
||||
let magnitude = seismic.magnitude.doubleValue
|
||||
|
||||
let color: String
|
||||
if magnitude < 2.0 {
|
||||
color = "white"
|
||||
return UIColor(red: 0.0, green: 200.0/255.0, blue: 200.0/255.0, alpha: 1.0)
|
||||
} else if magnitude < 3.5 {
|
||||
color = "green"
|
||||
return UIColor(red: 0.0, green: 200.0/255.0, blue: 0.0, alpha: 1.0)
|
||||
} else if magnitude < 4.5 {
|
||||
color = "yellow"
|
||||
return UIColor(red: 240.0/255.0, green: 190.0/255.0, blue: 0.0, alpha: 1.0)
|
||||
} else if magnitude < 5.5 {
|
||||
color = "red"
|
||||
return UIColor(red: 200.0/255.0, green: 0.0, blue: 0.0, alpha: 1.0)
|
||||
} else {
|
||||
color = "purple"
|
||||
return UIColor(red: 200.0/255.0, green: 0.0, blue: 200.0/255.0, alpha: 1.0)
|
||||
}
|
||||
|
||||
let icon: String
|
||||
switch seismic.provider.uppercased() {
|
||||
case "USGS": icon = "star"
|
||||
case "SGC": icon = "star3"
|
||||
case "CSN": icon = "star3f"
|
||||
case "SSN": icon = "star4"
|
||||
case "INPRES": icon = "star4r"
|
||||
case "FUNVISIS": icon = "star6"
|
||||
case "Ineter": icon = "triangle"
|
||||
case "RSN": icon = "triangle2"
|
||||
case "PHIVOLCS": icon = "triround_inner"
|
||||
case "IGEPN": icon = "triround"
|
||||
case "INGV": icon = "circle"
|
||||
case "EMSC": icon = "dyamond"
|
||||
case "IGP": icon = "dyamond_round"
|
||||
case "JMA": icon = "esa"
|
||||
case "GEONET": icon = "oct"
|
||||
case "CSI": icon = "penta"
|
||||
case "IGN": icon = "square"
|
||||
case "UASD", "BDTIM", "NCS": icon = "thick_star"
|
||||
case "RSPR": icon = "star6f"
|
||||
case "UOA": icon = "triangle"
|
||||
default: icon = ""
|
||||
}
|
||||
|
||||
private class func imageColor(for seismic: EQNSisma) -> UIColor {
|
||||
let magnitude = seismic.magnitude.doubleValue
|
||||
if magnitude < 2.0 {
|
||||
return UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) // white
|
||||
} else if magnitude < 3.5 {
|
||||
return UIColor(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0) // green
|
||||
} else if magnitude < 4.5 {
|
||||
return UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0) // yellow
|
||||
} else if magnitude < 5.5 {
|
||||
return UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) // red
|
||||
} else {
|
||||
return UIColor(red: 1.0, green: 0.0, blue: 1.0, alpha: 1.0) // magenta
|
||||
}
|
||||
|
||||
return UIImage(named: "\(icon)_\(color)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
//
|
||||
// EQNAllertaSismica.h
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi on 21/09/2020
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EQNAllertaSismica : NSObject
|
||||
|
||||
@property (nonatomic, assign) BOOL isAbilitato;
|
||||
@property (nonatomic, assign) BOOL isCriticalAlertsEnabled;
|
||||
@property (nonatomic, assign) BOOL isintervalloAllarme;
|
||||
|
||||
@property (nonatomic, strong) NSString *sismiDaNotificare;
|
||||
@property (nonatomic, strong) NSString *raggioSismiLievi;
|
||||
@property (nonatomic, strong) NSString *raggioSismiForti;
|
||||
|
||||
@property (nonatomic, strong) NSDate *oraioInizio;
|
||||
@property (nonatomic, strong) NSDate *orarioFine;
|
||||
@property (nonatomic, strong) NSArray *listaMessaggi;
|
||||
@property (nonatomic, strong) NSArray *listaAreeInteresse;
|
||||
|
||||
+ (instancetype)sharedInstance NS_SWIFT_NAME(shared());
|
||||
- (void)saveUserInfo;
|
||||
|
||||
+ (void)saveDefaultValues;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,77 +0,0 @@
|
||||
//
|
||||
// EQNAllertaSismica.m
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi on 21/09/2020
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import "EQNAllertaSismica.h"
|
||||
#import "Costanti.h"
|
||||
|
||||
|
||||
@implementation EQNAllertaSismica
|
||||
|
||||
#pragma mark - Singleton
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static EQNAllertaSismica *instance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
self.isAbilitato = [userDefaults boolForKey:NSUserDefaults.AllertaSismicaAbilitato];
|
||||
self.sismiDaNotificare = [userDefaults objectForKey:NSUserDefaults.AllertaSismicaSismiDaNotificare];
|
||||
self.raggioSismiLievi = [userDefaults objectForKey:NSUserDefaults.AllertaSismicaRaggioSismiLievi];
|
||||
self.raggioSismiForti = [userDefaults objectForKey:NSUserDefaults.AllertaSismicaRaggioSismiForti];
|
||||
self.isintervalloAllarme = [userDefaults boolForKey:NSUserDefaults.AllertaSismicaAbilitaIntervallo];
|
||||
self.oraioInizio = [userDefaults objectForKey:NSUserDefaults.AllertaSismicaOraInizio];
|
||||
self.orarioFine = [userDefaults objectForKey:NSUserDefaults.AllertaSismicaOraFine];
|
||||
|
||||
NSUserDefaults *sharedDefaults = [NSUserDefaults appGroupUserDefaults];
|
||||
self.isCriticalAlertsEnabled = [sharedDefaults boolForKey:NSUserDefaults.AllertaSismicaCriticalAlerts];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (void)saveUserInfo
|
||||
{
|
||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
[userDefaults setBool:self.isAbilitato forKey:NSUserDefaults.AllertaSismicaAbilitato];
|
||||
[userDefaults setObject:self.sismiDaNotificare forKey:NSUserDefaults.AllertaSismicaSismiDaNotificare];
|
||||
[userDefaults setObject:self.raggioSismiLievi forKey:NSUserDefaults.AllertaSismicaRaggioSismiLievi];
|
||||
[userDefaults setObject:self.raggioSismiForti forKey:NSUserDefaults.AllertaSismicaRaggioSismiForti];
|
||||
[userDefaults setBool:self.isintervalloAllarme forKey:NSUserDefaults.AllertaSismicaAbilitaIntervallo];
|
||||
[userDefaults setObject:self.oraioInizio forKey:NSUserDefaults.AllertaSismicaOraInizio];
|
||||
[userDefaults setObject:self.orarioFine forKey:NSUserDefaults.AllertaSismicaOraFine];
|
||||
|
||||
NSUserDefaults *sharedDefaults = [NSUserDefaults appGroupUserDefaults];
|
||||
[sharedDefaults setBool:self.isCriticalAlertsEnabled forKey:NSUserDefaults.AllertaSismicaCriticalAlerts];
|
||||
}
|
||||
|
||||
#pragma mark - Class
|
||||
|
||||
+ (void)saveDefaultValues
|
||||
{
|
||||
[EQNAllertaSismica sharedInstance].isAbilitato = YES;
|
||||
[EQNAllertaSismica sharedInstance].isCriticalAlertsEnabled = NO;
|
||||
[EQNAllertaSismica sharedInstance].sismiDaNotificare = @"0";
|
||||
[EQNAllertaSismica sharedInstance].raggioSismiLievi = @"300";
|
||||
[EQNAllertaSismica sharedInstance].raggioSismiForti = @"600";
|
||||
[[EQNAllertaSismica sharedInstance] saveUserInfo];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// EQNNotificheReteSismiche.h
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi on 21/09/2020
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EQNNotificheReteSismiche : NSObject
|
||||
|
||||
@property (nonatomic, assign) BOOL isAbilitato;
|
||||
@property (nonatomic, assign) BOOL isAbilitaVicini;
|
||||
@property (nonatomic, assign) BOOL isTerremortiForti;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *listaEnti;
|
||||
@property (nonatomic, strong) NSString *distanzaPosizione;
|
||||
@property (nonatomic, strong) NSString *energiaSisma;
|
||||
@property (nonatomic, strong) NSString *energiaTerremotiForti;
|
||||
|
||||
+ (instancetype)sharedInstance NS_SWIFT_NAME(shared());
|
||||
- (void)saveUserInfo;
|
||||
|
||||
+ (void)saveDefaultValues;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,72 +0,0 @@
|
||||
//
|
||||
// EQNNotificheReteSismiche.m
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi on 21/09/2020
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import "EQNNotificheReteSismiche.h"
|
||||
#import "Costanti.h"
|
||||
#import "EQNUtility.h"
|
||||
|
||||
|
||||
@implementation EQNNotificheReteSismiche
|
||||
|
||||
#pragma mark - Singleton
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static EQNNotificheReteSismiche *instance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.isAbilitato = [[NSUserDefaults standardUserDefaults] boolForKey:NSUserDefaults.NotificheRetiSismicheAbilitato];
|
||||
self.isAbilitaVicini = [[NSUserDefaults standardUserDefaults] boolForKey:NSUserDefaults.NotificheRetiSismicheViciniAbilitato];
|
||||
self.isTerremortiForti = [[NSUserDefaults standardUserDefaults] boolForKey:NSUserDefaults.NotificheRetiSismicheTerremotiFortiAbilitato];
|
||||
self.distanzaPosizione = [[NSUserDefaults standardUserDefaults] objectForKey:NSUserDefaults.NotificheRetiSismicheDistanzaPosizione];
|
||||
self.energiaSisma = [[NSUserDefaults standardUserDefaults] objectForKey:NSUserDefaults.NotificheRetiSismicheEnergiaSisma];
|
||||
self.energiaTerremotiForti = [[NSUserDefaults standardUserDefaults] objectForKey:NSUserDefaults.NotificheRetiSismicheEnergiaTerremotiForti];
|
||||
self.listaEnti = [EQNUtility loadArrayOfClass:[NSString class] fromUserDefaultsForKey:NSUserDefaults.NotificheRetiSismicheListaEnti];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (void)saveUserInfo
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:self.isAbilitato forKey:NSUserDefaults.NotificheRetiSismicheAbilitato];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:self.isAbilitaVicini forKey:NSUserDefaults.NotificheRetiSismicheViciniAbilitato];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:self.isTerremortiForti forKey:NSUserDefaults.NotificheRetiSismicheTerremotiFortiAbilitato];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.distanzaPosizione forKey:NSUserDefaults.NotificheRetiSismicheDistanzaPosizione];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.energiaSisma forKey:NSUserDefaults.NotificheRetiSismicheEnergiaSisma];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.energiaTerremotiForti forKey:NSUserDefaults.NotificheRetiSismicheEnergiaTerremotiForti];
|
||||
[EQNUtility storeArray:self.listaEnti toUserDefaultForKey:NSUserDefaults.NotificheRetiSismicheListaEnti];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
#pragma mark - Class
|
||||
|
||||
+ (void)saveDefaultValues
|
||||
{
|
||||
[EQNNotificheReteSismiche sharedInstance].isAbilitato = YES;
|
||||
[EQNNotificheReteSismiche sharedInstance].distanzaPosizione = @"1000";
|
||||
[EQNNotificheReteSismiche sharedInstance].energiaSisma = @"3.5";
|
||||
[EQNNotificheReteSismiche sharedInstance].isAbilitaVicini = NO;
|
||||
[EQNNotificheReteSismiche sharedInstance].isTerremortiForti = NO;
|
||||
[EQNNotificheReteSismiche sharedInstance].energiaTerremotiForti = @"7.5";
|
||||
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,26 +0,0 @@
|
||||
//
|
||||
// EQNNotificheSegnalazioniUtente.h
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi on 21/09/2020
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EQNNotificheSegnalazioniUtente : NSObject
|
||||
|
||||
@property (nonatomic, assign) BOOL isAbilitato;
|
||||
@property (nonatomic, strong) NSString *distanzaPosizione;
|
||||
|
||||
|
||||
+ (instancetype)sharedInstance NS_SWIFT_NAME(shared());
|
||||
- (void)saveUserInfo;
|
||||
|
||||
+ (void)saveDefaultValues;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// EQNNotificheSegnalazioniUtente.m
|
||||
// Earthquake Network
|
||||
//
|
||||
// Refactored by Andrea Busi on 21/09/2020
|
||||
// Copyright © 2020 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
#import "EQNNotificheSegnalazioniUtente.h"
|
||||
#import "Costanti.h"
|
||||
|
||||
@implementation EQNNotificheSegnalazioniUtente
|
||||
|
||||
#pragma mark - Singleton
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static EQNNotificheSegnalazioniUtente *instance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.isAbilitato = [[NSUserDefaults standardUserDefaults] boolForKey:NSUserDefaults.NotificheSegnalazioniUtenteAbilitato];
|
||||
self.distanzaPosizione = [[NSUserDefaults standardUserDefaults] objectForKey:NSUserDefaults.NotificheSegnalazioniUtenteDistanzaPosizione];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (void)saveUserInfo
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:self.isAbilitato forKey:NSUserDefaults.NotificheSegnalazioniUtenteAbilitato];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.distanzaPosizione forKey:NSUserDefaults.NotificheSegnalazioniUtenteDistanzaPosizione];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
#pragma mark - Class
|
||||
|
||||
+ (void)saveDefaultValues
|
||||
{
|
||||
[EQNNotificheSegnalazioniUtente sharedInstance].isAbilitato = YES;
|
||||
[EQNNotificheSegnalazioniUtente sharedInstance].distanzaPosizione = @"300";
|
||||
[[EQNNotificheSegnalazioniUtente sharedInstance] saveUserInfo];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// EQNSettingRealTimeAlert.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 10/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
@objc
|
||||
class EQNSettingRealTimeAlert: NSObject {
|
||||
|
||||
@objc(sharedInstance)
|
||||
static let shared = EQNSettingRealTimeAlert()
|
||||
|
||||
@objc var isAbilitato: Bool
|
||||
@objc var isCriticalAlertsEnabled: Bool
|
||||
|
||||
@objc var sismiDaNotificare: String
|
||||
@objc var raggioSismiLievi: String
|
||||
@objc var raggioSismiForti: String
|
||||
|
||||
private static let DefaultSismiDaNotificare = "0"
|
||||
private static let DefaultRaggioSismiLievi = "250"
|
||||
private static let DefaultRaggioSismiForti = "500"
|
||||
private static let DefaultDistanzaMassima = EQNData.DefaultSettingUserReportNotificationRadius.value
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
override init() {
|
||||
let defaults = UserDefaults.standard
|
||||
self.isAbilitato = defaults.bool(forKey: UserDefaults.AllertaSismicaAbilitato)
|
||||
self.sismiDaNotificare = defaults.object(forKey: UserDefaults.AllertaSismicaSismiDaNotificare, or: Self.DefaultSismiDaNotificare)
|
||||
self.raggioSismiLievi = defaults.object(forKey: UserDefaults.AllertaSismicaRaggioSismiLievi, or: Self.DefaultRaggioSismiLievi)
|
||||
self.raggioSismiForti = defaults.object(forKey: UserDefaults.AllertaSismicaRaggioSismiForti, or: Self.DefaultRaggioSismiForti)
|
||||
|
||||
let sharedDefaults = UserDefaults.appGroup
|
||||
isCriticalAlertsEnabled = sharedDefaults?.bool(forKey: UserDefaults.AllertaSismicaCriticalAlerts) ?? false
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func saveUserInfo() {
|
||||
let defaults = UserDefaults.standard
|
||||
defaults.set(isAbilitato, forKey: UserDefaults.AllertaSismicaAbilitato)
|
||||
defaults.set(sismiDaNotificare, forKey: UserDefaults.AllertaSismicaSismiDaNotificare)
|
||||
defaults.set(raggioSismiLievi, forKey: UserDefaults.AllertaSismicaRaggioSismiLievi)
|
||||
defaults.set(raggioSismiForti, forKey: UserDefaults.AllertaSismicaRaggioSismiForti)
|
||||
if let sharedDefaults = UserDefaults.appGroup {
|
||||
sharedDefaults.set(isCriticalAlertsEnabled, forKey: UserDefaults.AllertaSismicaCriticalAlerts)
|
||||
}
|
||||
}
|
||||
|
||||
@objc class func saveDefaultValues() {
|
||||
shared.isAbilitato = true
|
||||
shared.isCriticalAlertsEnabled = false
|
||||
shared.sismiDaNotificare = Self.DefaultSismiDaNotificare
|
||||
shared.raggioSismiLievi = Self.DefaultRaggioSismiLievi
|
||||
shared.raggioSismiForti = Self.DefaultRaggioSismiForti
|
||||
shared.saveUserInfo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// EQNSettingSeismicNetworkNotification.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 06/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
class EQNSettingSeismicNetworkNotification: NSObject {
|
||||
|
||||
enum FilterType: Int {
|
||||
case soloRilevanti
|
||||
case condizionati
|
||||
|
||||
var displayName: String {
|
||||
switch self {
|
||||
case .soloRilevanti: NSLocalizedString("options_official_type_relevant", comment: "")
|
||||
case .condizionati: NSLocalizedString("options_official_type_area", comment: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc(sharedInstance)
|
||||
static let shared = EQNSettingSeismicNetworkNotification()
|
||||
|
||||
@objc var isAbilitato: Bool
|
||||
@objc var magnitudoMinima: String
|
||||
@objc var distanzaMassima: String
|
||||
var filtro: FilterType
|
||||
|
||||
private static let DefaultMagnitudoMinima = EQNData.DefaultFilterMagnitude.value
|
||||
private static let DefaultDistanzaMassima = EQNData.DefaultFilterRadius.value
|
||||
private static let DefaultFiltro = FilterType.soloRilevanti
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
override init() {
|
||||
Self.migrate_v5_8()
|
||||
|
||||
let defaults = UserDefaults.standard
|
||||
self.isAbilitato = defaults.bool(forKey: UserDefaults.NotificheRetiSismicheAbilitato)
|
||||
self.magnitudoMinima = defaults.object(forKey: UserDefaults.NotificheRetiSismicheMagnitudoMinima, or: Self.DefaultMagnitudoMinima)
|
||||
self.distanzaMassima = defaults.object(forKey: UserDefaults.NotificheRetiSismicheDistanzaMassima, or: Self.DefaultDistanzaMassima)
|
||||
self.filtro = defaults.enumObject(forKey: UserDefaults.NotificheRetiSismicheFiltroNotifiche, or: Self.DefaultFiltro)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func saveUserInfo() {
|
||||
let defaults = UserDefaults.standard
|
||||
defaults.set(isAbilitato, forKey: UserDefaults.NotificheRetiSismicheAbilitato)
|
||||
defaults.set(magnitudoMinima, forKey: UserDefaults.NotificheRetiSismicheMagnitudoMinima)
|
||||
defaults.set(distanzaMassima, forKey: UserDefaults.NotificheRetiSismicheDistanzaMassima)
|
||||
defaults.set(filtro.rawValue, forKey: UserDefaults.NotificheRetiSismicheFiltroNotifiche)
|
||||
}
|
||||
|
||||
@objc class func saveDefaultValues() {
|
||||
shared.isAbilitato = true
|
||||
shared.magnitudoMinima = DefaultMagnitudoMinima
|
||||
shared.distanzaMassima = DefaultDistanzaMassima
|
||||
shared.filtro = DefaultFiltro
|
||||
shared.saveUserInfo()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private class func migrate_v5_8() {
|
||||
// migriamo i valori della distanza massima che sono diminuti nella v5.8
|
||||
// In precedenzai valori ammessi erano: 50, 100, 200, 300, 400, 500, 600, 800, 1000, 2000, 4000, qualsiasi distanza
|
||||
// ora invece sono solamente 100, 250, 500, 1000
|
||||
let defaults = UserDefaults.standard
|
||||
let alreadyMigrated = defaults.bool(forKey: UserDefaults.SettingsSeismicNetworkNotificationMigrationV5_8)
|
||||
if alreadyMigrated {
|
||||
return
|
||||
}
|
||||
|
||||
guard let savedDistance = defaults.object(forKey: UserDefaults.NotificheRetiSismicheDistanzaMassima) as? String else {
|
||||
defaults.set(true, forKey: UserDefaults.SettingsSeismicNetworkNotificationMigrationV5_8)
|
||||
return
|
||||
}
|
||||
|
||||
let maxDistance = switch savedDistance {
|
||||
case "50", "100": "100"
|
||||
case "200", "300": "250"
|
||||
case "400", "500", "600": "500"
|
||||
default:
|
||||
// 800, 1000, 2000, 4000, qualsiasi distanza
|
||||
"1000"
|
||||
}
|
||||
defaults.set(maxDistance, forKey: UserDefaults.NotificheRetiSismicheDistanzaMassima)
|
||||
defaults.set(true, forKey: UserDefaults.SettingsSeismicNetworkNotificationMigrationV5_8)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// EQNSettingUserReportNotification.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 10/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
@objc
|
||||
class EQNSettingUserReportNotification: NSObject {
|
||||
|
||||
@objc(sharedInstance)
|
||||
static let shared = EQNSettingUserReportNotification()
|
||||
|
||||
@objc var isAbilitato: Bool
|
||||
@objc var distanzaMassima: String
|
||||
|
||||
private static let DefaultDistanzaMassima = EQNData.DefaultSettingUserReportNotificationRadius.value
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
override init() {
|
||||
Self.migrate_v5_8()
|
||||
|
||||
let defaults = UserDefaults.standard
|
||||
self.isAbilitato = defaults.bool(forKey: UserDefaults.NotificheSegnalazioniUtenteAbilitato)
|
||||
self.distanzaMassima = defaults.object(forKey: UserDefaults.NotificheSegnalazioniUtenteDistanzaPosizione, or: Self.DefaultDistanzaMassima)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func saveUserInfo() {
|
||||
let defaults = UserDefaults.standard
|
||||
defaults.set(isAbilitato, forKey: UserDefaults.NotificheSegnalazioniUtenteAbilitato)
|
||||
defaults.set(distanzaMassima, forKey: UserDefaults.NotificheSegnalazioniUtenteDistanzaPosizione)
|
||||
}
|
||||
|
||||
@objc class func saveDefaultValues() {
|
||||
shared.isAbilitato = true
|
||||
shared.distanzaMassima = DefaultDistanzaMassima
|
||||
shared.saveUserInfo()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private class func migrate_v5_8() {
|
||||
// migriamo i valori della distanza massima che sono diminuti nella v5.8
|
||||
// In precedenzai valori ammessi erano: 50, 100, 200, 300, 400, 500, 600, 800, 1000, 2000, 4000, qualsiasi distanza
|
||||
// ora invece sono solamente 100, 250, 500, 1000
|
||||
let defaults = UserDefaults.standard
|
||||
let alreadyMigrated = defaults.bool(forKey: UserDefaults.SettingsUserReportNotificationMigrationV5_8)
|
||||
if alreadyMigrated {
|
||||
return
|
||||
}
|
||||
|
||||
guard let savedDistance = defaults.object(forKey: UserDefaults.NotificheSegnalazioniUtenteDistanzaPosizione) as? String else {
|
||||
defaults.set(true, forKey: UserDefaults.SettingsUserReportNotificationMigrationV5_8)
|
||||
return
|
||||
}
|
||||
|
||||
let maxDistance = switch savedDistance {
|
||||
case "50", "100": "100"
|
||||
case "200", "300": "250"
|
||||
case "400", "500", "600": "500"
|
||||
default:
|
||||
// 800, 1000, 2000, 4000, qualsiasi distanza
|
||||
"1000"
|
||||
}
|
||||
defaults.set(maxDistance, forKey: UserDefaults.NotificheSegnalazioniUtenteDistanzaPosizione)
|
||||
defaults.set(true, forKey: UserDefaults.SettingsUserReportNotificationMigrationV5_8)
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "navbar-icon-sort.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "navbar-icon-sort@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "navbar-icon-sort@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 118 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 138 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 167 B |
@@ -11,9 +11,6 @@
|
||||
#import "EQNUser.h"
|
||||
#import "EQNCalibrazione.h"
|
||||
#import "EQNRilevamento.h"
|
||||
#import "EQNNotificheSegnalazioniUtente.h"
|
||||
#import "EQNNotificheReteSismiche.h"
|
||||
#import "EQNAllertaSismica.h"
|
||||
#import <MapKit/MapKit.h>
|
||||
|
||||
@implementation EQNGeneratoreURLServer
|
||||
@@ -127,109 +124,15 @@
|
||||
|
||||
+ (NSURL *)urlInvioImpostazioniNotifiche
|
||||
{
|
||||
NSString *n_e = [NSString stringWithFormat:@"&n_e=%i",[EQNAllertaSismica sharedInstance].isAbilitato];
|
||||
NSString *n_m = [NSString stringWithFormat:@"&n_m=%i",[EQNNotificheSegnalazioniUtente sharedInstance].isAbilitato];
|
||||
NSString *n_o = [NSString stringWithFormat:@"&n_o=%i",[EQNNotificheReteSismiche sharedInstance].isAbilitato];
|
||||
NSString *n_o_near = [NSString stringWithFormat:@"&n_o_near=%i",[EQNNotificheReteSismiche sharedInstance].isAbilitaVicini];
|
||||
NSString *n_o_mag = [NSString stringWithFormat:@"&n_o_mag=%@",[EQNNotificheReteSismiche sharedInstance].energiaSisma];
|
||||
EQNSettingRealTimeAlert *allerta = [EQNSettingRealTimeAlert sharedInstance];
|
||||
EQNSettingUserReportNotification *utente = [EQNSettingUserReportNotification sharedInstance];
|
||||
EQNSettingSeismicNetworkNotification *reti = [EQNSettingSeismicNetworkNotification sharedInstance];
|
||||
CGFloat latitude = [EQNUser defaultUser].lastPosition.coordinate.latitude;
|
||||
CGFloat longitude = [EQNUser defaultUser].lastPosition.coordinate.longitude;
|
||||
|
||||
NSString *n_o_usgs = @"&n_o_usgs=0";
|
||||
NSString *n_o_emsc = @"&n_o_emsc=0";
|
||||
NSString *n_o_ingv = @"&n_o_ingv=0";
|
||||
NSString *n_o_ign = @"&n_o_ign=0";
|
||||
NSString *n_o_csi = @"&n_o_csi=0";
|
||||
NSString *n_o_jma = @"&n_o_jma=0";
|
||||
NSString *n_o_ineter = @"&n_o_ineter=0";
|
||||
NSString *n_o_ssn = @"&n_o_ssn=0";
|
||||
NSString *n_o_sgc = @"&n_o_sgc=0";
|
||||
NSString *n_o_rsn = @"&n_o_rsn=0";
|
||||
NSString *n_o_csn = @"&n_o_csn=0";
|
||||
NSString *n_o_funvisis = @"&n_o_funvisis=0";
|
||||
NSString *n_o_geonet = @"&n_o_geonet=0";
|
||||
NSString *n_o_inpres = @"&n_o_inpres=0";
|
||||
NSString *n_o_igepn = @"&n_o_igepn=0";
|
||||
NSString *n_o_phivolcs = @"&n_o_phivolcs=0";
|
||||
NSString *n_o_igp = @"&n_o_igp=0";
|
||||
NSString *n_o_uasd = @"&n_o_uasd=0";
|
||||
NSString *n_o_rspr = @"&n_o_rspr=0";
|
||||
NSString *n_o_bdtim = @"&n_o_bdtim=0";
|
||||
NSString *n_o_ncs = @"&n_o_ncs=0";
|
||||
NSString *n_o_uao = @"&n_o_uao=0";
|
||||
|
||||
for (NSString *ente in [EQNNotificheReteSismiche sharedInstance].listaEnti) {
|
||||
if ([ente isEqualToString:@"USGS"]) {
|
||||
n_o_usgs = @"&n_o_usgs=1";
|
||||
} else if ([ente isEqualToString:@"EMSC"]) {
|
||||
n_o_emsc = @"&n_o_emsc=1";
|
||||
} else if ([ente isEqualToString:@"INGV"]) {
|
||||
n_o_ingv = @"&n_o_ingv=1";
|
||||
} else if ([ente isEqualToString:@"IGN"]) {
|
||||
n_o_ign = @"&n_o_ign=1";
|
||||
} else if ([ente isEqualToString:@"CSI"]) {
|
||||
n_o_csi = @"&n_o_csi=1";
|
||||
} else if ([ente isEqualToString:@"JMA"]) {
|
||||
n_o_jma = @"&n_o_jma=1";
|
||||
} else if ([ente isEqualToString:@"Ineter"]) {
|
||||
n_o_ineter = @"&n_o_ineter=1";
|
||||
} else if ([ente isEqualToString:@"SSN"]) {
|
||||
n_o_ssn = @"&n_o_ssn=1";
|
||||
} else if ([ente isEqualToString:@"SGC"]) {
|
||||
n_o_sgc = @"&n_o_sgc=1";
|
||||
} else if ([ente isEqualToString:@"RSN"]) {
|
||||
n_o_rsn = @"&n_o_rsn=1";
|
||||
} else if ([ente isEqualToString:@"CSN"]) {
|
||||
n_o_csn = @"&n_o_csn=1";
|
||||
} else if ([ente isEqualToString:@"FUNVISIS"]) {
|
||||
n_o_funvisis = @"&n_o_funvisis=1";
|
||||
} else if ([ente isEqualToString:@"GeoNet"]) {
|
||||
n_o_geonet = @"&n_o_geonet=1";
|
||||
} else if ([ente isEqualToString:@"INPRES"]) {
|
||||
n_o_inpres = @"&n_o_inpres=1";
|
||||
} else if ([ente isEqualToString:@"IGEPN"]) {
|
||||
n_o_igepn = @"&n_o_igepn=1";
|
||||
} else if ([ente isEqualToString:@"PHIVOLCS"]) {
|
||||
n_o_phivolcs = @"&n_o_phivolcs=1";
|
||||
} else if ([ente isEqualToString:@"IGP"]) {
|
||||
n_o_igp = @"&n_o_igp=1";
|
||||
} else if ([ente isEqualToString:@"UASD"]) {
|
||||
n_o_uasd = @"&n_o_uasd=1";
|
||||
} else if ([ente isEqualToString:@"RSPR"]) {
|
||||
n_o_rspr = @"&n_o_rspr=1";
|
||||
} else if ([ente isEqualToString:@"BDTIM"]) {
|
||||
n_o_bdtim = @"&n_o_bdtim=1";
|
||||
} else if ([ente isEqualToString:@"NCS"]) {
|
||||
n_o_ncs = @"&n_o_ncs=1";
|
||||
} else if ([ente isEqualToString:@"XXX"]) {
|
||||
n_o_uao = @"&n_o_uao=1";
|
||||
}
|
||||
}
|
||||
NSString *enti = [NSString stringWithFormat:@"%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@", n_o_usgs, n_o_emsc, n_o_ingv, n_o_ign, n_o_csi, n_o_jma, n_o_ineter, n_o_ssn, n_o_sgc, n_o_rsn, n_o_csn, n_o_funvisis, n_o_geonet, n_o_inpres, n_o_igepn, n_o_phivolcs, n_o_igp, n_o_uasd, n_o_rspr, n_o_bdtim, n_o_ncs, n_o_uao];
|
||||
|
||||
NSString *n_o_strong = [NSString stringWithFormat:@"&n_o_strong=%i",[EQNNotificheReteSismiche sharedInstance].isTerremortiForti];
|
||||
|
||||
// andrea.busi - 27/09/2020: manteniamo il controllo su eventuali valori "Qualsiasi intensità/distanza" salvati
|
||||
// non sembrano servire, perchè i valori sono salvati come 100.000 anche nelle versioni prcedenti alla 2.0
|
||||
// per sicurezza, però, teniamo i controlli
|
||||
|
||||
NSString *n_o_strmag = [NSString stringWithFormat:@"&n_o_strmag=%@", [EQNNotificheReteSismiche sharedInstance].energiaTerremotiForti];
|
||||
|
||||
// andrea.busi - 18/05/2023: filtri rimossi, inviamo al WS dei valori fissi
|
||||
NSString *r_e_mild = @"&r_e_mild=100000";
|
||||
NSString *r_e_strong = @"&r_e_strong=100000";
|
||||
NSString *n_e_type = @"&n_e_type=0";
|
||||
|
||||
NSString *r_m = [NSString stringWithFormat:@"&r_m=%@", [EQNNotificheSegnalazioniUtente sharedInstance].distanzaPosizione];
|
||||
if ([[EQNNotificheSegnalazioniUtente sharedInstance].distanzaPosizione isEqualToString:NSLocalizedString(@"radius_any_distance", @"")]) {
|
||||
r_m = @"&r_m=100000";
|
||||
}
|
||||
|
||||
NSString *r_o = [NSString stringWithFormat:@"&r_o=%@", [EQNNotificheReteSismiche sharedInstance].distanzaPosizione];
|
||||
if ([[EQNNotificheReteSismiche sharedInstance].distanzaPosizione isEqualToString:NSLocalizedString(@"radius_any_distance", @"")]) {
|
||||
r_o = @"&r_o=100000";
|
||||
}
|
||||
|
||||
NSString *stringUrl = [NSString stringWithFormat:@"%@?u_id=%@&lat=%f&lon=%f%@%@%@%@%@%@%@%@%@%@%@%@%@", EQNServerUrlUploadSettings, [EQNUser defaultUser].user_ID, [EQNUser defaultUser].lastPosition.coordinate.latitude, [EQNUser defaultUser].lastPosition.coordinate.longitude, n_e, n_m, n_o, n_o_near,n_o_mag, enti, n_o_strong, n_e_type, n_o_strmag, r_e_mild, r_e_strong, r_m, r_o];
|
||||
NSString *stringUrl = [NSString stringWithFormat:@"%@?u_id=%@&lat=%f&lon=%f&n_e=%i&n_m=%i&n_o=%i&n_o_mag=%@&r_m=%@&r_o=%@", EQNServerUrlUploadSettings, [EQNUser defaultUser].user_ID, latitude, longitude, allerta.isAbilitato, utente.isAbilitato, reti.isAbilitato, reti.magnitudoMinima, utente.distanzaMassima, reti.distanzaMassima ];
|
||||
|
||||
NSLog(@"[DEBUG] url %@", stringUrl);
|
||||
|
||||
return [NSURL URLWithString:stringUrl];
|
||||
}
|
||||
@@ -249,7 +152,7 @@
|
||||
|
||||
+ (NSURL *)urlAlertPushTest
|
||||
{
|
||||
EQNGenericValue *radius = [EQNData raggioSismaFor:[EQNAllertaSismica sharedInstance].raggioSismiLievi];
|
||||
EQNGenericValue *radius = [EQNData getSettingSeismicNetworkAlertRadiusForValue:[EQNSettingRealTimeAlert sharedInstance].raggioSismiLievi];
|
||||
CLLocationCoordinate2D lastPosition = [EQNUser defaultUser].lastPosition.coordinate;
|
||||
NSString *stringUrl = [NSString stringWithFormat:@"%@?u_id=%@&radius=%@&lat=%f&lon=%f", EQNServerUrlTestAlarm, [EQNUser defaultUser].user_ID, radius.value, lastPosition.latitude, lastPosition.longitude ];
|
||||
return [NSURL URLWithString:stringUrl];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,9 @@ class AppTheme: NSObject {
|
||||
static let gray = UIColor(named: "Gray")!
|
||||
static let darkGray = UIColor(named: "Gray (dark)")!
|
||||
static let lightGray = UIColor(named: "Gray (light)")!
|
||||
|
||||
static let cardBackgroundRed = UIColor(named: "Red (card background)")!
|
||||
static let cardBackgroundGreen = UIColor(named: "Green (card background)")!
|
||||
}
|
||||
|
||||
static let shared = AppTheme()
|
||||
@@ -30,6 +33,9 @@ class AppTheme: NSObject {
|
||||
/// Color used for label that contains value (ex. in settings page)
|
||||
var valueColor: UIColor = .blue
|
||||
|
||||
/// Color for text inside cards
|
||||
var cardTextColor: UIColor = Colors.darkGray
|
||||
|
||||
/// Border color for button (needed only for @objc interoperability)
|
||||
var buttonBorderColor = AppTheme.Colors.gray
|
||||
/// Border with for button
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// EQNBaseContainerTableViewCell.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 14/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Shogun
|
||||
|
||||
|
||||
extension CGFloat {
|
||||
fileprivate static let cardVerticalMargin: CGFloat = 4.0
|
||||
fileprivate static let cardHorizontalMargin: CGFloat = 8.0
|
||||
|
||||
/// Padding between the card border and the internal content
|
||||
static let cardPadding: CGFloat = 8.0
|
||||
/// Spacing between items inside a card
|
||||
static let cardVerticalSpacing: CGFloat = 10.0
|
||||
}
|
||||
|
||||
class EQNBaseContainerTableViewCell: UITableViewCell {
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var internalContainerView: UIView = {
|
||||
let view = UIView(frame: .zero)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.backgroundColor = .white
|
||||
view.layer.cornerRadius = AppTheme.shared.cardCornerRadius
|
||||
view.layer.masksToBounds = false
|
||||
|
||||
// add shadow
|
||||
view.layer.shadowColor = UIColor.black.cgColor
|
||||
view.layer.shadowOpacity = 0.5
|
||||
view.layer.shadowOffset = CGSize(width: 0, height: 2)
|
||||
view.layer.shadowRadius = 2
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var chevronView: UIImageView = {
|
||||
let imageView = UIImageView(image: .init(systemName: "chevron.right"))
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.tintColor = AppTheme.Colors.lightGray
|
||||
return imageView
|
||||
}()
|
||||
|
||||
lazy var containerView: UIView = {
|
||||
let view = UIView(frame: .zero)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var headerLabel: UILabel = {
|
||||
let label = EQNEdgeInsetLabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.backgroundColor = AppTheme.Colors.lightBlue
|
||||
label.font = .systemFont(ofSize: 17.0, weight: .medium)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var emptyTopView: UIView = {
|
||||
let view = UIView(frame: .zero)
|
||||
view.backgroundColor = .clear
|
||||
return view
|
||||
}()
|
||||
|
||||
/// Returns the top view to use to attach descendant constraints
|
||||
var topView: UIView {
|
||||
isHeaderVisible ? headerLabel : emptyTopView
|
||||
}
|
||||
|
||||
/// If `true` an header on the top left corner will be visible
|
||||
var isHeaderVisible: Bool { true }
|
||||
/// If `true` a right chevron is displayed on right side
|
||||
var isRightArrowVisbile: Bool { false }
|
||||
/// Text to display inside the header
|
||||
var headerText: String { "" }
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
setupUI()
|
||||
updateUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
setupUI()
|
||||
updateUI()
|
||||
}
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
func setupUI() {
|
||||
selectionStyle = .default
|
||||
backgroundColor = .clear
|
||||
|
||||
contentView.addSubview(internalContainerView)
|
||||
|
||||
internalContainerView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: .cardVerticalMargin).isActive = true
|
||||
internalContainerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: .cardHorizontalMargin.negative).isActive = true
|
||||
internalContainerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: .cardHorizontalMargin).isActive = true
|
||||
internalContainerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: .cardVerticalMargin.negative).isActive = true
|
||||
|
||||
internalContainerView.addSubview(containerView)
|
||||
containerView.topAnchor.constraint(equalTo: internalContainerView.topAnchor).isActive = true
|
||||
containerView.leadingAnchor.constraint(equalTo: internalContainerView.leadingAnchor).isActive = true
|
||||
containerView.bottomAnchor.constraint(equalTo: internalContainerView.bottomAnchor).isActive = true
|
||||
|
||||
if isRightArrowVisbile {
|
||||
contentView.addSubview(chevronView)
|
||||
|
||||
chevronView.centerYAnchor.constraint(equalTo: internalContainerView.centerYAnchor).isActive = true
|
||||
chevronView.trailingAnchor.constraint(equalTo: internalContainerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
chevronView.heightAnchor.constraint(equalToConstant: 24.0).isActive = true
|
||||
chevronView.widthAnchor.constraint(equalTo: chevronView.heightAnchor).isActive = true
|
||||
|
||||
containerView.trailingAnchor.constraint(equalTo: chevronView.leadingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
} else {
|
||||
containerView.trailingAnchor.constraint(equalTo: internalContainerView.trailingAnchor).isActive = true
|
||||
}
|
||||
|
||||
if isHeaderVisible {
|
||||
containerView.addSubview(headerLabel)
|
||||
headerLabel.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
|
||||
headerLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
|
||||
headerLabel.heightAnchor.constraint(equalToConstant: 26.0).isActive = true
|
||||
} else {
|
||||
containerView.addSubview(emptyTopView)
|
||||
emptyTopView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
|
||||
emptyTopView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
|
||||
emptyTopView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
|
||||
emptyTopView.heightAnchor.constraint(equalToConstant: 0.0).isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
func updateUI() {
|
||||
// setup titles, colors and UI stuff here
|
||||
headerLabel.text = headerText.firstCharacterCapitalized
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright © 2021 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import MapKit
|
||||
|
||||
|
||||
|
||||
@@ -22,14 +22,52 @@ class EQNRoundedButton: UIButton {
|
||||
setupUI()
|
||||
}
|
||||
|
||||
// MARK: - Overrides
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
get {
|
||||
return titleLabel?.intrinsicContentSize ?? CGSize.zero
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
// adapt button height to titleLabel size
|
||||
titleLabel?.preferredMaxLayoutWidth = titleLabel?.frame.size.width ?? 0
|
||||
super.layoutSubviews()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupUI() {
|
||||
// add border
|
||||
layer.masksToBounds = true
|
||||
layer.borderWidth = AppTheme.shared.buttonBorderWidth
|
||||
layer.borderColor = AppTheme.Colors.gray.cgColor
|
||||
layer.cornerRadius = AppTheme.shared.buttonCornerRadius
|
||||
|
||||
// setup button for multiline title
|
||||
titleLabel?.font = .preferredFont(forTextStyle: .body)
|
||||
titleLabel?.lineBreakMode = .byWordWrapping
|
||||
titleLabel?.textAlignment = .center
|
||||
titleLabel?.numberOfLines = 0
|
||||
titleLabel?.adjustsFontForContentSizeCategory = true
|
||||
|
||||
setTitle(titleLabel?.text?.uppercased(), for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
extension EQNRoundedButton {
|
||||
class func make(
|
||||
title: String = "",
|
||||
target: Any,
|
||||
action: Selector
|
||||
) -> EQNRoundedButton {
|
||||
let button = EQNRoundedButton(type: .custom)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.addTarget(target, action: action, for: .touchUpInside)
|
||||
button.setTitle(title.uppercased(), for: .normal)
|
||||
button.setTitleColor(AppTheme.Colors.darkGray, for: .normal)
|
||||
button.backgroundColor = UIColor.white.withAlphaComponent(0.5)
|
||||
return button
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// EQNSeismicAnnotationView.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 21/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MapKit
|
||||
|
||||
|
||||
class EQNSeismicAnnotationView: MKAnnotationView {
|
||||
|
||||
static let IdentifierFull = "EQNSeismicAnnotationViewFull"
|
||||
static let IdentifierLight = "EQNSeismicAnnotationViewLight"
|
||||
static let IdentifierCircle = "EQNSeismicAnnotationViewCircle"
|
||||
|
||||
|
||||
private static let LabelHeight: CGFloat = 15.0
|
||||
private static let MagnitudeHeight: CGFloat = 25.0
|
||||
private static let MagnitudeWidth: CGFloat = 45.0
|
||||
private static let FullViewHeight: CGFloat = MagnitudeHeight + 2*LabelHeight
|
||||
private static let FullViewWidth: CGFloat = 100.0
|
||||
private static let SmallViewHeight: CGFloat = MagnitudeHeight
|
||||
private static let SmallViewWidth: CGFloat = 100.0
|
||||
static let CircleViewHeight: CGFloat = 20.0
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
var title: String? {
|
||||
set { labelTop.text = newValue }
|
||||
get { labelTop.text }
|
||||
}
|
||||
|
||||
var subtitle: String? {
|
||||
set { labelBottom.text = newValue }
|
||||
get { labelBottom.text }
|
||||
}
|
||||
|
||||
var magnitude: String? {
|
||||
set { magnitudeLabel.text = newValue }
|
||||
get { magnitudeLabel.text }
|
||||
}
|
||||
|
||||
var magnitudeColor: UIColor {
|
||||
set { magnitudeLabel.textColor = newValue }
|
||||
get { magnitudeLabel.textColor }
|
||||
}
|
||||
|
||||
var isUserSelection: Bool = false {
|
||||
didSet {
|
||||
magnitudeView.layer.borderColor = isUserSelection ? AppTheme.Colors.red.cgColor : AppTheme.Colors.darkGray.cgColor
|
||||
magnitudeView.layer.borderWidth = isUserSelection ? 2.0 : 1.0
|
||||
}
|
||||
}
|
||||
|
||||
@objc public override var image: UIImage? {
|
||||
set { imageView.image = newValue }
|
||||
get { imageView.image }
|
||||
}
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var imageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var magnitudeView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white
|
||||
view.layer.cornerRadius = 6.0
|
||||
view.layer.borderWidth = 1.0
|
||||
view.layer.borderColor = AppTheme.Colors.darkGray.cgColor
|
||||
view.clipsToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var magnitudeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.systemFont(ofSize: 12, weight: .bold)
|
||||
label.textAlignment = .center
|
||||
label.textColor = AppTheme.Colors.lightBlue
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var labelTop: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.systemFont(ofSize: 11, weight: .semibold)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var labelBottom: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.systemFont(ofSize: 11, weight: .semibold)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
|
||||
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
|
||||
|
||||
backgroundColor = .clear
|
||||
|
||||
if reuseIdentifier == Self.IdentifierFull {
|
||||
frame = CGRect(x: 0, y: 0, width: Self.FullViewWidth, height: Self.FullViewHeight)
|
||||
setupFullUI()
|
||||
} else if reuseIdentifier == Self.IdentifierLight {
|
||||
frame = CGRect(x: 0, y: 0, width: Self.SmallViewWidth, height: Self.SmallViewHeight)
|
||||
setupLightUI()
|
||||
} else if reuseIdentifier == Self.IdentifierCircle {
|
||||
frame = CGRect(x: 0, y: 0, width: Self.CircleViewHeight, height: Self.CircleViewHeight)
|
||||
setupCircleUI()
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupFullUI() {
|
||||
let labelTopFrame = CGRect(x: 0, y: 0, width: frame.width, height: Self.LabelHeight)
|
||||
labelTop.frame = labelTopFrame
|
||||
addSubview(labelTop)
|
||||
|
||||
magnitudeView.frame = CGRect(x: 0, y: 0, width: Self.MagnitudeWidth, height: Self.MagnitudeHeight)
|
||||
magnitudeView.center = center
|
||||
addSubview(magnitudeView)
|
||||
|
||||
magnitudeLabel.frame = magnitudeView.bounds
|
||||
magnitudeLabel.center = magnitudeView.center
|
||||
addSubview(magnitudeLabel)
|
||||
|
||||
labelBottom.frame = CGRect(x: 0, y: magnitudeView.frame.maxY, width: frame.width, height: Self.LabelHeight)
|
||||
addSubview(labelBottom)
|
||||
}
|
||||
|
||||
private func setupLightUI() {
|
||||
magnitudeView.frame = CGRect(x: 0, y: 0, width: Self.MagnitudeWidth, height: Self.MagnitudeHeight)
|
||||
magnitudeView.center = center
|
||||
addSubview(magnitudeView)
|
||||
|
||||
magnitudeLabel.frame = magnitudeView.bounds
|
||||
magnitudeLabel.center = magnitudeView.center
|
||||
addSubview(magnitudeLabel)
|
||||
}
|
||||
|
||||
private func setupCircleUI() {
|
||||
imageView.frame = CGRect(x: 0, y: 0, width: Self.CircleViewHeight, height: Self.CircleViewHeight)
|
||||
imageView.center = center
|
||||
addSubview(imageView)
|
||||
}
|
||||
}
|
||||
@@ -29,12 +29,11 @@
|
||||
"tab_official" = "الشبكات الزلزالية";
|
||||
"inapp_available_10k" = "\U200FTop 10K %lu اشتراكات لا تزال متوفرة ليتم تنبيهها في أقل من ثانية واحدة منذ اكتشاف الزلزال";
|
||||
"inapp_available_100k" = "\U200FTop 100K %lu اشتراكات لا تزال متوفرة ليتم تنبيهها في أقل من 5 ثوان منذ اكتشاف الزلزال";
|
||||
"filter_magnitude" = "القدر الأدنى";
|
||||
"filter_distance" = "البعد الأقصى";
|
||||
"filter_timeframe" = "إطار زمني";
|
||||
"filter_strong" = "أظهر الزلازل القوية على أي بعد إذا كان من";
|
||||
"filter_near" = "أظهر الزلازل مهما كانت قوتها إذا كانت أقرب من 50 كم";
|
||||
"filter_reflect" = "قم بتغيير إعدادات إخطار الزلازل وفقا للمرشحات";
|
||||
"filter_filter" = "اختر الزلازل التي تريد عرضها";
|
||||
"filter_show_area" = "إظهار كافة الزلازل ضمن دائرة نصف قطرها:";
|
||||
"filter_show_relevant" = "إظهار الزلازل ذات الصلة بموقعي فقط";
|
||||
"filter_show_all" = "عرض جميع الزلازل على مستوى العالم (M≥2)";
|
||||
"filter_minimum_magnitude" = "والحجم الأدنى:";
|
||||
"main_understood" = "مفهوم";
|
||||
"options_low_magnitude" = "الانتباه إلى أن ليست كل الشبكات الزلزالية توفر بيانات الزلازل التي تقل عن 2.0 درجة. علاوة على ذلك ، فإنك تزيد بشكل كبير من نقل البيانات واستخدام البطارية بسبب الإخطارات. ما لم يتم تصنيع جهازك حديثا ، ستلاحظ أيضا تباطؤا عاما.";
|
||||
"share_radius100" = "%@ في دائرة نصف قطرها 100 كم";
|
||||
@@ -42,14 +41,17 @@
|
||||
"official_reports" = "تم الإشعار من قبل %@ من المستخدمين";
|
||||
"official_prelimiary" = "تمهيدي";
|
||||
"calendar_description_nogeo_km" = "\U200Fزلزال M%@، عمق %@ كم.";
|
||||
"filter_empty" = "إعتمادا على المرشحات والشبكات الزلزالية التي تم تفعيلها, لم تحدث زلازل في آخر 24 ساعة. لتغيير المرشحات انقر على الشريط البنفسجي في الأسفل. لتمكين الشبكات الزلزالية الأخرى ، انقر فوق رمز العالم في الأعلى.";
|
||||
"official_select_message" = "ستستلم إشعارات فقط من شبكة المراقبة للبلد المحدد وستتضمن القائمة الاكتشافات القادمة من تلك الشبكة فقط. هل تؤكّد؟";
|
||||
"official_select_confirm" = "قم بالتأكيد على الدولة";
|
||||
"filter_empty_area" = "لا توجد زلازل خلال الـ 24 ساعة الماضية وفقًا للمرشحات";
|
||||
"filter_empty_relevant" = "لم تكن هناك زلازل ذات صلة بموقعك خلال الـ 24 ساعة الماضية";
|
||||
"filter_nolocation" = "هذا الخيار غير متاح لأن موقعك غير معروف";
|
||||
"official_provider" = "المصدر: %@";
|
||||
"share_hashtag" = "#زلزال أرضي";
|
||||
"share_notified" = "قررت من خلال التطبيق منبه الزلازل. قم بتنزيل التطبيق من https://sismo.app/download/ لاستلام تنبيهات في الوقت الفعلي حول #earthquake @SismoDetector";
|
||||
"manual_sure" = "هل تريد فعلا التنقرير عن زلزال أرضي؟";
|
||||
"manual_yes" = "نعم";
|
||||
"filter_filter" = "مرشحات";
|
||||
"filter_area" = "الزلازل المعروضة: في دائرة نصف قطرها";
|
||||
"filter_relevant" = "الزلازل المعروضة: ذات صلة";
|
||||
"filter_all" = "الزلازل المعروضة: الكل";
|
||||
"liveview_unknown_location" = "موقفك غير معروف. تمكين موقع الهاتف الذكي من تكوين الهاتف الذكي";
|
||||
"map_number" = "تم الكشف عن زلزال بواسطة %@ الهواتف الذكية";
|
||||
"permission_location_no" = "لقد اخترت منع التطبيق من قراءة موقع الجهاز. لن تستلم تنبيهات وإشعارات في الوقت الفعلي";
|
||||
@@ -70,18 +72,16 @@
|
||||
"globe_simulation_message6" = "مع مركز الزلزال هذا ، بفضل خدمة الأولوية %.0f، يجب أن تتلقى التنبيه مقدمًا قبل %.0fثانية. ستكون أول من يتم تنبيهه";
|
||||
"globe_simulation_priority" = "خدمة الأولوية";
|
||||
"status_cancel" = "ألغي";
|
||||
"options_near_alert" = "قم بالإبلاغ عن الزلازل مهما كانت قوتها إذا كانت المسافة أقل من 50 كم";
|
||||
"options_alarms" = "تنبيه بوقت فعلي";
|
||||
"options_notification_enable_alarm" = "قم بتفعيل الإنذار عند اكتشاف زلزال في الوقت الفعلي بواسطة شبكة الهواتف الذكية";
|
||||
"options_notification_official" = "إخطارات الشبكة الزلزالية";
|
||||
"options_notification_enable_official" = "استلم بلاغات الزلازل المكتشفة من قبل الشبكات الزلزالية الوطنية والدولية";
|
||||
"options_agencies" = "الشبكات الزلزالية";
|
||||
"options_notification_enable_official" = "تلقي إشعارات بشأن الزلازل التي اكتشفتها شبكات الزلازل الوطنية والدولية";
|
||||
"options_official_type" = "مرشح الإشعارات";
|
||||
"options_official_type_relevant" = "الزلازل ذات الصلة فقط";
|
||||
"options_official_type_area" = "الزلازل فقط بناءً على الشروط التالية";
|
||||
"options_radius" = "المجال من موقعك";
|
||||
"options_energy" = "طاقة الزلزال";
|
||||
"options_near" = "بالقرب من الزلازل الأرضية";
|
||||
"options_strong" = "زلازل قوية";
|
||||
"options_strong_alert" = "قم بالإخطار عن الزلازل على أي مسافة إذا كان حجمها أعلى من";
|
||||
"options_strong_magnitude" = "درجة";
|
||||
"options_official_minmag" = "الحد الأدنى للحجم";
|
||||
"options_official_maxdist" = "المسافة القصو";
|
||||
"options_notification_manual" = "إشعارات تقرير المستخدم";
|
||||
"options_notification_enable_manual" = "استلم الإخطارات للزلازل التي أبلغ عنها يدويا من قبل المستخدمين";
|
||||
"main_areacheck_message" = "في الوقت الحالي ، يوجد في منطقتك %s هواتف ذكية تراقب الزلازل في الوقت الفعلي. قدرة شبكة الهاتف الذكي على اكتشاف الزلازل في الوقت الفعلي هي%@. لتحسين اكتشاف الزلازل في منطقتك ، شارك التطبيق مع عائلتك وأصدقائك ، شكرًا!";
|
||||
@@ -222,3 +222,11 @@
|
||||
"calendar_missing_permission" = "لا يمكن فتح التقويم ، تأكد من تعيين الأذونات الصحيحة.";
|
||||
"error_server_registration" = "لم يكن من الممكن التسجيل في خادم التطبيق. التسجيل مطلوب لتلقي التنبيهات في الوقت الحقيقي وإشعارات الزلازل.";
|
||||
"retry" = "أعد المحاولة";
|
||||
"sort_date" = "حجم";
|
||||
"sort_position" = "مسافة";
|
||||
"sort_magnitude" = "تاريخ";
|
||||
"subscriptions_available" = "الاشتراكات المتاحة";
|
||||
"more_details" = "المزيد من التفاصيل";
|
||||
"subscription_plan_monthly" = "شهريا";
|
||||
"subscription_plan_yearly" = "سنوي";
|
||||
"subscription_plan_perpetual" = "حياة";
|
||||
|
||||
@@ -28,12 +28,11 @@
|
||||
"tab_official" = "ΣΕΙΣΜΙΚΑ ΔΙΚΤΥΑ";
|
||||
"inapp_available_10k" = "Top 10K: %lu εγγραφές είναι ακόμη διαθέσιμες για ειδοποίηση σε λιγότερο από 1 δευτερόλεπτο από την ανίχνευση του σεισμού";
|
||||
"inapp_available_100k" = "Top 100K: %lu εγγραφή είναι ακόμη διαθέσιμη για ειδοποίηση σε λιγότερο από 5 δευτερόλεπτα από την ανίχνευση του σεισμού";
|
||||
"filter_magnitude" = "Ελάχιστο μέγεθος";
|
||||
"filter_distance" = "Μέγιστη απόσταση";
|
||||
"filter_timeframe" = "Χρονικό πλαίσιο";
|
||||
"filter_strong" = "Εμφάνιση ισχυρών σεισμών σε οποιαδήποτε απόσταση εάν είναι";
|
||||
"filter_near" = "Δείξτε σεισμούς οποιουδήποτε μεγέθους σε απόσταση μικρότερη των 50 km";
|
||||
"filter_reflect" = "Αλλαγή ρυθμίσεων κοινοποίησης σεισμών σύμφωνα με τα φίλτρα";
|
||||
"filter_filter" = "Επιλέξτε ποιους σεισμούς θέλετε να δείτε";
|
||||
"filter_show_area" = "Εμφάνιση όλων των σεισμών σε ακτίνα:";
|
||||
"filter_show_relevant" = "Εμφάνιση μόνο των σχετικών σεισμών σε σχέση με την τοποθεσία μου";
|
||||
"filter_show_all" = "Εμφάνιση όλων των σεισμών παγκοσμίως (M≥2)";
|
||||
"filter_minimum_magnitude" = "και ελάχιστο μέγεθος:";
|
||||
"main_understood" = "Κατάλαβα";
|
||||
"options_low_magnitude" = "Λάβε υπόψη ότι δεν παρέχουν όλα τα σεισμικά δίκτυα δεδομένα για σεισμούς με μέγεθος κάτω από 2.0. Επίσης, αυξάνεις σημαντικά την μεταφορά δεδομένων και την χρήση μπαταρίας λόγω κοινοποιήσεων. Αν η συσκευή σου δεν είναι πρόσφατης κατασκευής, θα παρατηρήσεις επίσης μια γενική επιβράδυνση.";
|
||||
"share_radius100" = "%@ σε ακτίνα 100χλμ";
|
||||
@@ -41,14 +40,17 @@
|
||||
"official_reports" = "Αναφέρθηκαν από %@ χρήστες";
|
||||
"official_prelimiary" = "ΠΡΟΚΑΤΑΡΚΤΙΚΟ";
|
||||
"calendar_description_nogeo_km" = "Σεισμός M%@, βάθος %@ km.";
|
||||
"filter_empty" = "Σύμφωνα με τα φίλτρα και τα ενεργοποιημένα σεισμικά δίκτυα, δεν υπάρχουν σεισμοί τις τελευταίες 24 ώρες. Για την αλλαγή των φίλτρων κάνε κλικ στην γραμμή στο κάτω μέρος. Για να ενεργοποιήσεις άλλα σεισμικά δίκτυα κάνε κλικ στο εικονίδιο κόσμος στο επάνω μέρος.";
|
||||
"official_select_message" = "Θα λαμβάνεις κοινοποιήσεις μόνο από το δίκτυο παρακολούθησης της επιλεγόμενης χώρας και η λίστα θα περιλαμβάνει μόνο τις ανιχνεύσεις από το δίκτυο. Θέλεις να επιβεβαιώσεις;";
|
||||
"official_select_confirm" = "Επιβεβαίωση χώρας";
|
||||
"filter_empty_area" = "Δεν υπάρχουν σεισμοί τις τελευταίες 24 ώρες σύμφωνα με τα φίλτρα";
|
||||
"filter_empty_relevant" = "Δεν υπάρχουν σχετικοί σεισμοί τις τελευταίες 24 ώρες σε σχέση με την τοποθεσία σας";
|
||||
"filter_nolocation" = "Αυτή η επιλογή δεν είναι διαθέσιμη επειδή η τοποθεσία σας είναι άγνωστη";
|
||||
"official_provider" = "Πηγή: %@";
|
||||
"share_hashtag" = "#σεισμός";
|
||||
"share_notified" = "Έχει αναφερθεί μέσω της εφαρμογής Ανιχνευτής Σεισμών. Κατέβασε την εφαρμογή από το https://sismo.app/download/ για να λαμβάνεις σε πραγματικό χρόνο ειδοποιήσεις #σεισμού @SismoDetector";
|
||||
"manual_sure" = "Θέλεις πράγματι να κοινοποιήσεις έναν σεισμό;";
|
||||
"manual_yes" = "Ναι";
|
||||
"filter_filter" = "Φίλτρα";
|
||||
"filter_area" = "Εμφανίζονται σεισμοί: στην ακτίνα";
|
||||
"filter_relevant" = "Εμφανίζονται σεισμοί: σχετικοί";
|
||||
"filter_all" = "Εμφανίζονται σεισμοί: όλοι (M≥2)";
|
||||
"liveview_unknown_location" = "Η θέση σου είναι άγνωστη. Ενεργοποίησε την τοποθεσία του smartphone από την διαμόρφωση του smartphone";
|
||||
"map_number" = "Ανιχνεύθηκε δόνηση από %@ smartphone";
|
||||
"permission_location_no" = "Έχεις επιλέξει να αποτρέπεις την εφαρμογή από την ανάγνωση της τοποθεσίας της συσκευής. ΔΕΝ θα λαμβάνεις κοινοποιήσεις και ειδοποιήσεις σε πραγματικό χρόνο";
|
||||
@@ -69,18 +71,16 @@
|
||||
"globe_simulation_message6" = "Με αυτό το επίκεντρο, χάρη στην υπηρεσία προτεραιότητας %@ θα λάβεις την ειδοποίηση %.0f δευτερόλεπτα νωρίτερα. Θα είσαι ο πρώτος που θα ειδοποιηθεί!";
|
||||
"globe_simulation_priority" = "Υπηρεσία προτεραιότητας";
|
||||
"status_cancel" = "Διαγραφή";
|
||||
"options_near_alert" = "Κοινοποίηση σεισμών οποιουδήποτε μεγέθους εάν η απόσταση είναι κάτω από 50 km";
|
||||
"options_alarms" = "Ειδοποίηση σε πραγματικό χρόνο";
|
||||
"options_notification_enable_alarm" = "Να ακούγεται συναγερμός όταν ανιχνεύεται σεισμός σε πραγματικό χρόνο από το δίκτυο smartphone";
|
||||
"options_notification_official" = "Κοινοποιήσεις σεισμικών δικτύων";
|
||||
"options_notification_enable_official" = "Λήψη κοινοποιήσεων σεισμών που ανιχνεύονται από εθνικά και διεθνή σεισμικά δίκτυα.";
|
||||
"options_agencies" = "Σεισμικά δίκτυα";
|
||||
"options_notification_enable_official" = "Λήψη ειδοποιήσεων για τους σεισμούς που εντοπίζονται από τα εθνικά και διεθνή σεισμικά δίκτυα";
|
||||
"options_official_type" = "Φίλτρο ειδοποιήσεων";
|
||||
"options_official_type_relevant" = "Μόνο σχετικοί σεισμοί";
|
||||
"options_official_type_area" = "Μόνο σεισμοί με βάση τις ακόλουθες συνθήκες";
|
||||
"options_radius" = "Ακτίνα από την θέση σου";
|
||||
"options_energy" = "Ενέργεια σεισμού";
|
||||
"options_near" = "Πλησιέστεροι σεισμοί";
|
||||
"options_strong" = "Ισχυροί σεισμοί";
|
||||
"options_strong_alert" = "Κοινοποίηση σεισμών οποιασδήποτε απόστασης εάν το μέγεθος είναι μεγαλύτερο από";
|
||||
"options_strong_magnitude" = "Μέγεθος";
|
||||
"options_official_minmag" = "Ελάχιστο μέγεθος";
|
||||
"options_official_maxdist" = "Μέγιστη απόσταση";
|
||||
"options_notification_manual" = "Κοινοποιήσεις αναφοράς χρήστη";
|
||||
"options_notification_enable_manual" = "Λήψη κοινοποιήσεων σεισμών που αναφέρονται χειροκίνητα από χρήστες";
|
||||
"main_areacheck_message" = "Αυτήν τη στιγμή, στην περιοχή σου υπάρχουν %@ smartphone που παρακολουθούν σε πραγματικό χρόνο ενδεχόμενους σεισμούς. Για την βελτίωση της αποτύπωσης στην περιοχή σου μοιράσου την εφαρμογή με φίλους και συγγενείς, ευχαριστώ!";
|
||||
@@ -221,3 +221,11 @@
|
||||
"calendar_missing_permission" = "Το ημερολόγιο δεν μπορεί να ανοίξει, βεβαιωθείτε ότι έχετε ρυθμίσει τα σωστά δικαιώματα.";
|
||||
"error_server_registration" = "Δεν ήταν δυνατό να εγγραφείτε με το διακομιστή. Η εγγραφή υποχρεούται να λαμβάνει ειδοποιήσεις σε πραγματικό χρόνο και ειδοποιήσεις σεισμού.";
|
||||
"retry" = "Προσπαθησε ξανα";
|
||||
"sort_date" = "Ημερομηνία";
|
||||
"sort_position" = "Απόσταση";
|
||||
"sort_magnitude" = "Μέγεθος";
|
||||
"subscriptions_available" = "Διαθέσιμες συνδρομές";
|
||||
"more_details" = "Περισσότερες λεπτομέρειες";
|
||||
"subscription_plan_monthly" = "Μηνιαίο";
|
||||
"subscription_plan_yearly" = "Ετήσιο";
|
||||
"subscription_plan_perpetual" = "Διάρκεια Ζωής";
|
||||
|
||||
@@ -28,12 +28,11 @@
|
||||
"tab_official" = "SEISMIC NETWORKS";
|
||||
"inapp_available_10k" = "Top 10K: %lu subscriptions still available to be alerted in less than 1 second since the detection of the quake";
|
||||
"inapp_available_100k" = "Top 100K: %lu subscriptions still available to be alerted in less than 5 seconds since the detection of the quake";
|
||||
"filter_magnitude" = "Minimum magnitude";
|
||||
"filter_distance" = "Maximum distance";
|
||||
"filter_timeframe" = "Time frame";
|
||||
"filter_strong" = "Show strong quakes at any distance if of";
|
||||
"filter_near" = "Show quakes of any magnitude if closer than 50 km";
|
||||
"filter_reflect" = "Change the earthquake notification settings according to the filters";
|
||||
"filter_filter" = "Choose which earthquakes you want to view";
|
||||
"filter_show_area" = "Show all earthquakes within a radius of:";
|
||||
"filter_show_relevant" = "Show only the relevant earthquakes with respect to my location";
|
||||
"filter_show_all" = "Show all earthquakes globally (M≥2)";
|
||||
"filter_minimum_magnitude" = "and minimum magnitude:";
|
||||
"main_understood" = "Understood";
|
||||
"options_low_magnitude" = "Beware that not all seismic networks provide earthquake data below magnitude 2.0. Moreover, you significantly increase the data transfer and the battery usage due to notifications. Unless your device is recently manufactured, you will also notice a general slowdown.";
|
||||
"share_radius100" = "%@ in a radius of 100km";
|
||||
@@ -41,14 +40,17 @@
|
||||
"official_reports" = "Reported by %@ users";
|
||||
"official_prelimiary" = "PRELIMINARY";
|
||||
"calendar_description_nogeo_km" = "Earthquake M%@, depth %@ km.";
|
||||
"filter_empty" = "Based on the filters and enabled seismic networks, there are no earthquakes in the last 24 hours. To change the filters click on the purple bar at the bottom. Use the icons in the top bar to change filters or enable other seismic networks.";
|
||||
"official_select_message" = "You will receive notifications only from the monitoring network of the selected country and the list will include only the detections from that network. Do you confirm?";
|
||||
"official_select_confirm" = "Confirm country";
|
||||
"filter_empty_area" = "Nessun sisma nelle ultime 24 ore in base ai filtri impostati";
|
||||
"filter_empty_relevant" = "No relevant earthquakes in the last 24 hours with respect to your location";
|
||||
"filter_nolocation" = "This option is not available because your location is unknown";
|
||||
"official_provider" = "Source: %@";
|
||||
"share_hashtag" = "#earthquake";
|
||||
"share_notified" = "Reported through the app Earthquake Network. Download the app from https://sismo.app/download/ to receive real time alerts of #earthquake @SismoDetector";
|
||||
"manual_sure" = "Do you really want to notify an earthquake?";
|
||||
"manual_yes" = "Yes";
|
||||
"filter_filter" = "Filters";
|
||||
"filter_area" = "Quakes shown: in the radius";
|
||||
"filter_relevant" = "Quakes shown: relevant";
|
||||
"filter_all" = "Quakes shown: all (M≥2)";
|
||||
"liveview_unknown_location" = "Your position is unknown. Enable smartphone location from smartphone configuration";
|
||||
"map_number" = "Quake detected by %@ smartphones";
|
||||
"permission_location_no" = "You have chosen to prevent the app from reading the location of the device. You will NOT receive real-time notifications and alerts";
|
||||
@@ -69,18 +71,16 @@
|
||||
"globe_simulation_message6" = "With this epicentre, thanks to the %@ priority service you should receive the alert %.0f seconds in advance. You will be the first to be alerted!";
|
||||
"globe_simulation_priority" = "Priority service";
|
||||
"status_cancel" = "Cancel";
|
||||
"options_near_alert" = "Notify earthquakes of any magnitude if the distance is less than 50 km";
|
||||
"options_alarms" = "Real time alert";
|
||||
"options_notification_enable_alarm" = "Activate an alarm when a quake is detected in real time by the network of smartphones";
|
||||
"options_notification_official" = "Seismic network notifications";
|
||||
"options_notification_enable_official" = "Receive notifications for the earthquakes detected by the national and international seismic networks";
|
||||
"options_agencies" = "Seismic networks";
|
||||
"options_official_type" = "Notification filter";
|
||||
"options_official_type_relevant" = "Only relevant earthquakes";
|
||||
"options_official_type_area" = "Only earthquakes based on following conditions";
|
||||
"options_radius" = "Radius from your location";
|
||||
"options_energy" = "Earthquake energy";
|
||||
"options_near" = "Near earthquakes";
|
||||
"options_strong" = "Strong earthquakes";
|
||||
"options_strong_alert" = "Notify earthquakes at any distance if the magnitude is greater than";
|
||||
"options_strong_magnitude" = "Magnitud";
|
||||
"options_official_minmag" = "Minimum magnitude";
|
||||
"options_official_maxdist" = "Maximum distance";
|
||||
"options_notification_manual" = "User report notifications";
|
||||
"options_notification_enable_manual" = "Receive notifications of earthquakes manually reported by users";
|
||||
"main_areacheck_message" = "At this time, in your area there are %@ smartphones monitoring in real time for earthquakes. To improve detection share the app with your family and friends, thanks!";
|
||||
@@ -221,3 +221,11 @@
|
||||
"calendar_missing_permission" = "The calendar cannot be opened, make sure you have set the correct permissions.";
|
||||
"error_server_registration" = "It was not possible to register with the Earthquake Network server. Registration is required to receive real-time alerts and earthquake notifications.";
|
||||
"retry" = "Retry";
|
||||
"sort_date" = "Date";
|
||||
"sort_position" = "Distance";
|
||||
"sort_magnitude" = "Magnitude";
|
||||
"subscriptions_available" = "Subscriptions available";
|
||||
"more_details" = "More details";
|
||||
"subscription_plan_monthly" = "Monthly";
|
||||
"subscription_plan_yearly" = "Annual";
|
||||
"subscription_plan_perpetual" = "Lifetime";
|
||||
|
||||
@@ -28,12 +28,11 @@
|
||||
"tab_official" = "REDES SÍSMICAS";
|
||||
"inapp_available_10k" = "Top 10K: %lu suscripciones aún disponibles para recibir la alerta en menos de 1 segundo a partir de la detección del sismo";
|
||||
"inapp_available_100k" = "Top 100K: %lu suscripciones aún disponibles para recibir la alerta en menos de 5 segundos a partir de la detección del sismo";
|
||||
"filter_magnitude" = "Magnitud mínima";
|
||||
"filter_distance" = "Distancia máxima";
|
||||
"filter_timeframe" = "Periodo de tiempo";
|
||||
"filter_strong" = "Muestra sismos fuertes a cualquier distancia si de";
|
||||
"filter_near" = "Muestra sismos de cualquier magnitud si están a menos de 50 km";
|
||||
"filter_reflect" = "Cambia las notificaciones de sismo de acuerdo a los filtros";
|
||||
"filter_filter" = "Elige qué sismos quieres ver";
|
||||
"filter_show_area" = "Mostrar todos los sismos en un radio de:";
|
||||
"filter_show_relevant" = "Mostrar solo los sismos relevantes con respecto a mi ubicación";
|
||||
"filter_show_all" = "Mostrar todos los sismos globalmente (M≥2)";
|
||||
"filter_minimum_magnitude" = "y magnitud mínima:";
|
||||
"main_understood" = "Entendido";
|
||||
"options_low_magnitude" = "Tenga en cuenta que no todas las redes sísmicas proporcionan datos para sismos de magnitud inferior a 2.0. Además, aumenta significativamente la transferencia de datos con el servidor y el uso de la batería debido a la mayor cantidad de notificaciones. Si tu dispositivo no se ha fabricado recientemente, también notará una desaceleración general de la aplicación.";
|
||||
"share_radius100" = "%@ en un radio de 100km";
|
||||
@@ -41,14 +40,17 @@
|
||||
"official_reports" = "Reportado por %@ usuarios";
|
||||
"official_prelimiary" = "PRELIMINAR";
|
||||
"calendar_description_nogeo_km" = "Sismo M%@, profundidad %@ km.";
|
||||
"filter_empty" = "Según los filtros y las redes sísmicas habilitadas, no hay sismos en las últimas 24 horas. Para cambiar los filtros, haga clic en la barra en la parte inferior. Para habilitar otras redes sísmicas, haga clic en el icono en forma de mundo en la parte superior.";
|
||||
"official_select_message" = "Recibirá notificaciones solo desde la red de monitoreo del país seleccionado y la lista incluirá solo las detecciones de esa red. ¿Confirmas?";
|
||||
"official_select_confirm" = "Confirmar país";
|
||||
"filter_empty_area" = "No hay sismos en las últimas 24 horas según los filtros";
|
||||
"filter_empty_relevant" = "No hay sismos relevantes en las últimas 24 horas con respecto a tu ubicación";
|
||||
"filter_nolocation" = "Esta opción no está disponible porque tu ubicación es desconocida";
|
||||
"official_provider" = "Fuente: %@";
|
||||
"share_hashtag" = "#sismo";
|
||||
"share_notified" = "Reportado a través de la app Sismo Detector. Descarga la app desde https://sismo.app/download/ para recibir alertas de #sismo en tiempo real @SismoDetector";
|
||||
"manual_sure" = "¿Estas seguro de querer reportar un sismo?";
|
||||
"manual_yes" = "Sí";
|
||||
"filter_filter" = "Filtros";
|
||||
"filter_area" = "Sismos mostrados: en el radio";
|
||||
"filter_relevant" = "Sismos mostrados: relevantes";
|
||||
"filter_all" = "Sismos mostrados: todos (M≥2)";
|
||||
"liveview_unknown_location" = "Tu posición es desconocida. Habilitar la ubicación del smartphone desde la página de configuración del smartphone";
|
||||
"map_number" = "Sismo detectado por %@ smartphones";
|
||||
"permission_location_no" = "Ha elegido evitar que la aplicación lea la ubicación de tu dispositivo. NO recibirá notificaciones y alertas en tiempo real";
|
||||
@@ -69,18 +71,16 @@
|
||||
"globe_simulation_message6" = "Con este epicentro, gracias al servicio de prioridad %@, deberías recibir la alerta %.0f segundos antes. ¡Serás la primera persona en ser alertada!";
|
||||
"globe_simulation_priority" = "Servicio prioritario";
|
||||
"status_cancel" = "Clara";
|
||||
"options_near_alert" = "Notifica sismos de cualquier magnitud si la distancia es inferior a 50 km";
|
||||
"options_alarms" = "Alerta en tiempo real";
|
||||
"options_notification_enable_alarm" = "Suena una alarma cuando se detecta un sismo en tiempo real por la red de los teléfonos inteligentes";
|
||||
"options_notification_official" = "Notificaciones redes sísmicas";
|
||||
"options_notification_enable_official" = "Recibe las notificaciones de los sismos detectados por las redes sísmicas oficiales nacionales e internacionales";
|
||||
"options_agencies" = "Redes sísmicas";
|
||||
"options_notification_enable_official" = "Recibe las notificaciones de los sismos detectados por las redes sísmicas nacionales e internacionales";
|
||||
"options_official_type" = "Filtro de notificaciones";
|
||||
"options_official_type_relevant" = "Solo sismos relevantes";
|
||||
"options_official_type_area" = "Solo sismos basados en las siguientes condiciones";
|
||||
"options_radius" = "Radio desde tu posición";
|
||||
"options_energy" = "Energía del sismo";
|
||||
"options_near" = "Sismos cercanos";
|
||||
"options_strong" = "Sismos fuertes";
|
||||
"options_strong_alert" = "Notifica sismos a cualquier distancia si la magnitud es mayor que";
|
||||
"options_strong_magnitude" = "Magnitud";
|
||||
"options_official_minmag" = "Magnitud mínima";
|
||||
"options_official_maxdist" = "Distancia máxima";
|
||||
"options_notification_manual" = "Notificaciones de reportes manuales";
|
||||
"options_notification_enable_manual" = "Recibe las notificaciones de los sismos reportados manualmente por los usuarios";
|
||||
"main_areacheck_message" = "En este momento, en tu área hay %@ smartphones que están monitoreando los sismos en tiempo real. Para mejorar la detección en tu área comparta la app con tus amigos y familia, gracias!";
|
||||
@@ -221,3 +221,11 @@
|
||||
"calendar_missing_permission" = "El calendario no se puede abrir, asegúrese de haber configurado los permisos correctos.";
|
||||
"error_server_registration" = "No fue posible registrarse en el servidor de Sismo Detector. Es necesario registrarse para recibir alertas y notificaciones de terremotos en tiempo real.";
|
||||
"retry" = "Reintentar";
|
||||
"sort_date" = "Fecha";
|
||||
"sort_position" = "Distancia";
|
||||
"sort_magnitude" = "Magnitud";
|
||||
"subscriptions_available" = "Suscripciones disponibles";
|
||||
"more_details" = "Más detalles";
|
||||
"subscription_plan_monthly" = "Mensual";
|
||||
"subscription_plan_yearly" = "Anual";
|
||||
"subscription_plan_perpetual" = "Para siempre";
|
||||
|
||||
@@ -28,12 +28,11 @@
|
||||
"tab_official" = "RÉSEAUX SISMIQUES";
|
||||
"inapp_available_10k" = "Top 10K : %lu abonnements encore disponibles pour être alerté en moins de 1 seconde à partir de la détection du séisme";
|
||||
"inapp_available_100k" = "Top 100K : %lu abonnements encore disponibles pour être alerté en moins de 5 secondes à partir de la détection du séisme";
|
||||
"filter_magnitude" = "Magnitude minimale";
|
||||
"filter_distance" = "Distance maximale";
|
||||
"filter_timeframe" = "Plage de temps";
|
||||
"filter_strong" = "Affichez de forts séismes à n'importe quelle distance si la magnitude est de";
|
||||
"filter_near" = "Afficher les séismes de toute magnitude s'ils sont à moins de 50 km";
|
||||
"filter_reflect" = "Modifiez les paramètres de notification des séismes en fonction des filtres";
|
||||
"filter_filter" = "Choisissez les tremblements de terre que vous souhaitez visualiser";
|
||||
"filter_show_area" = "Afficher tous les tremblements de terre dans un rayon de :";
|
||||
"filter_show_relevant" = "Afficher uniquement les tremblements de terre pertinents par rapport à ma position";
|
||||
"filter_show_all" = "Afficher tous les tremblements de terre globalement (M≥2)";
|
||||
"filter_minimum_magnitude" = "et magnitude minimale :";
|
||||
"main_understood" = "J'ai compris";
|
||||
"options_low_magnitude" = "Attention, les réseaux sismiques ne fournissent pas tous des données pour des séismes de magnitude inférieure à 2,0. De plus, vous augmentez significativement le transfert de données et l'utilisation de la batterie en raison du plus grand nombre de notifications. Sauf si votre appareil est de fabrication récente, vous remarquerez également un ralentissement général.";
|
||||
"share_radius100" = "%@ dans un rayon de 100km";
|
||||
@@ -41,14 +40,17 @@
|
||||
"official_reports" = "Signalé par %@ utilisateurs";
|
||||
"official_prelimiary" = "PRÉLIMINAIRE";
|
||||
"calendar_description_nogeo_km" = "Séisme M%@, profondeur %@ km.";
|
||||
"filter_empty" = "Sur la base des filtres et des réseaux sismiques activés, il n'y a pas de séismes au cours des 24 dernières heures. Pour changer les filtres, cliquez sur la barre en bas. Pour activer d'autres réseaux sismiques, cliquez sur l'icône en forme de monde en haut.";
|
||||
"official_select_message" = "Vous ne recevrez des notifications que du réseau de surveillance du pays sélectionné et la liste inclura uniquement les détections de ce réseau. Confirmez-vous ?";
|
||||
"official_select_confirm" = "Confirmez le pays";
|
||||
"filter_empty_area" = "Aucun tremblement de terre au cours des dernières 24 heures selon les filtres";
|
||||
"filter_empty_relevant" = "Aucun tremblement de terre pertinent au cours des dernières 24 heures par rapport à votre emplacement";
|
||||
"filter_nolocation" = "EsCette option n'est pas disponible car votre emplacement est inconnu";
|
||||
"official_provider" = "Source : %@";
|
||||
"share_hashtag" = "#séisme";
|
||||
"share_notified" = "Signalé via l'app Détecteur de Séisme. Téléchargez l'app depuis https://sismo.app/download/ pour recevoir des alertes de #séisme en temps réel @SismoDetector";
|
||||
"manual_sure" = "Voulez-vous vraiment signaler un séisme ?";
|
||||
"manual_yes" = "Oui";
|
||||
"filter_filter" = "Filtres";
|
||||
"filter_area" = "Séismes affichés : dans le rayon";
|
||||
"filter_relevant" = "Séismes affichés : pertinents";
|
||||
"filter_all" = "Séismes affichés : tous (M≥2)";
|
||||
"liveview_unknown_location" = "Votre position est inconnue. Activez la localisation à partir de la page de configuration de votre appareil";
|
||||
"map_number" = "Séisme détecté par %@ smartphones";
|
||||
"permission_location_no" = "Vous avez choisi d'empêcher l'app de lire la position de votre appareil. Vous ne recevrez PAS de notifications et d'alertes en temps réel";
|
||||
@@ -69,18 +71,16 @@
|
||||
"globe_simulation_message6" = "Avec cet épicentre, grâce au service prioritaire %@, vous devriez recevoir l'alerte %.0f secondes à l'avance. Vous serez le premier à être alerté!";
|
||||
"globe_simulation_priority" = "Service prioritaire";
|
||||
"status_cancel" = "Supprimer";
|
||||
"options_near_alert" = "Notifiez les séismes de toute magnitude si la distance est inférieure à 50 km";
|
||||
"options_alarms" = "Alerte en temps réel";
|
||||
"options_notification_enable_alarm" = "Une alarme retentit lorsqu'un séisme est détecté par le réseau des smartphones";
|
||||
"options_notification_official" = "Notifications de réseaux sismiquex";
|
||||
"options_notification_enable_official" = "Recevez les notifications des séismes détectés par les réseaux sismiques nationaux et internationaux";
|
||||
"options_agencies" = "Réseaux sismiques";
|
||||
"options_official_type" = "Filtre de notificatio";
|
||||
"options_official_type_relevant" = "Seuls les séismes pertinents";
|
||||
"options_official_type_area" = "Seuls les séismes basés sur les conditions suivantes";
|
||||
"options_radius" = "Rayon de votre position";
|
||||
"options_energy" = "Énergie du séisme";
|
||||
"options_near" = "Séismes à proximité";
|
||||
"options_strong" = "Séismes forts";
|
||||
"options_strong_alert" = "Notifiez les séismes à n'importe quelle distance si la magnitude est supérieure à";
|
||||
"options_strong_magnitude" = "Magnitude";
|
||||
"options_official_minmag" = "Magnitude minimale";
|
||||
"options_official_maxdist" = "Distance maximale";
|
||||
"options_notification_manual" = "Notifications de signalements utilisateur";
|
||||
"options_notification_enable_manual" = "Recevez les notifications des séismes signalés manuellement par les utilisateurs";
|
||||
"main_areacheck_message" = "En ce moment, dans votre zone, %@ smartphones effectuent une surveillance sismique en temps réel. Pour améliorer la détection des séismes dans votre zone, partagez l'app avec votre famille et vos amis, merci !";
|
||||
@@ -221,3 +221,11 @@
|
||||
"calendar_missing_permission" = "Le calendrier ne peut pas être ouvert, assurez-vous d'avoir défini les autorisations appropriées.";
|
||||
"error_server_registration" = "Il n'a pas été possible de s'inscrire auprès du serveur. L'inscription est requise pour recevoir des alertes en temps réel et des notifications de tremblement de terre.";
|
||||
"retry" = "Réessayez";
|
||||
"sort_date" = "Date";
|
||||
"sort_position" = "Distance";
|
||||
"sort_magnitude" = "Magnitude";
|
||||
"subscriptions_available" = "Abonnements disponibles";
|
||||
"more_details" = "Plus de détails";
|
||||
"subscription_plan_monthly" = "Mensuel";
|
||||
"subscription_plan_yearly" = "Annuel";
|
||||
"subscription_plan_perpetual" = "Pour toujours";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user