Compare commits
123 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 465d3e8013 | |||
| a7e88b43f5 | |||
| 57ef877846 | |||
| c44d97b9fb | |||
| fd4ed7f66f | |||
| ef5db97854 | |||
| ce0e17a0c5 | |||
| 2a46f1d2d6 | |||
| 93871f0358 | |||
| 3e8fe0680d | |||
| 6be5f72360 | |||
| ccd1b9de59 | |||
| 5737eb5b02 | |||
| c549bb6ea5 | |||
| ff80905033 | |||
| dad2bc5648 | |||
| 10c74e278e | |||
| 96dbf960d2 | |||
| 81bfdd02a6 | |||
| 2ab3267981 | |||
| 48b6941ed5 | |||
| 669cb3c4f3 | |||
| 638d819d35 | |||
| a9884d8a8d | |||
| 2ef3560011 | |||
| 05093bb7a4 | |||
| 55f84ab46d | |||
| 03b4d0ddd6 | |||
| 3c5f26bc94 | |||
| 8c79d45b19 | |||
| 931d04c5e1 | |||
| 4d62fbbbd3 | |||
| 1c7065ece7 | |||
| 6dfa51e013 | |||
| b8b21d1458 | |||
| 88317f79e8 | |||
| 4e1147e782 | |||
| 579969d507 | |||
| 4d991d9a10 | |||
| 41491b5ee7 | |||
| 197b375c28 | |||
| f41e6b50ec | |||
| 796e4b5895 | |||
| e43a93979d | |||
| ef1aaa7d71 | |||
| 22d78baa8a | |||
| e4588aa731 | |||
| 07764f91ed | |||
| a0a238e384 | |||
| 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,16 @@
|
||||
# Changelog
|
||||
|
||||
## Versione 5.8.1
|
||||
- Corrette traduzioni errate (causavano crash)
|
||||
- Aggiunto ordinamento in sottoscrizioni utente (prima Top10k)
|
||||
|
||||
## 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
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"magnitude_range" : "0",
|
||||
"google.c.a.e" : "1",
|
||||
"provider" : "INGV",
|
||||
"google.c.fid" : "fFjFx_Em8E-op_zHYXZpSr",
|
||||
"preliminary" : "0",
|
||||
"longitude" : "15.2917",
|
||||
"gcm.message_id" : "1719991146578422",
|
||||
"latitude" : "40.7738",
|
||||
"google.c.sender.id" : "899482329945",
|
||||
"type" : "official",
|
||||
"magnitude" : "1.4",
|
||||
"difference" : "13",
|
||||
"depth" : "14.6",
|
||||
"aps" : {
|
||||
"mutable-content" : 1,
|
||||
"alert" : {
|
||||
"body" : "Sisma rilevato a",
|
||||
"title-loc-key" : "Segnalazione da rete sismica",
|
||||
"title" : "Segnalazione da rete sismica",
|
||||
"loc-key" : "Sisma rilevato a",
|
||||
"action-loc-key" : "",
|
||||
"loc-args" : [
|
||||
"2 km SW Laviano (SA) - M1.4"
|
||||
]
|
||||
},
|
||||
"content-available" : 1,
|
||||
"sound" : "default"
|
||||
},
|
||||
"data" : "2024-07-03 09:05:52",
|
||||
"magnitude_type" : "ML",
|
||||
"place" : "2 km SW Laviano (SA)",
|
||||
"pop100" : "6824"
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"magnitude_range" : "0",
|
||||
"provider" : "SGC",
|
||||
"google.c.a.e" : "1",
|
||||
"google.c.fid" : "d3PS1dEvrUA-tmLLpl5E5f",
|
||||
"preliminary" : "0",
|
||||
"longitude" : "-75.5157",
|
||||
"gcm.message_id" : "1668682445010677",
|
||||
"latitude" : "4.35306",
|
||||
"type" : "official",
|
||||
"google.c.sender.id" : "899482329945",
|
||||
"difference" : "6",
|
||||
"data" : "2022-11-17 11:48:00",
|
||||
"depth" : "26",
|
||||
"aps" : {
|
||||
"content-available" : 1,
|
||||
"alert" : {
|
||||
"loc-key" : "Sisma rilevato a",
|
||||
"title-loc-key" : "Segnalazione da rete sismica",
|
||||
"loc-args" : [
|
||||
"Cajamarca - Tolima, Colombia - M2.2"
|
||||
]
|
||||
},
|
||||
"mutable-content" : 1,
|
||||
"sound" : "default"
|
||||
},
|
||||
"magnitude" : "2.2",
|
||||
"magnitude_type" : "M",
|
||||
"place" : "Cajamarca - Tolima, Colombia",
|
||||
"pop100" : "6622"
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
"loc-args": [
|
||||
"2 km da Foligno"
|
||||
],
|
||||
"loc-key": "Rilevato sisma forte a",
|
||||
"loc-key": "Sisma segnalato da utente a",
|
||||
"title-loc-key": "Allerta sismica in tempo reale"
|
||||
},
|
||||
"category": "notifica_con_mappa",
|
||||
|
||||
@@ -97,23 +97,8 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
// use a generic warning icon instead
|
||||
iconName = "warning_yellow.png"
|
||||
case "official":
|
||||
let provider = userInfo.string(forKey: "provider", orDefault: "")
|
||||
let intensity = userInfo.double(forKey: "magnitude", orDefault: 0)
|
||||
|
||||
let color: String
|
||||
if intensity < 2.0 {
|
||||
color = "_white"
|
||||
} else if intensity < 3.5 {
|
||||
color = "_green"
|
||||
} else if intensity < 4.5 {
|
||||
color = "_yellow"
|
||||
} else if intensity < 5.5 {
|
||||
color = "_red"
|
||||
} else {
|
||||
color = "_purple"
|
||||
}
|
||||
|
||||
iconName = manualIconName(for: provider, color: color)
|
||||
// don't show any images
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -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 */; };
|
||||
6590EFF82C3004EA00F41420 /* EQNOfficialPushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6590EFF72C3004EA00F41420 /* EQNOfficialPushNotification.swift */; };
|
||||
65AB4A952C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AB4A942C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.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 */; };
|
||||
@@ -239,14 +246,11 @@
|
||||
DC99A50324E66E270071BC9F /* EQNCommandProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC99A50224E66E270071BC9F /* EQNCommandProtocol.swift */; };
|
||||
DC99A50524E66E430071BC9F /* EQNAppearanceCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC99A50424E66E430071BC9F /* EQNAppearanceCommand.swift */; };
|
||||
DC99A50724E66E5F0071BC9F /* EQNStartupCommandsBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC99A50624E66E5F0071BC9F /* EQNStartupCommandsBuilder.swift */; };
|
||||
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 +303,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 +326,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>"; };
|
||||
@@ -339,6 +344,7 @@
|
||||
658BC02A2859A4D3009EECAA /* RealtimeAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealtimeAlertView.swift; sourceTree = "<group>"; };
|
||||
658F19692A0D1F8F00BECC05 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
658F196A2A0D1F8F00BECC05 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
6590EFF72C3004EA00F41420 /* EQNOfficialPushNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNOfficialPushNotification.swift; sourceTree = "<group>"; };
|
||||
65A4D5AA26280A24003918E0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
65A4D5AB26280A24003918E0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
65A4D5AC26280A56003918E0 /* el-GR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "el-GR"; path = "el-GR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
@@ -349,10 +355,17 @@
|
||||
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>"; };
|
||||
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 +485,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 +527,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 +549,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 +561,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>"; };
|
||||
@@ -577,14 +573,11 @@
|
||||
DC99A50224E66E270071BC9F /* EQNCommandProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNCommandProtocol.swift; sourceTree = "<group>"; };
|
||||
DC99A50424E66E430071BC9F /* EQNAppearanceCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNAppearanceCommand.swift; sourceTree = "<group>"; };
|
||||
DC99A50624E66E5F0071BC9F /* EQNStartupCommandsBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNStartupCommandsBuilder.swift; sourceTree = "<group>"; };
|
||||
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 +612,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 +686,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DC974AFE251748B300A139EC /* SeismicFiltersViewController.swift */,
|
||||
652C37BC26092B3C0068EC3B /* FiltersViewModel.swift */,
|
||||
);
|
||||
path = Filters;
|
||||
sourceTree = "<group>";
|
||||
@@ -841,7 +838,6 @@
|
||||
65FFDC93292F672B00EA821B /* EQNNotificationService */,
|
||||
8CBD3DC32149B9AD0070C963 /* Products */,
|
||||
8CC2B44D214AC7F8002ED1B2 /* Frameworks */,
|
||||
A7982CE92BD5D51B8E2AA92F /* Pods */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -884,7 +880,6 @@
|
||||
8CC2B44E214AC7F8002ED1B2 /* CoreMotion.framework */,
|
||||
8CF12CD221DE49B600613AC5 /* UserNotifications.framework */,
|
||||
8CF12CD421DE49B600613AC5 /* UserNotificationsUI.framework */,
|
||||
25A8BFFE29D46740E8A8A7A3 /* Pods_Earthquake_Network.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -902,15 +897,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 +915,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 +1088,7 @@
|
||||
DC99A50124E66DFB0071BC9F /* Commands */,
|
||||
DCEFF21824F587CC009D3FE1 /* Settings */,
|
||||
65DBFB5225E2A2580041CBA6 /* Map annotation */,
|
||||
8C483CBB21FDACE500259FD2 /* VersioneProProducts.swift */,
|
||||
8C483CBB21FDACE500259FD2 /* EQNInAppProducts.swift */,
|
||||
8C483CB721FDACD300259FD2 /* IAPHelper.swift */,
|
||||
DCF10DC524D2B8C7009F34C3 /* EQNPurchaseUtility.swift */,
|
||||
DCF10DCC24D2C935009F34C3 /* EQNPurchaseAvailability.swift */,
|
||||
@@ -1128,6 +1112,7 @@
|
||||
8CF4F4DA216D44930057110B /* EQNPastquakes.m */,
|
||||
65EA58812A60360D0038EE9D /* EQNRealtimePushNotification.swift */,
|
||||
6552C1452926DBA1008E723C /* AppPreferences.swift */,
|
||||
6590EFF72C3004EA00F41420 /* EQNOfficialPushNotification.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@@ -1155,12 +1140,13 @@
|
||||
DCC23DED24D28F41003A2404 /* UI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */,
|
||||
DCC23DEE24D28F58003A2404 /* EQNEdgeInsetLabel.swift */,
|
||||
DC03BEAA250BC0A60084769B /* EQNRoundedButton.swift */,
|
||||
DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */,
|
||||
DCA5B6E6252E4BD8002AEC96 /* EQNBaseTableViewCell.swift */,
|
||||
653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */,
|
||||
6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */,
|
||||
656E02152C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift */,
|
||||
653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */,
|
||||
65172F522C25C496006D2A5C /* EQNSeismicAnnotationView.swift */,
|
||||
);
|
||||
path = UI;
|
||||
sourceTree = "<group>";
|
||||
@@ -1170,10 +1156,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 +1170,10 @@
|
||||
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 */,
|
||||
65DB60F12C16FA3600164366 /* SettingsRealTimeAlertsViewController.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
@@ -1214,12 +1196,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 +1238,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 +1253,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 +1339,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 +1503,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 +1520,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 +1544,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,30 +1558,26 @@
|
||||
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 */,
|
||||
8C4E344B2152EE5B008B0D2A /* EQNGeneratoreURLServer.m in Sources */,
|
||||
6590EFF82C3004EA00F41420 /* EQNOfficialPushNotification.swift in Sources */,
|
||||
DC99A50724E66E5F0071BC9F /* EQNStartupCommandsBuilder.swift in Sources */,
|
||||
DCA5B6E7252E4BD8002AEC96 /* EQNBaseTableViewCell.swift in Sources */,
|
||||
8CF66058214C566B009F4314 /* ServerRequest.m in Sources */,
|
||||
DCF9E14D24F6D1AA002B6B1D /* EQNData.swift in Sources */,
|
||||
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 +1587,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,7 +1598,6 @@
|
||||
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 */,
|
||||
@@ -1693,9 +1605,8 @@
|
||||
DC47D1BC252A0C2B004119F6 /* AlertsPastEartquakesTableViewCell.swift in Sources */,
|
||||
654D18C925F93CD700BB6DB0 /* EQNMapAnnotationPastquake.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 +1615,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 +1773,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 139;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WJA4MR4CPC;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -1865,13 +1784,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.2;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationservice;
|
||||
@@ -1896,20 +1815,20 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 139;
|
||||
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.2;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationservice;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1978,7 +1897,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 +1953,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 +1963,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 +1970,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 = 139;
|
||||
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.2;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -2084,28 +2003,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 +2017,6 @@
|
||||
"-framework",
|
||||
"\"Security\"",
|
||||
"-framework",
|
||||
"\"Solar\"",
|
||||
"-framework",
|
||||
"\"StoreKit\"",
|
||||
"-framework",
|
||||
"\"SystemConfiguration\"",
|
||||
@@ -2127,8 +2026,6 @@
|
||||
"\"UserMessagingPlatform\"",
|
||||
"-framework",
|
||||
"\"WebKit\"",
|
||||
"-framework",
|
||||
"\"nanopb\"",
|
||||
"-weak_framework",
|
||||
"\"AdSupport\"",
|
||||
"-weak_framework",
|
||||
@@ -2153,7 +2050,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 +2057,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 = 139;
|
||||
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.2;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -2192,28 +2089,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 +2103,6 @@
|
||||
"-framework",
|
||||
"\"Security\"",
|
||||
"-framework",
|
||||
"\"Solar\"",
|
||||
"-framework",
|
||||
"\"StoreKit\"",
|
||||
"-framework",
|
||||
"\"SystemConfiguration\"",
|
||||
@@ -2235,8 +2112,6 @@
|
||||
"\"UserMessagingPlatform\"",
|
||||
"-framework",
|
||||
"\"WebKit\"",
|
||||
"-framework",
|
||||
"\"nanopb\"",
|
||||
"-weak_framework",
|
||||
"\"AdSupport\"",
|
||||
"-weak_framework",
|
||||
@@ -2265,7 +2140,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = EQNNotificationContent/EQNNotificationContent.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 139;
|
||||
DEVELOPMENT_TEAM = WJA4MR4CPC;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
@@ -2274,13 +2149,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.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationcontent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Content - Development";
|
||||
@@ -2299,20 +2174,20 @@
|
||||
CODE_SIGN_ENTITLEMENTS = EQNNotificationContent/EQNNotificationContent.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 121;
|
||||
CURRENT_PROJECT_VERSION = 139;
|
||||
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.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationcontent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Content - AppStore";
|
||||
@@ -2373,6 +2248,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 +2301,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>
|
||||
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
<?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/>
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"originHash" : "c29b9b16ee6b4d1a6fec2debc59749097860256c8cbb2addc2abc08d3adba59d",
|
||||
"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" : "eca84fd638116dd6adb633b5a3f31cc7befcbb7d",
|
||||
"version" : "10.29.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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,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.
|
||||
@@ -173,20 +170,22 @@
|
||||
{
|
||||
NSString *type = content.userInfo[@"type"];
|
||||
|
||||
// Store both original payload and modified title/body
|
||||
// This will be usefull to avoid to re-evaluate logic for title display.
|
||||
NSDictionary *notification = @{
|
||||
@"title": content.title,
|
||||
@"body": content.body,
|
||||
@"userInfo": content.userInfo
|
||||
};
|
||||
|
||||
EQNTabBarSection section = EQNTabBarSectionAllerte;
|
||||
if ([type isEqualToString:@"eqn"]) {
|
||||
// Store both original payload and modified title/body
|
||||
// This will be usefull to avoid to re-evaluate logic for title display.
|
||||
NSDictionary *notification = @{
|
||||
@"title": content.title,
|
||||
@"body": content.body,
|
||||
@"userInfo": content.userInfo
|
||||
};
|
||||
if ([type isEqualToString:@"eqn"]) {
|
||||
[EQNRealtimePushNotification storeNotificationWithPayload:notification];
|
||||
section = EQNTabBarSectionAllerte;
|
||||
} else if([type isEqualToString:@"manual"]) {
|
||||
section = EQNTabBarSectionSegnalazioni;
|
||||
} else if([type isEqualToString:@"official"]) {
|
||||
[EQNOfficialPushNotification storeNotificationWithPayload:notification];
|
||||
section = EQNTabBarSectionRetiSismiche;
|
||||
}
|
||||
|
||||
@@ -213,14 +212,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 +232,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 +242,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"
|
||||
@@ -45,6 +37,7 @@ extension UserDefaults {
|
||||
static let UserReportCodeStatus = "CODE_MESSAGE_EQN"
|
||||
|
||||
// Proprietà e preferenze dell'utente
|
||||
static let FirstAppStartExecuted = "EQNUserDefaultFirstAppStartExecuted"
|
||||
/// Ultima posizione conosciuta dell'utente
|
||||
static let UserDataLastLocation = "EQNLast_Location"
|
||||
/// Token Firebase dell'utente corrente
|
||||
@@ -67,19 +60,25 @@ extension UserDefaults {
|
||||
// Migrazioni
|
||||
static let AppMigrationV5_3 = "EQNUserDefaultMigrationV5_3"
|
||||
static let AppMigrationV5_4 = "EQNUserDefaultMigrationV5_4"
|
||||
static let AppMigrationV5_8 = "EQNUserDefaultMigrationV5_8"
|
||||
static let AppMigrationV5_8_2 = "EQNUserDefaultMigrationV5_8_2"
|
||||
|
||||
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"
|
||||
// Notifica rete sismica aperta
|
||||
static let OfficialAlertPayload = "EQNData.OfficialPushNotificationPayload"
|
||||
|
||||
// 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 +94,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,14 @@ 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:@"SeismicNotificationCompactCell"];
|
||||
[self.tableView registerClass:[AlertsSeismicNotificationExpandedTableViewCell class] forCellReuseIdentifier:@"SeismicNotificationExpandedCell"];
|
||||
[self.tableView registerClass:[AlertsPositionDataTableViewCell class] forCellReuseIdentifier:@"PositionDataCell"];
|
||||
|
||||
if (EQNBackgroundPositionDebugHelper.shared.isEnabled) {
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:self action:@selector(backgroundPositionDebugTapped:)];
|
||||
}
|
||||
@@ -265,14 +270,16 @@ 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;
|
||||
[cell updateWith:notification];
|
||||
|
||||
__weak AllerteViewController *weakSelf = self;
|
||||
cell.onTapClose = ^{
|
||||
@@ -291,7 +298,8 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
|
||||
return cell;
|
||||
}
|
||||
|
||||
AlertsSeismicNotificationCompactTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SeismicNotificationCell" forIndexPath:indexPath];
|
||||
AlertsSeismicNotificationCompactTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SeismicNotificationCompactCell" forIndexPath:indexPath];
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
|
||||
__weak AllerteViewController *weakSelf = self;
|
||||
cell.onTapAlertTest = ^{
|
||||
@@ -311,8 +319,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 +329,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 +338,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 +357,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)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+47
-22
@@ -8,37 +8,62 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class AlertsPriorityServiceTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
@objc var smartphoneNetwork: EQNReteSmartphone? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@objc
|
||||
class AlertsPriorityServiceTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
override var headerText: String { NSLocalizedString("inapp_list", comment: "") }
|
||||
override var isRightArrowVisbile: Bool { true }
|
||||
|
||||
// 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.pureRed
|
||||
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()
|
||||
|
||||
backgroundColor = AppTheme.Colors.cardBackgroundOrange
|
||||
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()
|
||||
|
||||
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?()
|
||||
}
|
||||
}
|
||||
|
||||
+152
-58
@@ -10,78 +10,173 @@ import UIKit
|
||||
import MapKit
|
||||
import Shogun
|
||||
|
||||
class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMapViewDelegate {
|
||||
|
||||
class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseContainerTableViewCell, MKMapViewDelegate {
|
||||
|
||||
override var isHeaderVisible: Bool { false }
|
||||
|
||||
typealias DefaultCompletion = () -> Void
|
||||
|
||||
@objc var notification: EQNRealtimePushNotification? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@objc var onTapOpenTwitter: DefaultCompletion?
|
||||
@objc var onTapRateApp: DefaultCompletion?
|
||||
@objc var onTapClose: DefaultCompletion?
|
||||
@objc var onTapShareApp: DefaultCompletion?
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private lazy var notificationTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .title1)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var notificationIntensityLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.numberOfLines = 0
|
||||
label.textColor = AppTheme.shared.cardTextColor
|
||||
label.font = .preferredFont(forTextStyle: .title1)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var notificationDescriptionLabel: 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 mapView: MKMapView = {
|
||||
let mapView = MKMapView()
|
||||
mapView.translatesAutoresizingMaskIntoConstraints = false
|
||||
mapView.delegate = self
|
||||
mapView.isScrollEnabled = false
|
||||
mapView.isZoomEnabled = false
|
||||
mapView.register(EQNCustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SingleLineIdentifier)
|
||||
return mapView
|
||||
}()
|
||||
|
||||
private lazy var shareButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(shareAppTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var rateAppButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(rateAppTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var viewOnTwitterButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(viewInTwitterTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var closeButton: UIButton = {
|
||||
let button = EQNRoundedButton.make(target: self, action: #selector(closeTapped(_:)))
|
||||
return button
|
||||
}()
|
||||
|
||||
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
|
||||
}()
|
||||
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
@IBOutlet weak var notificationTitleLabel: UILabel!
|
||||
@IBOutlet weak var notificationDescriptionLabel: UILabel!
|
||||
@IBOutlet weak var notificationIntensityLabel: UILabel!
|
||||
@IBOutlet weak var waveTimeLabel: UILabel!
|
||||
@IBOutlet weak var mapView: MKMapView! {
|
||||
didSet {
|
||||
mapView.delegate = self
|
||||
mapView.isScrollEnabled = false
|
||||
mapView.isZoomEnabled = false
|
||||
mapView.register(EQNCustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SingleLineIdentifier)
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var shareButton: UIButton!
|
||||
@IBOutlet private weak var rateAppButton: UIButton!
|
||||
@IBOutlet private weak var viewOnTwitterButton: UIButton!
|
||||
@IBOutlet private weak var closeButton: UIButton!
|
||||
@IBOutlet private weak var descriptionLabel: UILabel!
|
||||
private var impactTimestamp: Date?
|
||||
private var countdownTimer: Timer?
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
setUI()
|
||||
let stackView = UIStackView(arrangedSubviews: [shareButton, rateAppButton])
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.axis = .horizontal
|
||||
stackView.distribution = .fillEqually
|
||||
stackView.spacing = .cardVerticalSpacing
|
||||
|
||||
containerView.addSubview(notificationTitleLabel)
|
||||
containerView.addSubview(notificationIntensityLabel)
|
||||
containerView.addSubview(notificationDescriptionLabel)
|
||||
containerView.addSubview(mapView)
|
||||
containerView.addSubview(stackView)
|
||||
containerView.addSubview(viewOnTwitterButton)
|
||||
containerView.addSubview(descriptionLabel)
|
||||
containerView.addSubview(closeButton)
|
||||
|
||||
notificationTitleLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: .cardPadding).isActive = true
|
||||
notificationTitleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
|
||||
notificationTitleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
|
||||
|
||||
notificationIntensityLabel.topAnchor.constraint(equalTo: notificationTitleLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
notificationIntensityLabel.leadingAnchor.constraint(equalTo: notificationTitleLabel.leadingAnchor).isActive = true
|
||||
notificationIntensityLabel.trailingAnchor.constraint(equalTo: notificationTitleLabel.trailingAnchor).isActive = true
|
||||
|
||||
notificationDescriptionLabel.topAnchor.constraint(equalTo: notificationIntensityLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
notificationDescriptionLabel.leadingAnchor.constraint(equalTo: notificationTitleLabel.leadingAnchor).isActive = true
|
||||
notificationDescriptionLabel.trailingAnchor.constraint(equalTo: notificationTitleLabel.trailingAnchor).isActive = true
|
||||
|
||||
mapView.topAnchor.constraint(equalTo: notificationDescriptionLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
mapView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
|
||||
mapView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
|
||||
mapView.heightAnchor.constraint(greaterThanOrEqualToConstant: 240.0).isActive = true
|
||||
|
||||
shareButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 40.0).isActive = true
|
||||
rateAppButton.heightAnchor.constraint(equalTo: shareButton.heightAnchor).isActive = true
|
||||
viewOnTwitterButton.heightAnchor.constraint(equalTo: shareButton.heightAnchor).isActive = true
|
||||
closeButton.heightAnchor.constraint(equalTo: shareButton.heightAnchor).isActive = true
|
||||
stackView.topAnchor.constraint(equalTo: mapView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
stackView.leadingAnchor.constraint(equalTo: notificationDescriptionLabel.leadingAnchor).isActive = true
|
||||
stackView.trailingAnchor.constraint(equalTo: notificationDescriptionLabel.trailingAnchor).isActive = true
|
||||
|
||||
viewOnTwitterButton.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
viewOnTwitterButton.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true
|
||||
viewOnTwitterButton.trailingAnchor.constraint(equalTo: stackView.trailingAnchor).isActive = true
|
||||
|
||||
descriptionLabel.topAnchor.constraint(equalTo: viewOnTwitterButton.bottomAnchor, constant: .cardPadding).isActive = true
|
||||
descriptionLabel.leadingAnchor.constraint(equalTo: viewOnTwitterButton.leadingAnchor).isActive = true
|
||||
descriptionLabel.trailingAnchor.constraint(equalTo: viewOnTwitterButton.trailingAnchor).isActive = true
|
||||
|
||||
closeButton.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
|
||||
closeButton.leadingAnchor.constraint(equalTo: descriptionLabel.leadingAnchor).isActive = true
|
||||
closeButton.trailingAnchor.constraint(equalTo: descriptionLabel.trailingAnchor).isActive = true
|
||||
closeButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardVerticalSpacing.negative).isActive = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func localizeUI() {
|
||||
override func updateUI() {
|
||||
super.updateUI()
|
||||
|
||||
shareButton.setLocalizedTitle(key: "main_share_app")
|
||||
rateAppButton.setLocalizedTitle(key: "main_vote")
|
||||
viewOnTwitterButton.setLocalizedTitle(key: "main_twitter_see")
|
||||
closeButton.setLocalizedTitle(key: "official_close")
|
||||
descriptionLabel.text = NSLocalizedString("map_smartphone_magnitude", comment: "")
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
private func setUI() {
|
||||
shareButton.layer.borderColor = AppTheme.Colors.darkGray.cgColor
|
||||
rateAppButton.layer.borderColor = AppTheme.Colors.darkGray.cgColor
|
||||
viewOnTwitterButton.layer.borderColor = AppTheme.Colors.darkGray.cgColor
|
||||
closeButton.layer.borderColor = AppTheme.Colors.darkGray.cgColor
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
@objc
|
||||
func update(with notification: EQNRealtimePushNotification?) {
|
||||
// clearn any other previous notifications
|
||||
notificationTitleLabel.text = ""
|
||||
notificationDescriptionLabel.text = ""
|
||||
notificationTitleLabel.text = "Sisma rilevato a 150km (TEST)"
|
||||
notificationIntensityLabel.text = "Previsto uno scuotimento forte"
|
||||
notificationDescriptionLabel.text = "Distanza 150 km - 13 minuti fa"
|
||||
mapView.removeAnnotations(mapView.annotations)
|
||||
|
||||
guard let notification = notification else { return }
|
||||
|
||||
containerView.backgroundColor = backgroundColor(for: notification.relativeIntensity())
|
||||
|
||||
backgroundColor = backgroundColor(for: notification.relativeIntensity())
|
||||
notificationTitleLabel.text = notification.title
|
||||
notificationIntensityLabel.text = notification.displayBody
|
||||
notificationIntensityLabel.textColor = notification.relativeIntensityColor
|
||||
@@ -95,7 +190,6 @@ class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMa
|
||||
notificationDescriptionLabel.text = ""
|
||||
+ NSLocalizedString("official_card_distance", comment: "") + " \(distanceRound) km"
|
||||
+ " - " + EQNUtility.formattedString(forTimeDifference: difference)
|
||||
+ "\n" + String(format: NSLocalizedString("map_number", comment: ""), "\(notification.counter)")
|
||||
}
|
||||
|
||||
let span = MKCoordinateSpan(latitudeDelta: 10.5, longitudeDelta: 10.5)
|
||||
@@ -118,37 +212,37 @@ class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMa
|
||||
annotationView.title = annotation.title
|
||||
return annotationView
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction private func shareAppTapped(_ sender: UIButton) {
|
||||
@objc private func shareAppTapped(_ sender: UIButton) {
|
||||
onTapShareApp?()
|
||||
}
|
||||
|
||||
@IBAction private func rateAppTapped(_ sender: UIButton) {
|
||||
@objc private func rateAppTapped(_ sender: UIButton) {
|
||||
onTapRateApp?()
|
||||
}
|
||||
|
||||
@IBAction private func viewInTwitterTapped(_ sender: UIButton) {
|
||||
@objc private func viewInTwitterTapped(_ sender: UIButton) {
|
||||
onTapOpenTwitter?()
|
||||
}
|
||||
|
||||
@IBAction private func closeTapped(_ sender: UIButton) {
|
||||
@objc private func closeTapped(_ sender: UIButton) {
|
||||
onTapClose?()
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
// MARK: - Private
|
||||
|
||||
private func backgroundColor(for intensity: Double) -> UIColor {
|
||||
switch intensity {
|
||||
case _ where intensity < 0.004:
|
||||
return UIColor(named: "Gray (card background)")!
|
||||
return AppTheme.Colors.cardBackgroundGray
|
||||
case _ where intensity < 0.30:
|
||||
return UIColor(named: "Green (card background)")!
|
||||
return AppTheme.Colors.cardBackgroundGreen
|
||||
case _ where intensity < 0.70:
|
||||
return UIColor(named: "Yellow (card background)")!
|
||||
return AppTheme.Colors.cardBackgroundYellow
|
||||
default:
|
||||
return UIColor(named: "Red (card background)")!
|
||||
return AppTheme.Colors.cardBackgroundRed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+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
|
||||
|
||||
+69
-20
@@ -9,38 +9,87 @@
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
class SubscriptionsActiveTableViewCell: EQNBaseTableViewCell {
|
||||
|
||||
var product: SKProduct? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
class SubscriptionsActiveTableViewCell: EQNBaseContainerTableViewCell {
|
||||
|
||||
override var headerText: String { NSLocalizedString("inapp_active", comment: "") }
|
||||
|
||||
var onTapRestore: () -> Void = { }
|
||||
|
||||
// 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: - View Lifecycle
|
||||
private lazy var restoreButton: UIButton = {
|
||||
let button = UIButton(type: .system)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.addTarget(self, action: #selector(restoreSubscriptionsTapped(_:)), for: .touchUpInside)
|
||||
button.titleLabel?.font = .preferredFont(forTextStyle: .headline)
|
||||
button.backgroundColor = .systemGroupedBackground
|
||||
button.eqn_applyShadowAndRoundedCorners()
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
override func setupUI() {
|
||||
super.setupUI()
|
||||
|
||||
localizeUI()
|
||||
let stackView = UIStackView(arrangedSubviews: [ activeSubscriptionImageView, noSubscriptionsLabel, restoreButton ])
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.alignment = .center
|
||||
stackView.distribution = .equalSpacing
|
||||
stackView.axis = .vertical
|
||||
stackView.spacing = 20.0
|
||||
containerView.addSubview(stackView)
|
||||
|
||||
activeSubscriptionImageView.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
|
||||
activeSubscriptionImageView.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
|
||||
restoreButton.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
|
||||
restoreButton.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true
|
||||
restoreButton.trailingAnchor.constraint(equalTo: stackView.trailingAnchor).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: "")
|
||||
restoreButton.setTitle(NSLocalizedString("purchase_pro_restore", comment: ""), for: .normal)
|
||||
}
|
||||
|
||||
private func updateUI() {
|
||||
if let productIdentifier = product?.productIdentifier {
|
||||
// MARK: - Actions
|
||||
|
||||
@objc private func restoreSubscriptionsTapped(_ sender: UIButton) {
|
||||
onTapRestore()
|
||||
}
|
||||
|
||||
// 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() {
|
||||
@@ -90,75 +80,52 @@ class SubscriptionsViewController: UITableViewController {
|
||||
}
|
||||
|
||||
private func configureUI() {
|
||||
let restoreButton = UIBarButtonItem(title: NSLocalizedString("purchase_pro_restore", comment: ""),
|
||||
style: .plain,
|
||||
target: self,
|
||||
action: #selector(restoreTapped(_:)))
|
||||
navigationItem.rightBarButtonItem = restoreButton
|
||||
|
||||
// if is presented in Simulator, add done button
|
||||
if navigationController?.viewControllers.first == self {
|
||||
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 purchased = products.filter { (product) -> Bool in
|
||||
let isPurchased = VersioneProProducts.store.isProductPurchased(product.productIdentifier)
|
||||
let isSubscription = VersioneProProducts.isSubscription(for: product.productIdentifier)
|
||||
return isPurchased && isSubscription
|
||||
}
|
||||
self.subscribedProduct = purchased.first
|
||||
self.allProducts = products.sorted(by: { $0.productIdentifier > $1.productIdentifier })
|
||||
let products = storeProducts.compactMap { EQNInAppProducts.from(product: $0) }
|
||||
|
||||
self.updateUI()
|
||||
let purchased = products
|
||||
.filter { (product) -> Bool in
|
||||
// filter for subscriptions
|
||||
let isPurchased = EQNInAppProducts.store.isProductPurchased(product.productIdentifier)
|
||||
let isSubscription = product.isSubscription
|
||||
return isPurchased && isSubscription
|
||||
}.sorted { lProduct, rProduct in
|
||||
// if user has more than one subscriptions,
|
||||
// show first the Top10k
|
||||
let lIs10k = lProduct.isTop100k
|
||||
let rIs10k = rProduct.isTop100k
|
||||
if lIs10k {
|
||||
return lIs10k
|
||||
}
|
||||
return rIs10k
|
||||
}
|
||||
self.productSubscribed = purchased.first
|
||||
self.products = products.sorted(by: { $0.productIdentifier > $1.productIdentifier })
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,18 +138,13 @@ class SubscriptionsViewController: UITableViewController {
|
||||
EQNPurchaseUtility.availableSubscriptions { (availability) in
|
||||
DispatchQueue.main.async {
|
||||
self.availability = availability
|
||||
self.updateUI()
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc func restoreTapped(_ sender: AnyObject) {
|
||||
isRestorePurchase = true
|
||||
VersioneProProducts.store.restorePurchases()
|
||||
}
|
||||
|
||||
@objc func closeTapped(_ sender: AnyObject) {
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
@@ -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,59 @@ 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)
|
||||
cell.onTapRestore = { [weak self] in
|
||||
guard let self else { return }
|
||||
|
||||
self.isRestorePurchase = true
|
||||
EQNInAppProducts.store.restorePurchases()
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ class RealtimeAlertContainerView: UIView {
|
||||
lazy var alertView: RealtimeAlertView = {
|
||||
let view = RealtimeAlertView()
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.eqn_applyRoundedCorners()
|
||||
view.clipsToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
@@ -78,10 +80,11 @@ class RealtimeAlertView: UIView {
|
||||
let waveTimeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = .preferredFont(forTextStyle: .title2)
|
||||
label.font = .preferredFont(forTextStyle: .largeTitle)
|
||||
label.textColor = AppTheme.Colors.red
|
||||
label.text = String.localizedStringWithFormat(NSLocalizedString("alert_wave", comment: ""), 0)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 2
|
||||
label.isHidden = true
|
||||
return label
|
||||
}()
|
||||
@@ -89,7 +92,7 @@ class RealtimeAlertView: UIView {
|
||||
let intensityLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.font = .preferredFont(forTextStyle: .title3)
|
||||
label.font = .preferredFont(forTextStyle: .largeTitle)
|
||||
label.textColor = AppTheme.Colors.red
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 2
|
||||
|
||||
@@ -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];
|
||||
|
||||
+71
-83
@@ -52,13 +52,12 @@ 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?
|
||||
private(set) var displayType = DisplayType.normal
|
||||
private var informationTypes = [InformationType]()
|
||||
private var isPushSelected = false
|
||||
|
||||
private var colors: MagnitudeColors?
|
||||
|
||||
@@ -67,23 +66,22 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
private lazy var containerView: UIView = {
|
||||
let view = UIView(frame: .zero)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
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
|
||||
view.backgroundColor = .white
|
||||
view.clipsToBounds = true
|
||||
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 = .scaleToFill
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
private lazy var placeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
@@ -95,8 +93,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 +110,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 +151,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 +161,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
|
||||
}()
|
||||
|
||||
@@ -183,6 +189,15 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
setupUI()
|
||||
}
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
containerView.eqn_applyShadowAndRoundedCorners()
|
||||
gradientView.eqn_applyRoundedCorners()
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
private func setupUI() {
|
||||
@@ -196,6 +211,9 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0).isActive = true
|
||||
containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4.0).isActive = 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 +248,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 +329,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 +344,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 +371,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
|
||||
@@ -364,6 +382,9 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
else {
|
||||
previousView.bottomAnchor.constraint(equalTo: containerView.layoutMarginsGuide.bottomAnchor).isActive = true
|
||||
}
|
||||
|
||||
containerView.eqn_applyShadowAndRoundedCorners()
|
||||
gradientView.eqn_applyRoundedCorners()
|
||||
}
|
||||
|
||||
private func recreateUI() {
|
||||
@@ -377,14 +398,16 @@ 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: 500, height: 1)))
|
||||
} else {
|
||||
gradientView.image = nil
|
||||
}
|
||||
|
||||
// update seismic data
|
||||
placeLabel.text = viewModel.place
|
||||
networkLabel.text = viewModel.network + " " // add some padding
|
||||
placeLabel.textColor = isPushSelected ? AppTheme.Colors.pureBlue : AppTheme.shared.cardTextColor
|
||||
networkLabel.text = String(format: NSLocalizedString("official_provider", comment: ""), viewModel.network)
|
||||
magnitudeLabel.textColor = colors?.textColor
|
||||
magnitudeLabel.text = viewModel.magnitude
|
||||
depthLabel.text = viewModel.depth
|
||||
@@ -431,11 +454,17 @@ class SeismicNetworkTableViewCell: UITableViewCell {
|
||||
/// - seismic: Seismic to display
|
||||
/// - type: Type of cell
|
||||
/// - informations: Informations to show
|
||||
public func configure(with seismic: EQNSisma, type: DisplayType, informations: [InformationType]) {
|
||||
public func configure(
|
||||
with seismic: EQNSisma,
|
||||
type: DisplayType,
|
||||
informations: [InformationType],
|
||||
isPushSelected: Bool
|
||||
) {
|
||||
self.seismic = seismic
|
||||
self.colors = calculateColors(for: seismic.magnitude.doubleValue)
|
||||
self.displayType = type
|
||||
self.informationTypes = informations
|
||||
self.isPushSelected = isPushSelected
|
||||
|
||||
if !informations.contains(.time) {
|
||||
self.informationTypes += [.time]
|
||||
@@ -499,48 +528,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
|
||||
}
|
||||
}
|
||||
|
||||
+431
-65
@@ -19,16 +19,10 @@ 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!
|
||||
weak var currentMapController: SeismicNetworksMapDetailViewController?
|
||||
|
||||
/// The ad loader
|
||||
private lazy var adLoader: GADAdLoader = {
|
||||
let adLoader = GADAdLoader(
|
||||
@@ -44,21 +38,64 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
private var informations = [SeismicNetworkTableViewCell.InformationType]()
|
||||
/// Index path of row with map expanded
|
||||
private var openMapIndexPath: IndexPath?
|
||||
/// Push notification opened by the user
|
||||
private var openedPushNotification: EQNOfficialPushNotification? {
|
||||
didSet {
|
||||
scrollToOpenedSeismic = true
|
||||
}
|
||||
}
|
||||
private var scrollToOpenedSeismic = false
|
||||
/// Current displayed controller with map
|
||||
private weak var currentMapController: SeismicNetworksMapDetailViewController?
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
@IBOutlet private weak var expandeCollapseButton: UIBarButtonItem!
|
||||
@IBOutlet private weak var sortButton: UIBarButtonItem!
|
||||
private var tableViewTopConstraint: NSLayoutConstraint?
|
||||
|
||||
private lazy var tableView: UITableView = {
|
||||
let tableView = UITableView(frame: .zero, style: .plain)
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
return tableView
|
||||
}()
|
||||
|
||||
private lazy var filterChangedView: UIView = {
|
||||
let view = UIView(frame: .zero)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.backgroundColor = AppTheme.Colors.pureBlue
|
||||
|
||||
view.addSubview(filterChangedLabel)
|
||||
filterChangedLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0).isActive = true
|
||||
filterChangedLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0).isActive = true
|
||||
filterChangedLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
|
||||
filterChangedLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var filterChangedLabel: UILabel = {
|
||||
let label = UILabel(frame: .zero)
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = .white
|
||||
label.font = .preferredFont(forTextStyle: .subheadline)
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setupUI()
|
||||
configureUI()
|
||||
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)
|
||||
}
|
||||
configureFilterView(isVisible: false)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveDownloadCompleteNotification(_:)), name: .EQNDownloadDataDidComplete, object: nil)
|
||||
}
|
||||
@@ -67,16 +104,95 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
loadData(forced: false)
|
||||
|
||||
// check for a push to manage
|
||||
if let notification = EQNOfficialPushNotification.stored() {
|
||||
manageFilter(for: notification)
|
||||
self.openedPushNotification = notification
|
||||
EQNOfficialPushNotification.removeStored()
|
||||
} else {
|
||||
configureFilterView(isVisible: false)
|
||||
self.openedPushNotification = nil
|
||||
}
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupUI() {
|
||||
view.addSubview(tableView)
|
||||
|
||||
tableViewTopConstraint = tableView.topAnchor.constraint(equalTo: view.topAnchor)
|
||||
tableViewTopConstraint?.isActive = true
|
||||
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
||||
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
||||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
||||
}
|
||||
|
||||
private func setupFilterView(isVisible: Bool) {
|
||||
if isVisible && filterChangedView.superview == nil {
|
||||
view.addSubview(filterChangedView)
|
||||
tableViewTopConstraint?.isActive = false
|
||||
filterChangedView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
||||
filterChangedView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
||||
filterChangedView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
|
||||
tableViewTopConstraint = filterChangedView.bottomAnchor.constraint(equalTo: tableView.topAnchor)
|
||||
tableViewTopConstraint?.isActive = true
|
||||
} else {
|
||||
filterChangedView.removeFromSuperview()
|
||||
tableViewTopConstraint?.isActive = false
|
||||
tableViewTopConstraint = tableView.topAnchor.constraint(equalTo: view.topAnchor)
|
||||
tableViewTopConstraint?.isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
private func configureFilterView(isVisible: Bool) {
|
||||
setupFilterView(isVisible: isVisible)
|
||||
if isVisible {
|
||||
filterChangedLabel.text = NSLocalizedString("official_filter_changed", comment: "")
|
||||
filterChangedView.backgroundColor = AppTheme.Colors.pureBlue
|
||||
} else {
|
||||
filterChangedLabel.text = nil
|
||||
filterChangedView.backgroundColor = .white
|
||||
}
|
||||
}
|
||||
|
||||
private func configureUI() {
|
||||
title = NSLocalizedString("tab_official", comment: "").capitalized
|
||||
|
||||
tableView?.estimatedRowHeight = 300.0
|
||||
tableView?.rowHeight = UITableView.automaticDimension
|
||||
tableView?.register(SeismicNetworkTableViewCell.self, forCellReuseIdentifier: SeismicNetworkTableViewCell.Identifier)
|
||||
tableView?.register(SeismicNetworkAdvertiseTableViewCell.self, forCellReuseIdentifier: SeismicNetworkAdvertiseTableViewCell.Identifier)
|
||||
tableView?.emptyDataSetSource = self
|
||||
tableView.estimatedRowHeight = 300.0
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.registerCell(for: SeismicNetworkTableViewCell.self)
|
||||
tableView.registerCell(for: SeismicNetworkAdvertiseTableViewCell.self)
|
||||
tableView.emptyDataSetSource = self
|
||||
tableView.separatorStyle = .none
|
||||
|
||||
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 !isLocationAvailable() {
|
||||
EQNSeismic.shared.filterOption = .worldWide
|
||||
EQNSeismic.shared.saveFilters()
|
||||
}
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
@@ -85,14 +201,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 +214,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
|
||||
}
|
||||
@@ -136,7 +245,12 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
expandeCollapseButton.image = UIImage(named: "navbar-icon-arrow-expand")
|
||||
}
|
||||
|
||||
tableView?.reloadData()
|
||||
tableView.reloadData()
|
||||
|
||||
if scrollToOpenedSeismic, let index = getSeismics().firstIndex(where: { isSeismicToHighlight(seismic: $0) }) {
|
||||
tableView.scrollToRow(at: IndexPath(row: index, section: 0), at: .middle, animated: true)
|
||||
scrollToOpenedSeismic = false
|
||||
}
|
||||
}
|
||||
|
||||
private func loadAd() {
|
||||
@@ -176,6 +290,276 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
|
||||
return seismics
|
||||
}
|
||||
|
||||
private func changeSort(to sort: EQNSeismic.Sort) {
|
||||
EQNSeismic.shared.sort = sort
|
||||
EQNSeismic.shared.saveFilters()
|
||||
|
||||
setupSortMenu()
|
||||
refreshUI()
|
||||
}
|
||||
|
||||
private func manageFilter(
|
||||
for notification: EQNOfficialPushNotification
|
||||
) {
|
||||
//gestisco i filtri solo se la posizione dell'utente è nota
|
||||
guard let userPosition = EQNUser.default().lastPosition else {
|
||||
return
|
||||
}
|
||||
|
||||
var filter_type = EQNSeismic.shared.filterOption
|
||||
var filter_radius = Double(EQNSeismic.shared.maximumDistance) ?? 0
|
||||
var filter_min_magnitude = Double(EQNSeismic.shared.minimumMagnitude) ?? 0
|
||||
|
||||
var filter_changed = false
|
||||
|
||||
//recupero i dati del sisma notificato
|
||||
let notification_magnitude = notification.magnitude
|
||||
let notification_latitude = notification.coordinate.coordinate.latitude
|
||||
let notification_longitude = notification.coordinate.coordinate.longitude
|
||||
|
||||
//distanza tra smartphone utente e sisma notificato
|
||||
let locationNotification = CLLocation(latitude: notification_latitude, longitude: notification_longitude)
|
||||
let distance = userPosition.distance(from: locationNotification) / 1_000
|
||||
|
||||
//verifico se il sisma è significativo in base alla definizione di significativo
|
||||
var is_significant = true
|
||||
if notification_magnitude < 7.0 && distance > 2000 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 6.5 && distance > 1600 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 6.0 && distance > 1300 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 5.5 && distance > 1000 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 5.0 && distance > 700 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 4.5 && distance > 500 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 4.0 && distance > 350 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 3.5 && distance > 200 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 3.0 && distance > 125 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 2.5 && distance > 70 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 2.0 && distance > 35 {
|
||||
is_significant = false
|
||||
} else if notification_magnitude < 1.5 && distance > 20 {
|
||||
is_significant = false
|
||||
}
|
||||
|
||||
//verifico se devo modificare il filtro scelto dall'utente
|
||||
if filter_type == .inRadius { //filter_type=0 è il filtro basato su raggio e magnitudo
|
||||
if distance > 2000 && is_significant {
|
||||
filter_type = .positionRelevant //passo al filtro che mostra i sismi significativi (perché il raggio massimo del filtro basato sul raggio è 2000)
|
||||
updateFilter(type: filter_type)
|
||||
filter_changed = true
|
||||
}
|
||||
else if distance > 2000 && notification_magnitude >= 2.0 {
|
||||
filter_type = .worldWide //passo al filtro che mostra tutti i sismi nel mondo
|
||||
updateFilter(type: filter_type)
|
||||
filter_changed = true
|
||||
}
|
||||
else {
|
||||
//verifico se devo cambiare il raggio del filtro
|
||||
if distance > filter_radius {
|
||||
if distance > 1500 {
|
||||
filter_radius = 2000
|
||||
} else if distance > 1000 {
|
||||
filter_radius = 1500
|
||||
} else if distance > 750 {
|
||||
filter_radius = 1000
|
||||
} else if distance > 500 {
|
||||
filter_radius = 750
|
||||
} else if distance > 250 {
|
||||
filter_radius = 500
|
||||
} else if distance > 100 {
|
||||
filter_radius = 250
|
||||
}
|
||||
updateFilter(radius: filter_radius)
|
||||
|
||||
filter_changed = true
|
||||
}
|
||||
//verifico se devo cambiare la mgnitudo del filtro
|
||||
if notification_magnitude < filter_min_magnitude {
|
||||
if notification_magnitude < 1.0 {
|
||||
filter_min_magnitude = 0.0
|
||||
} else if notification_magnitude < 2.0 {
|
||||
filter_min_magnitude = 1.0
|
||||
} else if notification_magnitude < 3.0 {
|
||||
filter_min_magnitude = 2.0
|
||||
} else if notification_magnitude < 4.0 {
|
||||
filter_min_magnitude = 3.0
|
||||
} else if notification_magnitude < 5.0 {
|
||||
filter_min_magnitude = 4.0
|
||||
} else if notification_magnitude < 6.0 {
|
||||
filter_min_magnitude = 5.0
|
||||
}
|
||||
|
||||
filter_changed = true
|
||||
updateFilter(magnitude: filter_min_magnitude)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if filter_type == .positionRelevant && !is_significant && distance <= 2000 {
|
||||
filter_type = .inRadius //passo a filtro basato su raggio e magnitudo
|
||||
updateFilter(type: filter_type)
|
||||
|
||||
if distance > filter_radius {
|
||||
if distance>1500 {
|
||||
filter_radius = 2000
|
||||
}
|
||||
else if distance > 1000 {
|
||||
filter_radius = 1500
|
||||
}
|
||||
else if distance > 750 {
|
||||
filter_radius = 1000
|
||||
}
|
||||
else if distance > 500 {
|
||||
filter_radius = 750
|
||||
}
|
||||
else if distance > 250 {
|
||||
filter_radius = 500
|
||||
}
|
||||
else if distance > 100 {
|
||||
filter_radius = 250
|
||||
}
|
||||
updateFilter(radius: filter_radius)
|
||||
}
|
||||
if notification_magnitude < filter_min_magnitude {
|
||||
if notification_magnitude < 1.0 {
|
||||
filter_min_magnitude = 0.0
|
||||
}
|
||||
else if notification_magnitude < 2.0 {
|
||||
filter_min_magnitude = 1.0
|
||||
}
|
||||
else if notification_magnitude < 3.0 {
|
||||
filter_min_magnitude = 2.0
|
||||
}
|
||||
else if notification_magnitude < 4.0 {
|
||||
filter_min_magnitude = 3.0
|
||||
}
|
||||
else if notification_magnitude < 5.0 {
|
||||
filter_min_magnitude = 4.0
|
||||
}
|
||||
else if notification_magnitude < 6.0 {
|
||||
filter_min_magnitude = 5.0
|
||||
}
|
||||
updateFilter(magnitude: filter_min_magnitude)
|
||||
}
|
||||
|
||||
filter_changed = true
|
||||
}
|
||||
|
||||
if filter_type == .positionRelevant && !is_significant && distance > 2000 && notification_magnitude >= 2.0 {
|
||||
filter_type = .worldWide //passo a filtro che mostra tutti i sismi nel mondo
|
||||
updateFilter(type: filter_type)
|
||||
filter_changed = true
|
||||
}
|
||||
|
||||
if filter_type == .worldWide && notification_magnitude < 2.0 && is_significant {
|
||||
filter_type = .positionRelevant //passo a filtro sismi significativi
|
||||
updateFilter(type: filter_type)
|
||||
filter_changed = true
|
||||
}
|
||||
|
||||
if filter_type == .worldWide && notification_magnitude < 2.0 && distance <= 2000 && !is_significant {
|
||||
filter_type = .inRadius
|
||||
updateFilter(type: filter_type)
|
||||
|
||||
if distance > filter_radius {
|
||||
if distance > 1500 {
|
||||
filter_radius = 2000
|
||||
}
|
||||
else if distance > 1000 {
|
||||
filter_radius = 1500
|
||||
}
|
||||
else if distance > 750 {
|
||||
filter_radius = 1000
|
||||
}
|
||||
else if distance > 500 {
|
||||
filter_radius = 750
|
||||
}
|
||||
else if distance > 250 {
|
||||
filter_radius = 500
|
||||
}
|
||||
else if distance > 100 {
|
||||
filter_radius = 250
|
||||
}
|
||||
updateFilter(radius: filter_radius)
|
||||
}
|
||||
if notification_magnitude < filter_min_magnitude {
|
||||
if notification_magnitude < 1.0 {
|
||||
filter_min_magnitude = 0.0
|
||||
}
|
||||
else if notification_magnitude < 2.0 {
|
||||
filter_min_magnitude = 1.0
|
||||
}
|
||||
else if notification_magnitude < 3.0 {
|
||||
filter_min_magnitude = 2.0
|
||||
}
|
||||
else if notification_magnitude < 4.0 {
|
||||
filter_min_magnitude = 3.0
|
||||
}
|
||||
else if notification_magnitude < 5.0 {
|
||||
filter_min_magnitude = 4.0
|
||||
}
|
||||
else if notification_magnitude < 6.0 {
|
||||
filter_min_magnitude = 5.0
|
||||
}
|
||||
updateFilter(magnitude: filter_min_magnitude)
|
||||
}
|
||||
|
||||
filter_changed = true
|
||||
}
|
||||
|
||||
//mostro all'utente un messaggio per avvisarlo che i filtri sono stati modificati
|
||||
configureFilterView(isVisible: filter_changed)
|
||||
if filter_changed {
|
||||
loadData(forced: true)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateFilter(
|
||||
type: EQNSeismic.FilterType? = nil,
|
||||
radius: Double? = nil,
|
||||
magnitude: Double? = nil
|
||||
) {
|
||||
if let type {
|
||||
EQNSeismic.shared.filterOption = type
|
||||
}
|
||||
if let radius {
|
||||
EQNSeismic.shared.maximumDistance = String(format: "%.0f", radius)
|
||||
}
|
||||
if let magnitude {
|
||||
EQNSeismic.shared.minimumMagnitude = String(format: "%.1f", magnitude)
|
||||
}
|
||||
EQNSeismic.shared.saveFilters()
|
||||
}
|
||||
|
||||
private func isLocationAvailable() -> Bool {
|
||||
EQNUser.default().lastPosition != nil
|
||||
}
|
||||
|
||||
private func isSeismicToHighlight(seismic: EQNSisma) -> Bool {
|
||||
guard let notification = openedPushNotification else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard let seismicDate = seismic.date, let notificationDate = notification.date else { return false }
|
||||
|
||||
let deltaTime = abs(seismicDate.timeIntervalSince(notificationDate))
|
||||
let magnitudeRatio = seismic.magnitude.doubleValue / notification.magnitude
|
||||
let latitudeDiff = abs(seismic.coordinate.coordinate.latitude - notification.coordinate.coordinate.latitude)
|
||||
let longitudeDiff = abs(seismic.coordinate.coordinate.longitude - notification.coordinate.coordinate.longitude)
|
||||
if deltaTime <= 120 && magnitudeRatio > 0.8 && magnitudeRatio < 1.2 && latitudeDiff < 1 && longitudeDiff < 1 { // secondi?
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func refreshDataTapped(_ sender: Any) {
|
||||
@@ -185,11 +569,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,18 +591,19 @@ 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 {
|
||||
type = .mapExpanded
|
||||
}
|
||||
|
||||
cell.configure(with: seismic, type: type, informations: informations)
|
||||
|
||||
let isPushSelected = isSeismicToHighlight(seismic: seismic)
|
||||
cell.configure(with: seismic, type: type, informations: informations, isPushSelected: isPushSelected)
|
||||
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
|
||||
}
|
||||
@@ -298,7 +679,7 @@ extension SeismicNetworksViewController: GADNativeAdLoaderDelegate {
|
||||
|
||||
let adPosition = min(3, rows.count)
|
||||
rows.insert(.advertise(nativeAd), at: adPosition)
|
||||
tableView?.reloadData()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
|
||||
@@ -310,7 +691,7 @@ extension SeismicNetworksViewController: GADNativeAdLoaderDelegate {
|
||||
extension SeismicNetworksViewController: SeismicNetworkTableViewCellDelegate {
|
||||
|
||||
func seismicNetworkCellDidTapShare(_ cell: SeismicNetworkTableViewCell) {
|
||||
guard let index = tableView?.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
|
||||
guard let index = tableView.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
|
||||
|
||||
// create a snapshot of the cell and share with default share sheet
|
||||
let snapshot = cell.contentView.createSnapshot()
|
||||
@@ -327,22 +708,22 @@ extension SeismicNetworksViewController: SeismicNetworkTableViewCellDelegate {
|
||||
}
|
||||
|
||||
func seismicNetworkCellDidTapMap(_ cell: SeismicNetworkTableViewCell) {
|
||||
guard let index = tableView?.indexPath(for: cell) else { return }
|
||||
guard let index = tableView.indexPath(for: cell) else { return }
|
||||
|
||||
let indexToReloads = [openMapIndexPath, index].compactMap { $0 }
|
||||
|
||||
openMapIndexPath = index
|
||||
tableView?.reloadRows(at: indexToReloads, with: .automatic)
|
||||
tableView.reloadRows(at: indexToReloads, with: .automatic)
|
||||
}
|
||||
|
||||
func seismicNetworkCellDidTapMapDetail(_ cell: SeismicNetworkTableViewCell) {
|
||||
guard let index = tableView?.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
|
||||
guard let index = tableView.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
|
||||
|
||||
showMapDetail(for: seismic)
|
||||
}
|
||||
|
||||
func seismicNetworkCellDidTapCalendar(_ cell: SeismicNetworkTableViewCell) {
|
||||
guard let index = tableView?.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
|
||||
guard let index = tableView.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
|
||||
|
||||
openCalendar(for: seismic)
|
||||
}
|
||||
@@ -352,12 +733,12 @@ extension SeismicNetworksViewController: SeismicNetworkTableViewCellDelegate {
|
||||
}
|
||||
|
||||
func seismicNetworkCellDidTapClose(_ cell: SeismicNetworkTableViewCell) {
|
||||
guard let index = tableView?.indexPath(for: cell) else { return }
|
||||
guard let index = tableView.indexPath(for: cell) else { return }
|
||||
|
||||
let indexToReloads = [openMapIndexPath, index].compactMap { $0 }
|
||||
|
||||
openMapIndexPath = nil
|
||||
tableView?.reloadRows(at: indexToReloads, with: .automatic)
|
||||
tableView.reloadRows(at: indexToReloads, with: .automatic)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,24 +756,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 +763,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
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// 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) {
|
||||
if enabled {
|
||||
askForCriticalAlertsPermission()
|
||||
}
|
||||
|
||||
isCriticalAlertsEnabled = enabled
|
||||
EQNSettingRealTimeAlert.shared.isCriticalAlertsEnabled = isCriticalAlertsEnabled
|
||||
EQNSettingRealTimeAlert.shared.saveUserInfo()
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
private func askForCriticalAlertsPermission() {
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: [ .criticalAlert ]) { granted, error in
|
||||
// nope
|
||||
}
|
||||
}
|
||||
}
|
||||
-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
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// 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 magnitudoMinima
|
||||
case distanzaMassima
|
||||
}
|
||||
|
||||
private var isNotificationEnabled = false
|
||||
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: .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
|
||||
|
||||
// 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 .slider:
|
||||
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingSliderTableViewCell.self, for: indexPath)
|
||||
cell.titleLabel.text = setting.displayTitle
|
||||
|
||||
let filtersEnabled = isNotificationEnabled
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
@@ -55,9 +55,9 @@
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>L'accesso al calendario è richiesto per poter salvare le informazioni dei sismi di interesse</string>
|
||||
<string>L'accesso al calendario è richiesto per poter salvare le informazioni dei sismi di interesse</string>
|
||||
<key>NSContactsUsageDescription</key>
|
||||
<string>L'accesso ai contatti è richiesto per poter aggiungere persone agli eventi creati</string>
|
||||
<string>L'accesso ai contatti è richiesto per poter aggiungere persone agli eventi creati</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string> Ci occorre la tua posizione per inviare messaggi precisi in caso di terremoto</string>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
@@ -65,9 +65,9 @@
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string> Ci occorre la tua posizione per inviare messaggi precisi in caso di terremoto</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>L'accesso alla libreria è richiesto per poter salvare le immagini generate dall'app</string>
|
||||
<string>L'accesso alla libreria è richiesto per poter salvare le immagini generate dall'app</string>
|
||||
<key>NSUserTrackingUsageDescription</key>
|
||||
<string>Il tracciamento serve a capire se la pubblicità dell'app è efficace</string>
|
||||
<string>Il tracciamento serve a capire se la pubblicità dell'app è efficace</string>
|
||||
<key>SKAdNetworkItems</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -104,5 +104,7 @@
|
||||
</array>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Light</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -26,3 +26,14 @@ extension NSDate {
|
||||
return (self as Date).isBeforeInterval(interval)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension CGFloat {
|
||||
var negative: CGFloat {
|
||||
-self
|
||||
}
|
||||
|
||||
var x2: CGFloat {
|
||||
self*2.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ import UIKit
|
||||
extension UIView {
|
||||
|
||||
func eqn_applyShadowAndRoundedCorners() {
|
||||
// rounded corners
|
||||
layer.cornerRadius = AppTheme.shared.cardCornerRadius
|
||||
layer.masksToBounds = false
|
||||
eqn_applyRoundedCorners()
|
||||
|
||||
// apply a shadow to the current view
|
||||
layer.shadowColor = UIColor.black.cgColor
|
||||
@@ -22,4 +20,10 @@ extension UIView {
|
||||
layer.shadowOffset = CGSize(width: 0, height: 2)
|
||||
layer.shadowRadius = 2
|
||||
}
|
||||
|
||||
func eqn_applyRoundedCorners() {
|
||||
// rounded corners
|
||||
layer.cornerRadius = AppTheme.shared.cardCornerRadius
|
||||
layer.masksToBounds = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public class EQNAppearanceCommand: EQNCommandProtocol {
|
||||
// MARK: - Public
|
||||
|
||||
func execute() {
|
||||
print("EQNAppearanceCommand: start execute")
|
||||
print("[EQNAppearanceCommand] Start execute")
|
||||
|
||||
applyAppearance()
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public class EQNAppearanceCommand: EQNCommandProtocol {
|
||||
navAppearance.largeTitleTextAttributes = [
|
||||
NSAttributedString.Key.foregroundColor: AppTheme.Colors.darkGray
|
||||
]
|
||||
navAppearance.backgroundColor = AppTheme.Colors.primary
|
||||
navAppearance.backgroundColor = AppTheme.Colors.navBar
|
||||
navAppearance.shadowColor = UIColor.clear
|
||||
|
||||
proxyNavBar.isTranslucent = false
|
||||
|
||||
@@ -15,13 +15,13 @@ public class EQNUserDefaultsCommand: EQNCommandProtocol {
|
||||
// MARK: - Public
|
||||
|
||||
func execute() {
|
||||
print("EQNUserDefaultsCommand: start execute")
|
||||
print("[EQNUserDefaultsCommand] Start execute")
|
||||
|
||||
applyDefaultSettings()
|
||||
saveMissingValues()
|
||||
|
||||
migrationV5_3()
|
||||
migrationV5_4()
|
||||
migrationV5_8()
|
||||
migrationFirstAppStat()
|
||||
migrationCriticalAlerts()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -35,47 +35,76 @@ public class EQNUserDefaultsCommand: EQNCommandProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private func saveMissingValues() {
|
||||
// `raggio sismi forti` was not saved before v2.3
|
||||
if UserDefaults.standard.object(forKey: UserDefaults.AllertaSismicaRaggioSismiForti) == nil {
|
||||
UserDefaults.standard.set("600", forKey: UserDefaults.AllertaSismicaRaggioSismiForti)
|
||||
}
|
||||
}
|
||||
|
||||
private func migrationV5_3() {
|
||||
let migrationPerformed = UserDefaults.standard.bool(forKey: UserDefaults.AppMigrationV5_3)
|
||||
private func migrationV5_8() {
|
||||
let migrationPerformed = UserDefaults.standard.bool(forKey: UserDefaults.AppMigrationV5_8)
|
||||
if migrationPerformed {
|
||||
print("[EQNUserDefaultsCommand] Migration v5.3 already performed")
|
||||
print("[EQNUserDefaultsCommand] Migration v5.8 already performed")
|
||||
return
|
||||
}
|
||||
|
||||
// l'ultima posizione era salvata come array, la trasformiamo in valore singolo
|
||||
let lastLocations = EQNUtility.loadArray(of: CLLocation.self, fromUserDefaultsForKey: UserDefaults.UserDataLastLocation) as? [CLLocation]
|
||||
if let lastLocation = lastLocations?.last {
|
||||
UserDefaults.standard.removeObject(forKey: UserDefaults.UserDataLastLocation)
|
||||
EQNUserData.shared.saveLastLocation(lastLocation)
|
||||
}
|
||||
|
||||
// resettiamo il Firebase token in modo da ri-eseguire la procedura di registrazione corretta
|
||||
EQNUserData.shared.saveFirebaseToken(nil)
|
||||
|
||||
UserDefaults.standard.set(true, forKey: UserDefaults.AppMigrationV5_3)
|
||||
}
|
||||
|
||||
private func migrationV5_4() {
|
||||
let migrationPerformed = UserDefaults.standard.bool(forKey: UserDefaults.AppMigrationV5_4)
|
||||
if migrationPerformed {
|
||||
print("[EQNUserDefaultsCommand] Migration v5.4 already performed")
|
||||
return
|
||||
}
|
||||
|
||||
// migriamo l'ultima posizione negli user defaults condivisi
|
||||
|
||||
// delete old notification settings
|
||||
let userDefaults = UserDefaults.standard
|
||||
let groupUserDefaults = UserDefaults.appGroup
|
||||
if let encodedLocation = userDefaults.object(forKey: UserDefaults.UserDataLastLocation) as? Data {
|
||||
groupUserDefaults?.set(encodedLocation, forKey: UserDefaults.UserDataLastLocation)
|
||||
[
|
||||
"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)
|
||||
}
|
||||
|
||||
userDefaults.set(true, forKey: UserDefaults.AppMigrationV5_4)
|
||||
// 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)
|
||||
}
|
||||
|
||||
private func migrationFirstAppStat() {
|
||||
// before v5.8.2, first app start was defined using Firebase Token
|
||||
let userDefaults = UserDefaults.standard
|
||||
let firstAppStartExecuted = userDefaults.bool(forKey: UserDefaults.FirstAppStartExecuted)
|
||||
if firstAppStartExecuted {
|
||||
print("[EQNUserDefaultsCommand] First app start already executed")
|
||||
return
|
||||
}
|
||||
|
||||
let firebaseToken = userDefaults.object(forKey: UserDefaults.UserDataFirebaseToken) as? String
|
||||
if firebaseToken != nil {
|
||||
print("[EQNUserDefaultsCommand] First app start migrated")
|
||||
userDefaults.set(true, forKey: UserDefaults.FirstAppStartExecuted)
|
||||
}
|
||||
}
|
||||
|
||||
private func migrationCriticalAlerts() {
|
||||
let userDefaults = UserDefaults.standard
|
||||
let migrationPerformed = userDefaults.bool(forKey: UserDefaults.AppMigrationV5_8_2)
|
||||
if migrationPerformed {
|
||||
print("[EQNUserDefaultsCommand] Migration v5.8.2 already performed")
|
||||
return
|
||||
}
|
||||
|
||||
UNUserNotificationCenter.current().getNotificationSettings { settings in
|
||||
if settings.criticalAlertSetting != .enabled {
|
||||
print("[EQNUserDefaultsCommand] Critical alerts not enabled, disable settings")
|
||||
EQNSettingRealTimeAlert.shared.isCriticalAlertsEnabled = false
|
||||
EQNSettingRealTimeAlert.shared.saveUserInfo()
|
||||
} else {
|
||||
print("[EQNUserDefaultsCommand] Critical alerts enabled, do nothing")
|
||||
}
|
||||
}
|
||||
|
||||
userDefaults.set(true, forKey: UserDefaults.AppMigrationV5_8_2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
//
|
||||
// EQNOfficialPushNotification.swift
|
||||
// Earthquake Network
|
||||
//
|
||||
// Created by Andrea Busi on 29/06/24.
|
||||
// Copyright © 2024 Earthquake Network. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Shogun
|
||||
|
||||
|
||||
@objc
|
||||
class EQNOfficialPushNotification: NSObject, Codable {
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case latitude
|
||||
case longitude
|
||||
case magnitude
|
||||
case date
|
||||
}
|
||||
|
||||
private let latitude: Double
|
||||
private let longitude: Double
|
||||
let magnitude: Double
|
||||
let date: Date?
|
||||
|
||||
var coordinate: CLLocation {
|
||||
.init(latitude: latitude, longitude: longitude)
|
||||
}
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
init(
|
||||
latitude: Double,
|
||||
longitude: Double,
|
||||
magnitude: Double,
|
||||
date: Date?
|
||||
) {
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
self.magnitude = magnitude
|
||||
self.date = date
|
||||
}
|
||||
|
||||
// MARK: - Class
|
||||
|
||||
/// Remove any saved notification
|
||||
static func removeStored() {
|
||||
UserDefaults.standard.removeObject(forKey: UserDefaults.OfficialAlertPayload)
|
||||
}
|
||||
|
||||
/// Retrieve stored notification (if any)
|
||||
static func stored() -> EQNOfficialPushNotification? {
|
||||
guard let data = UserDefaults.standard.object(forKey: UserDefaults.OfficialAlertPayload) as? Data else {
|
||||
print("[EQNOfficialPushNotification] No notification saved for key '\(UserDefaults.OfficialAlertPayload)'")
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let notification = try? JSONDecoder().decode(EQNOfficialPushNotification.self, from: data) else {
|
||||
print("[EQNOfficialPushNotification] Unable to decode given notification")
|
||||
return nil
|
||||
}
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
/// Convert and store a push notification payload.
|
||||
/// Expected payload has the following structure:
|
||||
/// ```
|
||||
/// {
|
||||
/// "title": "Segnalazione da rete sismica",
|
||||
/// "body": "Sisma rilevato a 4km S Valfabbrica (PG)",
|
||||
/// "userInfo": {
|
||||
/// "data" : "2024-06-29 11:21:30",
|
||||
/// ...
|
||||
/// "aps": {
|
||||
/// "alert" : {
|
||||
/// "loc-key" : "Sisma rilevato a",
|
||||
/// "title-loc-key" : "Segnalazione da rete sismica",
|
||||
/// "title" : "Segnalazione da rete sismica",
|
||||
/// "action-loc-key" : "",
|
||||
/// "loc-args" : [
|
||||
/// "6 km S Acate (RG) - M1.9"
|
||||
/// ]
|
||||
/// },
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// - Parameter payload: Notification payload
|
||||
/// - Returns: `true` if save succeed, `false` otherwise
|
||||
@objc(storeNotificationWithPayload:)
|
||||
@discardableResult
|
||||
static func store(payload: [String: Any]) -> Bool {
|
||||
guard let notification = from(payload: payload) else {
|
||||
print("[EQNOfficialPushNotification] Unable to convert received notification")
|
||||
return false
|
||||
}
|
||||
|
||||
guard let data = try? JSONEncoder().encode(notification) else {
|
||||
print("[EQNOfficialPushNotification] Unable to encode given notification")
|
||||
return false
|
||||
}
|
||||
|
||||
UserDefaults.standard.set(data, forKey: UserDefaults.OfficialAlertPayload)
|
||||
return true
|
||||
}
|
||||
|
||||
@objc
|
||||
private static func from(payload: [String: Any]) -> EQNOfficialPushNotification? {
|
||||
guard let userInfo = payload["userInfo"] as? [String: Any] else {
|
||||
print("[EQNOfficialPushNotification] Missing required info to parse push notification")
|
||||
return nil
|
||||
}
|
||||
|
||||
let latitude = userInfo.double(forKey: "latitude") ?? 0
|
||||
let longitude = userInfo.double(forKey: "longitude") ?? 0
|
||||
let magnitude = userInfo.double(forKey: "magnitude") ?? 0
|
||||
let dateString = userInfo.string(forKey: "data") ?? ""
|
||||
let date = EQNUtility.getDateFrom(dateString)
|
||||
|
||||
return .init(
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
magnitude: magnitude,
|
||||
date: date
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
self.registrationInProgress = NO;
|
||||
self.user_ID = EQNUserData.sharedData.userId;
|
||||
self.lastPosition = EQNUserData.sharedData.lastLocation;
|
||||
self.currentFirebaseToken = EQNUserData.sharedData.firebaseToken;
|
||||
|
||||
[self registerForLocationUpdates];
|
||||
}
|
||||
@@ -122,6 +123,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) {
|
||||
|
||||
@@ -19,7 +19,8 @@ import CoreLocation
|
||||
|
||||
@objc
|
||||
var isFirstStart: Bool {
|
||||
firebaseToken == nil
|
||||
let firstAppStartExecuted = UserDefaults.standard.bool(forKey: UserDefaults.FirstAppStartExecuted)
|
||||
return !firstAppStartExecuted
|
||||
}
|
||||
|
||||
// MARK: - Firebase Token
|
||||
|
||||
@@ -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,79 @@
|
||||
//
|
||||
// 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 {
|
||||
|
||||
@objc(sharedInstance)
|
||||
static let shared = EQNSettingSeismicNetworkNotification()
|
||||
|
||||
@objc var isAbilitato: Bool
|
||||
@objc var magnitudoMinima: String
|
||||
@objc var distanzaMassima: String
|
||||
|
||||
private static let DefaultMagnitudoMinima = EQNData.DefaultFilterMagnitude.value
|
||||
private static let DefaultDistanzaMassima = EQNData.DefaultFilterRadius.value
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@objc class func saveDefaultValues() {
|
||||
shared.isAbilitato = true
|
||||
shared.magnitudoMinima = DefaultMagnitudoMinima
|
||||
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.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)
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -5,9 +5,9 @@
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "130",
|
||||
"green" : "212",
|
||||
"red" : "148"
|
||||
"blue" : "196",
|
||||
"green" : "226",
|
||||
"red" : "200"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "167",
|
||||
"green" : "231",
|
||||
"red" : "255"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -5,9 +5,9 @@
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.318",
|
||||
"green" : "0.565",
|
||||
"red" : "0.000"
|
||||
"blue" : "35",
|
||||
"green" : "160",
|
||||
"red" : "12"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
||||
+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];
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
case EQNTipoChiamataCalibrazione:
|
||||
case EQNTipoChiamataImpostazioniNotifiche:
|
||||
case EQNTipoChiamataAlertSimulator:
|
||||
case EQNTipoChiamataAlertPushTest:
|
||||
case EQNTipoChiamataRegisterSubscription:
|
||||
onSuccess(newStr);
|
||||
default:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user