Compare commits

..

48 Commits

Author SHA1 Message Date
Andrea Busi 73caf9647c release: Increase version for release 2022-06-22 16:16:24 +02:00
Andrea Busi 8700e200f9 chore: Update push payloads 2022-06-22 16:15:50 +02:00
Andrea Busi e99845ff1b fix: Add missing check for null alert 2022-06-22 09:27:47 +02:00
Andrea Busi a0161e8f4c release: Increase version for release 2022-06-17 14:42:47 +02:00
Andrea Busi 1b9944a7ca fix: Solve retain cycle and crashes 2022-06-17 14:42:47 +02:00
Andrea Busi 4c00e4ef6a refactor: Review time to show full screen view or card only 2022-06-17 14:42:47 +02:00
Andrea Busi 63592e6cfb refactor: Create a model for the realtime alert 2022-06-17 14:42:47 +02:00
Andrea Busi 2877dff23c refactor: Increase card interspace 2022-06-17 10:09:04 +02:00
Andrea Busi f2386a1abb refactor: Don't show countdown in expanded card 2022-06-17 10:09:04 +02:00
Andrea Busi 5e4a500f03 dependency: Update Pods 2022-06-17 10:09:04 +02:00
Andrea Busi 2b8f2db7c5 feat: Add new realtime alert screen 2022-06-17 10:09:04 +02:00
Andrea Busi 11d994696d release: Increase version for release 2022-06-09 22:20:56 +02:00
Andrea Busi cd6e20c1b2 fix: Solve issue with EMSC networks 2022-06-09 22:20:48 +02:00
Andrea Busi af5371571c release: Increase version for release 2022-06-03 17:44:54 +02:00
Andrea Busi 6291b22df0 fix: Add a delay before calling the completion, to let iOS remove already posted notification 2022-06-03 17:44:32 +02:00
Andrea Busi 2a7cfd3079 release: Increase version for release 2022-06-01 18:10:01 +02:00
Andrea Busi cae5fee992 feat: Remove same type posted notifications
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/48
2022-05-30 16:02:46 +02:00
Andrea Busi 53b8c0fab4 release: Increase version for release 2022-05-29 22:16:19 +02:00
Andrea Busi 8751d3c8f2 fix: Solve crazy behaviour with iOS 15 2022-05-29 22:14:06 +02:00
Andrea Busi 2d333f993b feat: Make slider with step values 2022-05-29 22:13:46 +02:00
Andrea Busi 22d421f1cc refactor: Add debug log 2022-05-26 21:51:30 +02:00
Andrea Busi cec8b39fc7 fix: Be sure to update push token in Firebase 2022-05-26 21:51:08 +02:00
Andrea Busi 5ceaa4a8be fix: Save user position after server registration 2022-05-26 18:06:37 +02:00
Andrea Busi 94bdb9dbe1 fix: Don't try to parse nil data 2022-05-26 18:06:27 +02:00
Andrea Busi ee1b762032 fix: Call callback for position endpoint 2022-05-26 18:06:13 +02:00
Andrea Busi 5a6c5a5cfc release: Increase version for release 2022-05-22 21:31:58 +02:00
Andrea Busi d55b2ec98f fix: Solve wrong value save in settings 2022-05-22 21:31:50 +02:00
Andrea Busi 761ebc1d17 release: Increase version for release 2022-05-22 11:54:06 +02:00
Andrea Busi dd5e8862ed fix: Don't reload entire table view in settings, to avoid strange behaviour with iOS 15 2022-05-22 11:53:23 +02:00
Andrea Busi ceca3ed50d fix: Remove wrong translatesAutoresizingMaskIntoConstraints for cell views 2022-05-22 11:28:07 +02:00
Andrea Busi 6cce448acf release: Increase version for release 2022-05-20 18:37:45 +02:00
Andrea Busi 5ddb8da902 chore: Add project icon for SourceTree 2022-05-20 18:36:31 +02:00
Andrea Busi 644002a792 fix: Solve layout issue in seismic card 2022-05-20 18:35:26 +02:00
Andrea Busi e902969c9a release: Increase version for release 2022-05-19 11:26:56 +02:00
Andrea Busi 57c2ca5ae9 refactor: Disable ads
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/46
2022-05-19 11:26:50 +02:00
Andrea Busi 107d4c7600 fix: Remove broken reference 2022-05-19 11:26:33 +02:00
Andrea Busi 6a41f4558a dependency: Update Pods
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/45
2022-05-19 11:26:33 +02:00
Andrea Busi 995a6011d5 chore: Update certificates and profiles 2022-05-19 11:26:33 +02:00
Andrea Busi fcb3ab5be1 release: Update changelog 2022-05-19 11:26:33 +02:00
Andrea Busi f8c7edf588 refactor: Hide pro version section in home
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/43
2022-05-19 11:26:28 +02:00
Andrea Busi 4bb77e2921 refactor: Use new icon
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/43
2022-05-19 11:26:22 +02:00
Andrea Busi d399e0b37b refactor: Replace deprecated 'class' in protocol definition
Also remove not needed @objc declaration

Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/44
2022-05-19 11:25:22 +02:00
Andrea Busi a85fbe56be release: Increase version for release 2021-04-23 14:02:20 +02:00
Andrea Busi cf97c3cb61 fix: Properly handle new subscriptions also in detail page 2021-04-23 14:02:20 +02:00
Andrea Busi 7611e3eb15 feat: Add button to show/hide some cards in alerts section
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/42
2021-04-23 14:02:20 +02:00
Andrea Busi 4369284fb7 refactor: Align UI style in subscriptions and pro version page 2021-04-23 14:02:20 +02:00
Andrea Busi 0e4fadd666 feat: Handle new lifetime subscriptions
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/41
2021-04-23 14:02:20 +02:00
Andrea Busi 6622256339 refactor: Improve code in VersioneProProducts class 2021-04-23 10:33:22 +02:00
86 changed files with 1335 additions and 621 deletions
+50
View File
@@ -1,5 +1,55 @@
# Changelog
## Versione 5.2
- Nuova schermata per allerta in tempo reale
## Versione 5.1
### Build (91)
- Corretto problema con selezioni reti EMSC
### Build (90)
- Rimozione notifiche dello stesso tipo
## Versione 5.0.3
### Build (89)
- Corretto problema con ultima posizione non salvata in app
- Forzato aggiornamento Firebase
- Corretti metodi deprecati in salvataggio dati
- Corretti comportamento filtri con iOS 15
- Slider con valori a step
## Versione 5.0.2
### Build (88)
- Corretto errato salvataggio raggio sismi forti in allerte tempo reale
## Versione 5.0.1
### Build (87)
- Corretto problema con slider in impostazioni
## Versione 5.0
### Build (86)
- Corretto problema layout in schede sismi
### Build (85)
- Nuova icona
- Nascosta sezione 'pro'
- Aggiornamento ad Xcode 13
- Disabilitati ads
## Versione 4.2
### Build (84)
- Corretti errori in nuovi sviluppi
### Build (83)
- Aggiunto supporto per abbonamenti a vita
- Allineata UI in sezione abbonamenti e versione pro
## Versione 4.1.1
### Build (82)
- Corretti placeholder in stringhe
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-15 21:34:50",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "37.983810",
"detection_longitude": "23.727539",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "37.683810",
"latitude": "38.19",
"location": "150 km (Test)",
"longitude": "23.327539",
"longitude": "22.26",
"peak": "-1",
"randcode": 0,
"test": 1,
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-16 12:41:20",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "37.3229978",
"detection_longitude": "-122.0321823",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "37.9229978",
"latitude": "35.15",
"location": "150 km (Test)",
"longitude": "-121.0321823",
"longitude": "-117.78",
"peak": "-1",
"randcode": 0,
"test": 1,
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-15 20:39:00",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "-34.603722",
"detection_longitude": "-58.381592",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "-34.103722",
"latitude": "-32.57",
"location": "150 km (Test)",
"longitude": "-58.781592",
"longitude": "-71.46",
"peak": "-1",
"randcode": 0,
"test": 1,
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-15 21:37:40",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "48.856614",
"detection_longitude": "2.8522219",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "48.456614",
"latitude": "49.77",
"location": "150 km (Test)",
"longitude": "2.3522219",
"longitude": "1.05",
"peak": "-1",
"randcode": 0,
"test": 1,
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-15 21:39:50",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "45.813177",
"detection_longitude": "15.977048",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "45.413177",
"latitude": "45.09",
"location": "150 km (Test)",
"longitude": "15.677048",
"longitude": "14.87",
"peak": "-1",
"randcode": 0,
"test": 1,
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-15 21:42:40",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "-2.548926",
"detection_longitude": "118.0148634",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "-2.948926",
"latitude": "-7.38",
"location": "150 km (Test)",
"longitude": "118.6148634",
"longitude": "106.83",
"peak": "-1",
"randcode": 0,
"test": 1,
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-15 20:32:20",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "45.64664",
"detection_longitude": "9.188540",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "45.164664",
"latitude": "42.958",
"location": "150 km (Test)",
"longitude": "9.788540",
"longitude": "12.702",
"peak": "-1",
"randcode": 0,
"test": 1,
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-16 12:39:40",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "19.432608",
"detection_longitude": "-99.133209",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "19.932608",
"latitude": "18.72",
"location": "150 km (Test)",
"longitude": "-98.033209",
"longitude": "-97.90",
"peak": "-1",
"randcode": 0,
"test": 1,
+3 -3
View File
@@ -14,16 +14,16 @@
"sound": "alert_star_trek.wav"
},
"counter": 10,
"datetime": "2021-04-15 21:44:30",
"datetime": "2022-06-22 16:15:00",
"detection_latitude": "41.008238",
"detection_longitude": "28.978359",
"gcm.message_id": "1614708857742608",
"google.c.a.e": 1,
"google.c.sender.id": "899482329945",
"intensity": 2,
"latitude": "41.608238",
"latitude": "40.33",
"location": "150 km (Test)",
"longitude": "28.678359",
"longitude": "27.66",
"peak": "-1",
"randcode": 0,
"test": 1,
@@ -2,3 +2,4 @@
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "NotificationService.h"
@@ -0,0 +1,47 @@
//
// NotificationService+Extension.swift
// EQNNotificationService
//
// Created by Andrea Busi on 28/05/22.
// Copyright © 2022 Earthquake Network. All rights reserved.
//
import Foundation
import UserNotifications
extension NotificationService {
@objc(removeNotificationsForType:completion:)
func removeNotifications(
for type: String?,
completion: @escaping() -> Void
) {
guard let type = type else {
completion()
return
}
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.getDeliveredNotifications { notifications in
let sameTypeNotifications = notifications.filter { notification in
let payload = notification.request.content.userInfo
if let notificationType = payload["type"] as? String {
return notificationType == type
}
return false
}
let identifiers = sameTypeNotifications.map { $0.request.identifier }
notificationCenter.removeDeliveredNotifications(withIdentifiers: identifiers)
// !! Note: this is a known issue/bug
// we need to add a delay before invoking the completion, otherwise the notification will not be remved
// ref: https://stackoverflow.com/questions/53697279/why-are-notifications-not-removed-with-removedeliverednotifications
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
completion()
}
}
}
}
@@ -9,6 +9,8 @@
#import "NotificationService.h"
#import "EQNAllertaSismica.h"
#import "Costanti.h"
#import "EQNNotificationService-Swift.h"
@interface NotificationService ()
@@ -158,7 +160,10 @@ static NSString * const EQNSoundNotificationEQN = @"alert_sound.wav";
}
}
[self contentComplete];
// remove same type posted notification
[self removeNotificationsForType:notificationType completion:^{
[self contentComplete];
}];;
}
- (void)serviceExtensionTimeWillExpire
@@ -7,9 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
650B23AB2632CCD3007AE752 /* UIView+EQNExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650B23AA2632CCD3007AE752 /* UIView+EQNExtensions.swift */; };
651901B925F5358700CAFF20 /* EQNMapAnnotationSeismic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 651901B825F5358700CAFF20 /* EQNMapAnnotationSeismic.swift */; };
6525A82625E13FD4008FE0D0 /* SeismicNetworkAdvertiseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6525A82525E13FD4008FE0D0 /* SeismicNetworkAdvertiseTableViewCell.swift */; };
652C37BD26092B3C0068EC3B /* FiltersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652C37BC26092B3C0068EC3B /* FiltersViewModel.swift */; };
6531185928425B89006CBC29 /* NotificationService+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6531185828425B89006CBC29 /* NotificationService+Extension.swift */; };
65355FFF25F38D3300BB57D2 /* SegnalazioniMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65355FFE25F38D3300BB57D2 /* SegnalazioniMapViewController.swift */; };
6535600425F398CD00BB57D2 /* Costanti+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6535600325F398CD00BB57D2 /* Costanti+Extensions.swift */; };
653604E9262348FA00B2B651 /* EQNBaseMapFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653604E8262348FA00B2B651 /* EQNBaseMapFilter.swift */; };
@@ -129,6 +131,8 @@
6562C80725FFA6B100C85273 /* SeismicNetworkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */; };
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 */; };
65AD23CE261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AD23CD261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift */; };
65BBB22C26064BE6005D6CDF /* SegnalazioniLast24HoursCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BBB22B26064BE6005D6CDF /* SegnalazioniLast24HoursCell.swift */; };
65D409942619BA34008CF356 /* SegnalazioniSendReportCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D409932619BA34008CF356 /* SegnalazioniSendReportCell.swift */; };
@@ -136,6 +140,7 @@
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 */; };
65E1226C285C92AA000E294A /* EQNRealtimeAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E1226B285C92AA000E294A /* EQNRealtimeAlert.swift */; };
65E1B19B260F980600A0ACBA /* Dictionary+EQNExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E1B19A260F980600A0ACBA /* Dictionary+EQNExtensions.swift */; };
8C10B0B92281FE7F00125C9F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8C10B0BD2281FE7F00125C9F /* Localizable.strings */; };
8C10B0BA2281FE7F00125C9F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8C10B0BD2281FE7F00125C9F /* Localizable.strings */; };
@@ -225,7 +230,6 @@
DCB528212560161C005288E5 /* AlertSimulatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB528202560161C005288E5 /* AlertSimulatorViewController.swift */; };
DCB6FBEC24D0B40600ED23B8 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DCB6FBEB24D0B40600ED23B8 /* Colors.xcassets */; };
DCBB267A24D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCBB267924D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift */; };
DCBB267C24D1E98300F04559 /* EQNInsetTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCBB267B24D1E98300F04559 /* EQNInsetTableViewCell.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 */; };
@@ -284,9 +288,11 @@
/* 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>"; };
650B23AA2632CCD3007AE752 /* UIView+EQNExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+EQNExtensions.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>"; };
652C37BC26092B3C0068EC3B /* FiltersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersViewModel.swift; sourceTree = "<group>"; };
6531185828425B89006CBC29 /* NotificationService+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationService+Extension.swift"; sourceTree = "<group>"; };
65355FFE25F38D3300BB57D2 /* SegnalazioniMapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegnalazioniMapViewController.swift; sourceTree = "<group>"; };
6535600325F398CD00BB57D2 /* Costanti+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Costanti+Extensions.swift"; sourceTree = "<group>"; };
653604E8262348FA00B2B651 /* EQNBaseMapFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseMapFilter.swift; sourceTree = "<group>"; };
@@ -404,6 +410,8 @@
6562C80625FFA6B100C85273 /* SeismicNetworkViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeismicNetworkViewModel.swift; sourceTree = "<group>"; };
6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBlurredCloseButton.swift; sourceTree = "<group>"; };
658BAB7A25FE67930015C454 /* EQNBaseMapRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseMapRepresentable.swift; sourceTree = "<group>"; };
658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealtimeAlertViewController.swift; sourceTree = "<group>"; };
658BC02A2859A4D3009EECAA /* RealtimeAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealtimeAlertView.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>"; };
@@ -423,6 +431,7 @@
65DBFB7125E2BBF20041CBA6 /* GADTMediumTemplateView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GADTMediumTemplateView.m; sourceTree = "<group>"; };
65DBFB7225E2BBF20041CBA6 /* GADTTemplateView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GADTTemplateView.m; sourceTree = "<group>"; };
65DBFB7325E2BBF20041CBA6 /* GADTMediumTemplateView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GADTMediumTemplateView.h; sourceTree = "<group>"; };
65E1226B285C92AA000E294A /* EQNRealtimeAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNRealtimeAlert.swift; sourceTree = "<group>"; };
65E1B19A260F980600A0ACBA /* Dictionary+EQNExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+EQNExtensions.swift"; sourceTree = "<group>"; };
8C10B0BC2281FE7F00125C9F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
8C10B0BE2281FE9E00125C9F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -547,7 +556,6 @@
DCB528202560161C005288E5 /* AlertSimulatorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertSimulatorViewController.swift; sourceTree = "<group>"; };
DCB6FBEB24D0B40600ED23B8 /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = "<group>"; };
DCBB267924D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsHeaderTableViewCell.swift; sourceTree = "<group>"; };
DCBB267B24D1E98300F04559 /* EQNInsetTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNInsetTableViewCell.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>"; };
@@ -615,6 +623,15 @@
path = Debug;
sourceTree = "<group>";
};
658BC0272859A43C009EECAA /* Realtime Alert */ = {
isa = PBXGroup;
children = (
658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */,
658BC02A2859A4D3009EECAA /* RealtimeAlertView.swift */,
);
path = "Realtime Alert";
sourceTree = "<group>";
};
65DBFB5225E2A2580041CBA6 /* Map annotation */ = {
isa = PBXGroup;
children = (
@@ -660,6 +677,7 @@
8C483CB521FDACD100259FD2 /* EQNNotificationService-Bridging-Header.h */,
8C4B0B7C21CACE3F00AED489 /* NotificationService.h */,
8C4B0B7D21CACE3F00AED489 /* NotificationService.m */,
6531185828425B89006CBC29 /* NotificationService+Extension.swift */,
DC30BC862534DBB30041B23B /* Icons */,
8C4B0B7F21CACE3F00AED489 /* Info.plist */,
);
@@ -752,6 +770,7 @@
8C7A3B64225A5EA30045B266 /* NSDictionary+EQNExtensions.m */,
65E1B19A260F980600A0ACBA /* Dictionary+EQNExtensions.swift */,
65583A04261B83BE00ECA9F9 /* UIKit+Extensions.swift */,
650B23AA2632CCD3007AE752 /* UIView+EQNExtensions.swift */,
);
path = Extensions;
sourceTree = "<group>";
@@ -1067,6 +1086,7 @@
8C593E89217BA2470008B260 /* EQNSegnalazione.m */,
8CF4F4D9216D44930057110B /* EQNPastquakes.h */,
8CF4F4DA216D44930057110B /* EQNPastquakes.m */,
65E1226B285C92AA000E294A /* EQNRealtimeAlert.swift */,
);
path = Models;
sourceTree = "<group>";
@@ -1086,6 +1106,7 @@
DCEFF21024F57163009D3FE1 /* Settings */,
DC141968250E769B0059E060 /* Seismic Networks */,
DCB5281F256015EB005288E5 /* Simulator */,
658BC0272859A43C009EECAA /* Realtime Alert */,
);
path = Controllers;
sourceTree = "<group>";
@@ -1097,7 +1118,6 @@
DC03BEAA250BC0A60084769B /* EQNRoundedButton.swift */,
DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */,
DCA5B6E6252E4BD8002AEC96 /* EQNBaseTableViewCell.swift */,
DCBB267B24D1E98300F04559 /* EQNInsetTableViewCell.swift */,
653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */,
6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */,
);
@@ -1451,9 +1471,9 @@
"${BUILT_PRODUCTS_DIR}/DZNEmptyDataSet/DZNEmptyDataSet.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCrashlytics/FirebaseCrashlytics.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseInstanceID/FirebaseInstanceID.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
"${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
@@ -1466,9 +1486,9 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DZNEmptyDataSet.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreDiagnostics.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}/FirebaseInstanceID.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
@@ -1526,6 +1546,7 @@
buildActionMask = 2147483647;
files = (
DCDAB31925188BB3001AE40D /* EQNAllertaSismica.m in Sources */,
6531185928425B89006CBC29 /* NotificationService+Extension.swift in Sources */,
8C4B0B7E21CACE3F00AED489 /* NotificationService.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1574,13 +1595,14 @@
DCA5B6E7252E4BD8002AEC96 /* EQNBaseTableViewCell.swift in Sources */,
8CF66058214C566B009F4314 /* ServerRequest.m in Sources */,
DCF9E14D24F6D1AA002B6B1D /* EQNData.swift in Sources */,
65E1226C285C92AA000E294A /* EQNRealtimeAlert.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 */,
DCBB267C24D1E98300F04559 /* EQNInsetTableViewCell.swift in Sources */,
8CBD3DCA2149B9AD0070C963 /* AllerteViewController.m in Sources */,
DC646F32252B698B000AA5FD /* AlertsSeismicNotificationCompactTableViewCell.swift in Sources */,
DCF10DCD24D2C935009F34C3 /* EQNPurchaseAvailability.swift in Sources */,
@@ -1608,6 +1630,7 @@
DC65B391250F243E00251693 /* SeismicSettingsNetworksViewController.swift in Sources */,
65DBFB4B25E29DD60041CBA6 /* SeismicNetworksMapDetailViewController.swift in Sources */,
DC08804124F5B41400186D97 /* SettingSliderTableViewCell.swift in Sources */,
658BC0292859A456009EECAA /* RealtimeAlertViewController.swift in Sources */,
8CBD3DD82149B9AD0070C963 /* main.m in Sources */,
8CF05B57218C93BA0055012B /* EQNUtility.m in Sources */,
8C4E34422152B5E8008B0D2A /* EQNRilevamento.m in Sources */,
@@ -1631,6 +1654,7 @@
DCB28CEE24FB8400001F557E /* SettingsViewController.swift in Sources */,
DCB528212560161C005288E5 /* AlertSimulatorViewController.swift in Sources */,
DCC76BD8251F56050005C4DC /* SeismicCardSettingsViewController.swift in Sources */,
650B23AB2632CCD3007AE752 /* UIView+EQNExtensions.swift in Sources */,
653C67FC25F3D63500FE52AC /* EQNMapAnnotationUserReport.swift in Sources */,
DC3CE50A250EB7A8005A7DD5 /* EQNGenericPickerViewController.swift in Sources */,
DCEFF21A24F587E3009D3FE1 /* SettingItem.swift in Sources */,
@@ -1738,12 +1762,12 @@
CODE_SIGN_ENTITLEMENTS = EQNNotificationService/EQNNotificationService.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 82;
CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = WJA4MR4CPC;
INFOPLIST_FILE = EQNNotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 4.1.1;
MARKETING_VERSION = 5.2;
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationservice;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Service - Development";
@@ -1762,12 +1786,12 @@
CODE_SIGN_ENTITLEMENTS = EQNNotificationService/EQNNotificationService.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 82;
CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = WJA4MR4CPC;
INFOPLIST_FILE = EQNNotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 4.1.1;
MARKETING_VERSION = 5.2;
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationservice;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Service - AppStore";
@@ -1811,9 +1835,11 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = WJA4MR4CPC;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -1823,6 +1849,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
"ADS_ENABLED=0",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -1870,13 +1897,16 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = WJA4MR4CPC;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = "ADS_ENABLED=0";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -1899,16 +1929,16 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "Earthquake Network/Earthquake Network.entitlements";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 82;
CURRENT_PROJECT_VERSION = 97;
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";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 4.1.1;
MARKETING_VERSION = 5.2;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1944,8 +1974,6 @@
"-framework",
"\"FirebaseInstallations\"",
"-framework",
"\"FirebaseInstanceID\"",
"-framework",
"\"FirebaseMessaging\"",
"-framework",
"\"Foundation\"",
@@ -2011,15 +2039,15 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "Earthquake Network/Earthquake Network.entitlements";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution";
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 82;
CURRENT_PROJECT_VERSION = 97;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = WJA4MR4CPC;
GCC_PREFIX_HEADER = "Earthquake Network/Earthquake Network-Prefix.pch";
INFOPLIST_FILE = "Earthquake Network/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 4.1.1;
MARKETING_VERSION = 5.2;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -2055,8 +2083,6 @@
"-framework",
"\"FirebaseInstallations\"",
"-framework",
"\"FirebaseInstanceID\"",
"-framework",
"\"FirebaseMessaging\"",
"-framework",
"\"Foundation\"",
@@ -2120,12 +2146,12 @@
CODE_SIGN_ENTITLEMENTS = EQNNotificationContent/EQNNotificationContent.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 82;
CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = WJA4MR4CPC;
INFOPLIST_FILE = EQNNotificationContent/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 4.1.1;
MARKETING_VERSION = 5.2;
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationcontent;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Content - Development";
@@ -2144,12 +2170,12 @@
CODE_SIGN_ENTITLEMENTS = EQNNotificationContent/EQNNotificationContent.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 82;
CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = WJA4MR4CPC;
INFOPLIST_FILE = EQNNotificationContent/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 4.1.1;
MARKETING_VERSION = 5.2;
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationcontent;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Content - AppStore";
+7 -2
View File
@@ -36,10 +36,12 @@
// Test ads on specific devices
GADMobileAds.sharedInstance.requestConfiguration.testDeviceIdentifiers = @[ @"81392581e1790d4fbc6eff919815088d" ];
#endif
#if ADS_ENABLED
// start 3rd party SDKs and custom managers
[GADMobileAds.sharedInstance startWithCompletionHandler:^(GADInitializationStatus *status) {
NSLog(@"[AppDelegate] GADMobileAds started with status: %@", status);
}];
#endif
[EQNUser defaultUser];
[EQNManager defaultManager];
@@ -122,7 +124,10 @@
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = [self stringWithDeviceToken:deviceToken];
NSLog(@"[DEBUG] push token: %@", token);
[[NSUserDefaults standardUserDefaults] setObject:token forKey:EQNUserDefaultPushToken];
FIRMessaging.messaging.APNSToken = deviceToken;
}
- (NSString *)stringWithDeviceToken:(NSData *)deviceToken
@@ -178,9 +183,9 @@
EQNTabBarSection section = EQNTabBarSectionAllerte;
if ([userInfo[@"type"] isEqualToString:@"eqn"]) {
NSDate *dataRicezione = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:dataRicezione forKey:NOTIFICHE_RETE_SMARTPHONE_DATA_NOTIFICA];
[[NSUserDefaults standardUserDefaults] setObject:dataRicezione forKey:EQNUserDefaultRealTimeAlertDate];
[EQNUtility storeDictionary:userInfo toUserDefaultForKey:NOTIFICHE_RETE_SMARTPHONE_DIZIONARIO_NOTIFICA];
[EQNUtility storeDictionary:userInfo toUserDefaultForKey:EQNUserDefaultRealTimeAlertPayload];
section = EQNTabBarSectionAllerte;
} else if([userInfo[@"type"] isEqualToString:@"manual"]) {
section = EQNTabBarSectionSegnalazioni;
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -24,12 +24,12 @@
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" red="0.50766238939999997" green="0.75272958739999996" blue="0.98132258650000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Dzo-29-2FJ" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="LUF-7j-Kmc"/>
<constraint firstItem="Dzo-29-2FJ" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="MuU-xU-Ic2"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -38,6 +38,6 @@
</scene>
</scenes>
<resources>
<image name="eq_icon" width="166" height="166"/>
<image name="eq_icon" width="200" height="200"/>
</resources>
</document>
@@ -16,9 +16,9 @@
@import StoreKit;
@import SafariServices;
@import CoreLocation;
@import GoogleMobileAds;
@interface AllerteViewController () <UITableViewDelegate, UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UIBarButtonItem *expandeCollapseButton;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) NSMutableArray *tableItems;
@property (nonatomic) BOOL isNotificaAttiva;
@@ -36,7 +36,7 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
AllerteTableRowAllertePassate,
AllerteTableRowReteSmartphone,
AllerteTableRowServizioPriorita,
AllerteTableRowVersionePro,
AllerteTableRowVersionePro, // non più visualizzata con passaggio dell'app a pagamento
AllerteTableRowDatiPosizione
};
@@ -104,7 +104,7 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
- (void)setupUI
{
self.title = [NSLocalizedString(@"tab_network", nil) capitalizedString];
self.tableView.estimatedRowHeight = 200.0;
self.tableView.estimatedRowHeight = 600.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
@@ -112,37 +112,61 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
{
[super refreshUI];
NSDate *date = [[NSUserDefaults standardUserDefaults] objectForKey:NOTIFICHE_RETE_SMARTPHONE_DATA_NOTIFICA];
if (date) {
if ([EQNUtility getDifferenceMinute:date] < TEMPO_VISUALIZZAZIONE_NOTIFICA)
self.isNotificaAttiva = YES;
else{
self.isNotificaAttiva = NO;
[[NSUserDefaults standardUserDefaults] removeObjectForKey:NOTIFICHE_RETE_SMARTPHONE_DATA_NOTIFICA];
[[NSUserDefaults standardUserDefaults] synchronize];
// `AllerteTableRowReteSmartphone` and `AllerteTableRowDatiPosizione` are hidden bu default, user can show them
BOOL showAllCards = [[NSUserDefaults standardUserDefaults] boolForKey:EQNUserDefaultKeyAlertsShowAllCards];
self.expandeCollapseButton.image = showAllCards ? [UIImage imageNamed:@"navbar-icon-arrow-collapse"] : [UIImage imageNamed:@"navbar-icon-arrow-expand"];
// controlliamo se c'è una notifica in tempo reale da mostrare
NSDate *date = [[NSUserDefaults standardUserDefaults] objectForKey:EQNUserDefaultRealTimeAlertDate];
NSDictionary *info = [EQNUtility loadDictionaryFromUserDefaultsForKey:EQNUserDefaultRealTimeAlertPayload];
if (date && info && [EQNUtility getDifferenceMinute:date] < EQNRealtimeAlertExpiration) {
self.isNotificaAttiva = YES;
// mostriamo la schermata solo se il countdown non è a zero
EQNRealtimeAlert *alert = [[EQNRealtimeAlert alloc] initWithNotification:info];
if (alert != nil && ![alert isCountdownExpired]) {
RealtimeAlertViewController *controller = [[RealtimeAlertViewController alloc] initWithAlert:alert];
if (@available(iOS 13.0, *)) {
controller.modalInPresentation = YES;
}
[self presentViewController:controller animated:YES completion:nil];
}
} else {
[self resetRealtimeAlert];
}
[self.tableItems removeAllObjects];
// rows always visible
[self.tableItems addObjectsFromArray:@[ @(AllerteTableRowSismiRilevati), @(AllerteTableRowAllertePassate), @(AllerteTableRowServizioPriorita)]];
if (showAllCards) {
[self.tableItems addObject:@(AllerteTableRowReteSmartphone)];
}
// check if locations is enabled
if (CLLocationManager.authorizationStatus != kCLAuthorizationStatusAuthorizedAlways) {
[self.tableItems addObject:@(AllerteTableRowLocationPermission)];
}
// always visible rows
[self.tableItems addObjectsFromArray:@[ @(AllerteTableRowSismiRilevati), @(AllerteTableRowAllertePassate), @(AllerteTableRowReteSmartphone), @(AllerteTableRowServizioPriorita)]];
// pro cell visible only if user hasn't already bought the app
if ([EQNPurchaseUtility isProVersionEnabled] == NO) {
[self.tableItems addObject:@(AllerteTableRowVersionePro)];
}
// location data visible only if last position is known
if ([EQNUser defaultUser].lastPosition != nil) {
if ([EQNUser defaultUser].lastPosition != nil && showAllCards) {
[self.tableItems addObject:@(AllerteTableRowDatiPosizione)];
}
// sort items based on enum position
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES];
[self.tableItems sortUsingDescriptors:@[sorter]];
[self.tableView reloadData];
}
- (void)resetRealtimeAlert
{
[[NSUserDefaults standardUserDefaults] removeObjectForKey:EQNUserDefaultRealTimeAlertDate];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:EQNUserDefaultRealTimeAlertPayload];
self.isNotificaAttiva = NO;
}
#pragma mark - Actions
- (IBAction)refreshDataTapped:(id)sender
@@ -150,13 +174,19 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
[[EQNManager defaultManager] sincronizza];
}
- (IBAction)collapseExpandTapped:(id)sender
{
// toggle saved value
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL showAll = [defaults boolForKey:EQNUserDefaultKeyAlertsShowAllCards];
[defaults setBool:!showAll forKey:EQNUserDefaultKeyAlertsShowAllCards];
[self refreshUI];
}
- (void)actionCloseNotification
{
[[NSUserDefaults standardUserDefaults] removeObjectForKey:NOTIFICHE_RETE_SMARTPHONE_DATA_NOTIFICA];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:NOTIFICHE_RETE_SMARTPHONE_DIZIONARIO_NOTIFICA];
[[NSUserDefaults standardUserDefaults] synchronize];
self.isNotificaAttiva = NO;
[self resetRealtimeAlert];
[self.tableView reloadData];
}
@@ -239,7 +269,7 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
} else if (tableRow == AllerteTableRowSismiRilevati) {
if (self.isNotificaAttiva) {
AlertsSeismicNotificationExpandedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SeismicNotificationExpandedCell" forIndexPath:indexPath];
NSDictionary *info = [EQNUtility loadDictionaryFromUserDefaultsForKey:NOTIFICHE_RETE_SMARTPHONE_DIZIONARIO_NOTIFICA];
NSDictionary *info = [EQNUtility loadDictionaryFromUserDefaultsForKey:EQNUserDefaultRealTimeAlertPayload];
cell.notification = info;
__weak AllerteViewController *weakSelf = self;
@@ -15,7 +15,6 @@ class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMa
@objc var notification: [String: Any]? {
didSet {
startCountdown()
updateUI()
}
}
@@ -64,17 +63,6 @@ class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMa
descriptionLabel.text = NSLocalizedString("map_smartphone_magnitude", comment: "")
}
private func startCountdown() {
guard let notification = notification else { return }
// calculate the impact timestamp and start a timer for the countdown label
if let impactTimestamp = EQNUtility.calculateUserSeismicTimestamp(fromUserInfo: notification) {
self.impactTimestamp = impactTimestamp
countdownTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(countdownTimerFired(_:)), userInfo: nil, repeats: true)
countdownTimer?.fire()
}
}
private func updateUI() {
// clearn any other previous notifications
notificationTitleLabel.text = ""
@@ -149,20 +137,6 @@ class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMa
// MARK: - Actions
@objc private func countdownTimerFired(_ sender: Timer) {
guard let impactTimestamp = impactTimestamp else { return }
let now = Date()
let difference = lround(max(impactTimestamp.timeIntervalSince(now), 0))
waveTimeLabel.text = String(format: NSLocalizedString("alert_wave", comment: ""), difference)
if difference <= 0 {
// stop the countdown
countdownTimer?.invalidate()
countdownTimer = nil
}
}
@IBAction private func shareAppTapped(_ sender: UIButton) {
onTapShareApp?()
}
@@ -44,7 +44,11 @@
{
[super viewWillAppear:animated];
#if ADS_ENABLED
[self handleAdBanner];
#else
[self hideAdBanner];
#endif
}
#pragma mark - Public
@@ -13,6 +13,7 @@ import StoreKit
class PurchaseProVersionViewController: UIViewController {
@IBOutlet private weak var containerView: UIView!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var subtitleLabel: UILabel!
@IBOutlet private weak var discountTextLabel: UILabel!
@@ -65,6 +66,7 @@ class PurchaseProVersionViewController: UIViewController {
openTermsButton.setTitle(NSLocalizedString("network_pro_terms_conditions", comment: ""), for: .normal)
payingLabel.text = NSLocalizedString("network_pro_paying", comment: "")
purchaseButton.setTitle(NSLocalizedString("network_pro_convert", comment: "").uppercased(), for: .normal)
containerView.eqn_applyShadowAndRoundedCorners()
}
private func updateUI() {
@@ -22,6 +22,7 @@ class SubscriptionDetailViewController: UIViewController {
}
}
@IBOutlet private weak var containerView: UIView!
@IBOutlet private weak var productTitleLabel: UILabel!
@IBOutlet private weak var productImageView: UIImageView!
@IBOutlet private weak var productDescriptionLabel: UILabel!
@@ -43,42 +44,44 @@ class SubscriptionDetailViewController: UIViewController {
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:
productImageView.image = UIImage.init(named: "top_10k")
case VersioneProProducts.Identifier.Subscription10kMonthly,
VersioneProProducts.Identifier.Subscription100kMonthly:
purchaseRecapString = "inapp_monthly_payment"
case VersioneProProducts.Identifier.Subscription100kMonthly:
productImageView.image = UIImage.init(named: "top_100k")
purchaseRecapString = "inapp_monthly_payment"
case VersioneProProducts.Identifier.Subscription100kYearly, VersioneProProducts.Identifier.Subscription100kYearlyDiscounted:
productImageView.image = UIImage.init(named: "top_100k")
subscriptionDetailsString = "inapp_detail_description"
case VersioneProProducts.Identifier.Subscription100kYearly,
VersioneProProducts.Identifier.Subscription100kYearlyDiscounted,
VersioneProProducts.Identifier.Subscription10kYearly,
VersioneProProducts.Identifier.Subscription10kYearlyDiscounted:
purchaseRecapString = "inapp_yearly_payment"
case VersioneProProducts.Identifier.Subscription10kYearly, VersioneProProducts.Identifier.Subscription10kYearlyDiscounted:
productImageView.image = UIImage.init(named: "top_10k")
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("", comment: "")
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)
@@ -9,7 +9,7 @@
import UIKit
import StoreKit
class SubscriptionProductTableViewCell: EQNInsetTableViewCell {
class SubscriptionProductTableViewCell: UITableViewCell {
var product: SKProduct? {
didSet {
@@ -28,22 +28,38 @@ class SubscriptionProductTableViewCell: EQNInsetTableViewCell {
@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 }
productImageView.image = imageForProductIdentifier(product.productIdentifier)
productImageView.image = VersioneProProducts.image(for: product.productIdentifier)
productTitleLabel.text = product.localizedTitle
productDescriptionLabel?.text = product.localizedDescription
let infoKey = is100kSubscriptionForProductIdentifier(product.productIdentifier) ? "inapp_available_100k" : "inapp_available_10k"
let infoKey = VersioneProProducts.is100kSubscription(for: product.productIdentifier) ? "inapp_available_100k" : "inapp_available_10k"
let counter = availability(for: product.productIdentifier)
productInfoLabel.text = String(format: NSLocalizedString(infoKey, comment: ""), counter)
}
private func availability(for productIdentifier: String) -> Int {
if is100kSubscriptionForProductIdentifier(productIdentifier) {
if VersioneProProducts.is100kSubscription(for: productIdentifier) {
return availability?.top100kAvailable ?? 0
}
return availability?.top10kAvailable ?? 0
@@ -9,7 +9,7 @@
import UIKit
import StoreKit
class SubscriptionsActiveTableViewCell: EQNInsetTableViewCell {
class SubscriptionsActiveTableViewCell: EQNBaseTableViewCell {
var product: SKProduct? {
didSet {
@@ -40,7 +40,7 @@ class SubscriptionsActiveTableViewCell: EQNInsetTableViewCell {
if let productIdentifier = product?.productIdentifier {
noSubscriptionsLabel.isHidden = true
activeSubscriptionImageView.isHidden = false
activeSubscriptionImageView.image = imageForProductIdentifier(productIdentifier)
activeSubscriptionImageView.image = VersioneProProducts.image(for: productIdentifier)
} else {
noSubscriptionsLabel.isHidden = false
activeSubscriptionImageView.isHidden = true
@@ -8,7 +8,7 @@
import UIKit
class SubscriptionsDescriptionTableViewCell: EQNInsetTableViewCell {
class SubscriptionsDescriptionTableViewCell: EQNBaseTableViewCell {
@IBOutlet private weak var headerLabel: UILabel!
@IBOutlet private weak var descriptionLabel: UILabel!
@@ -8,7 +8,7 @@
import UIKit
class SubscriptionsHeaderTableViewCell: EQNInsetTableViewCell {
class SubscriptionsHeaderTableViewCell: UITableViewCell {
var isLoading = false {
didSet {
@@ -25,13 +25,6 @@ class SubscriptionsHeaderTableViewCell: EQNInsetTableViewCell {
@IBOutlet private weak var headerTitleLabel: UILabel!
@IBOutlet private weak var loadingActivityIndicator: UIActivityIndicatorView!
// MARK: - View Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
// MARK: - Private
private func updateUI() {
@@ -21,11 +21,13 @@ class SubscriptionsViewController: UITableViewController {
case description
case monthly
case yearly
case perpetual
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
}
}
@@ -36,6 +38,7 @@ class SubscriptionsViewController: UITableViewController {
private var allProducts = [SKProduct]()
private var monthlyProducts = [SKProduct]()
private var yearlyProducts = [SKProduct]()
private var perpetualProducts = [SKProduct]()
/// Product already bought by the user
private var subscribedProduct: SKProduct?
/// Availability for subscriptions
@@ -105,6 +108,7 @@ class SubscriptionsViewController: UITableViewController {
private func updateUI() {
monthlyProducts.removeAll()
yearlyProducts.removeAll()
perpetualProducts.removeAll()
// creates list to show
let isDiscountAvailable = checkDiscountPrice()
@@ -127,6 +131,11 @@ class SubscriptionsViewController: UITableViewController {
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()
@@ -142,7 +151,7 @@ class SubscriptionsViewController: UITableViewController {
let purchased = products.filter { (product) -> Bool in
let isPurchased = VersioneProProducts.store.isProductPurchased(product.productIdentifier)
let isSubscription = VersioneProProducts.Identifier.isSubscription(for: product.productIdentifier)
let isSubscription = VersioneProProducts.isSubscription(for: product.productIdentifier)
return isPurchased && isSubscription
}
self.subscribedProduct = purchased.first
@@ -231,7 +240,7 @@ class SubscriptionsViewController: UITableViewController {
if tableSection.sectionTitle != nil {
return 50
}
return 10
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@@ -239,8 +248,10 @@ class SubscriptionsViewController: UITableViewController {
switch tableSection {
case .active: return 1
case .description: return 1
case .monthly: return monthlyProducts.count
case .yearly: return yearlyProducts.count
case .monthly,
.yearly,
.perpetual:
return availableProducts(for: tableSection).count
}
}
@@ -252,6 +263,33 @@ class SubscriptionsViewController: UITableViewController {
}
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]
@@ -265,7 +303,7 @@ class SubscriptionsViewController: UITableViewController {
return cell
}
let products = tableSection == .monthly ? monthlyProducts : yearlyProducts
let products = availableProducts(for: tableSection)
let cell = tableView.dequeueReusableCell(withIdentifier: "SubscriptionCell", for: indexPath) as! SubscriptionProductTableViewCell
cell.product = products[indexPath.row]
cell.availability = availability
@@ -276,11 +314,22 @@ class SubscriptionsViewController: UITableViewController {
tableView.deselectRow(at: indexPath, animated: true)
let tableSection = sections[indexPath.section]
if tableSection == .monthly || tableSection == .yearly {
let products = tableSection == .monthly ? monthlyProducts : yearlyProducts
let products = availableProducts(for: tableSection)
if !products.isEmpty {
performSegue(withIdentifier: Self.SegueIdentifierSubscriptionDetail, sender: products[indexPath.row])
}
}
// MARK: - Helpers
private func availableProducts(for section: TableSection) -> [SKProduct] {
switch section {
case .monthly: return monthlyProducts
case .yearly: return yearlyProducts
case .perpetual: return perpetualProducts
default: return []
}
}
}
extension SubscriptionsViewController: StoryboardInitializable {
@@ -0,0 +1,160 @@
//
// RealtimeAlertView.swift
// Earthquake Network
//
// Created by Andrea Busi on 15/06/22.
// Copyright © 2022 Earthquake Network. All rights reserved.
//
import UIKit
import MapKit
class RealtimeAlertView: UIView {
let titleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .preferredFont(forTextStyle: .title2)
label.text = NSLocalizedString("app_name", comment: "")
return label
}()
let descriptionLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .preferredFont(forTextStyle: .body)
label.numberOfLines = 0
return label
}()
let waveTimeLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .preferredFont(forTextStyle: .title3)
label.textColor = AppTheme.Colors.red
label.text = String(format: NSLocalizedString("alert_wave", comment: ""), 0)
label.textAlignment = .center
label.isHidden = true
return label
}()
lazy var mapView: MKMapView = {
let map = MKMapView()
map.translatesAutoresizingMaskIntoConstraints = false
map.delegate = self
map.register(EQNCustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SingleLineIdentifier)
map.showsUserLocation = true
return map
}()
let closeButton: EQNBlurredCloseButton = {
let button = EQNBlurredCloseButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(.darkGray, for: .normal)
return button
}()
// MARK: - Init
convenience init() {
self.init(frame: .zero)
configureUI()
}
// MARK: - Private
private func configureUI() {
backgroundColor = AppTheme.Colors.lightGray
addSubview(closeButton)
addSubview(titleLabel)
addSubview(descriptionLabel)
addSubview(waveTimeLabel)
addSubview(mapView)
closeButton.addDefaultConstraint(to: self)
titleLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: closeButton.leadingAnchor, constant: -10.0).isActive = true
titleLabel.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor, constant: 10.0).isActive = true
descriptionLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true
descriptionLabel.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor).isActive = true
descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 20.0).isActive = true
waveTimeLabel.leadingAnchor.constraint(equalTo: descriptionLabel.leadingAnchor).isActive = true
waveTimeLabel.trailingAnchor.constraint(equalTo: descriptionLabel.trailingAnchor).isActive = true
waveTimeLabel.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 20.0).isActive = true
mapView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
mapView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
mapView.topAnchor.constraint(equalTo: waveTimeLabel.bottomAnchor, constant: 20.0).isActive = true
mapView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
// MARK: - Public
func addMapCircle(
center: CLLocationCoordinate2D,
radius: CLLocationDistance,
overlayId: String
) {
// remove any other existing overlays
let overlays = mapView.overlays.filter { $0.title == overlayId }
mapView.removeOverlays(overlays)
// add new overlay
let circle = MKCircle(center: center, radius: radius)
circle.title = overlayId
mapView.addOverlay(circle)
}
func addMapLine(
coordinates: [CLLocationCoordinate2D]
) {
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOverlay(polyline)
}
func addMapAnnotation(
title: String = "",
center: CLLocationCoordinate2D,
intensity: Int
) {
let annotation = EQNMapAnnotationPastquake(title: title, coordinate: center, intensity: intensity)
mapView.addAnnotation(annotation)
}
}
extension RealtimeAlertView: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
switch overlay {
case let circle as MKCircle:
let circleRenderer = MKCircleRenderer(overlay: circle)
circleRenderer.strokeColor = AppTheme.Colors.red
circleRenderer.fillColor = AppTheme.Colors.red.withAlphaComponent(0.2)
circleRenderer.lineWidth = 3.0
return circleRenderer
case let polyline as MKPolyline:
let polylineRenderer = MKPolylineRenderer(polyline: polyline)
polylineRenderer.strokeColor = .blue
polylineRenderer.lineWidth = 2.0
return polylineRenderer
default:
return MKOverlayRenderer(overlay: overlay)
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let annotation = annotation as? EQNMapAnnotationPastquake else {
return nil
}
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: EQNCustomAnnotationView.SingleLineIdentifier, for: annotation) as! EQNCustomAnnotationView
annotationView.image = annotation.image
annotationView.title = annotation.title
return annotationView
}
}
@@ -0,0 +1,168 @@
//
// RealtimeAlertViewController.swift
// Earthquake Network
//
// Created by Andrea Busi on 15/06/22.
// Copyright © 2022 Earthquake Network. All rights reserved.
//
import UIKit
import MapKit
class RealtimeAlertViewController: UIViewController, MKMapViewDelegate {
@objc var onClose: () -> Void = {}
// MARK: - Internal
private let notificationView = RealtimeAlertView()
/// Alert to display
private let realtimeAlert: EQNRealtimeAlert
/// Timer to constantly update countdown label
private var countdownTimer: Timer?
/// Refresh time for wave animation
private let waveAnimationRefreshRate = 0.1
/// Current radius of the wave animation on the map
private var waveAnimationCurrentRadius: CLLocationDistance = 0
private var waveAnimationVelocity: Double = 1_000
/// Timer to simulate animation for the wave
private var waveAnimationTimer: Timer?
// MARK: - Init
@objc
init(alert: EQNRealtimeAlert) {
self.realtimeAlert = alert
super.init(nibName: nil, bundle: nil)
self.waveAnimationCurrentRadius = currentWavePosition()
self.waveAnimationVelocity = evaluateWaveAnimationVelocity()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
// importante togliere il delegato, altrimenti causa crash
notificationView.mapView.delegate = nil
}
// MARK: - View Lifecycle
override func loadView() {
view = notificationView
}
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
updateUI()
startCountdown()
startWaveAnimation()
}
// MARK: - Private
private func configureUI() {
notificationView.closeButton.addTarget(self, action: #selector(onTapClose(_:)), for: .touchUpInside)
}
private func updateUI() {
notificationView.descriptionLabel.text = realtimeAlert.title
// update title with distance from earthquake
let distanceRound = Int(round(realtimeAlert.distanceFromUser() / 1_000))
notificationView.descriptionLabel.text = (notificationView.descriptionLabel.text ?? "")
+ ".\n"
+ String(format: NSLocalizedString("timer_message2_other", comment: ""), distanceRound)
// center map on the earthquake coordinate
let span = MKCoordinateSpan(latitudeDelta: 10.5, longitudeDelta: 10.5)
let region = MKCoordinateRegion(center: realtimeAlert.coordinate.coordinate, span: span)
notificationView.mapView.setCenter(realtimeAlert.coordinate.coordinate, animated: false)
notificationView.mapView.setRegion(region, animated: true)
// aggiungiamo annotation con epicentro sisma
notificationView.addMapAnnotation(center: realtimeAlert.coordinate.coordinate, intensity: realtimeAlert.intensity)
// simuliamo animazione dell'onda sismica
notificationView.addMapCircle(center: realtimeAlert.coordinate.coordinate, radius: waveAnimationCurrentRadius, overlayId: "wave_animation")
// aggiungiamo un segmento tra la posizione del sisma e quella dell'utente
if let lastPosition = EQNUser.default().lastPosition {
notificationView.addMapLine(coordinates: [realtimeAlert.coordinate.coordinate, lastPosition.coordinate])
}
}
private func startCountdown() {
// show countdown only if time is less than 300 seconds
if realtimeAlert.currentCountdown() < 300 {
// start a timer for the countdown label
notificationView.waveTimeLabel.isHidden = false
countdownTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(countdownTimerFired(_:)), userInfo: nil, repeats: true)
countdownTimer?.fire()
}
}
private func startWaveAnimation() {
waveAnimationTimer = Timer.scheduledTimer(timeInterval: waveAnimationRefreshRate, target: self, selector: #selector(mapWaveAnimationFired(_:)), userInfo: nil, repeats: true)
waveAnimationTimer?.fire()
}
// MARK: - Action
@objc private func onTapClose(_ sender: UIButton) {
// invalidiamo i timer, altri
countdownTimer?.invalidate()
countdownTimer = nil
waveAnimationTimer?.invalidate()
waveAnimationTimer = nil
onClose()
dismiss(animated: true)
}
// MARK: - Timer
@objc private func countdownTimerFired(_ sender: Timer) {
let countdown = realtimeAlert.currentCountdown()
notificationView.waveTimeLabel.text = String(format: NSLocalizedString("alert_wave", comment: ""), countdown)
if countdown <= 0 {
// stop the countdown
countdownTimer?.invalidate()
countdownTimer = nil
}
}
@objc private func mapWaveAnimationFired(_ sender: Timer) {
waveAnimationCurrentRadius += waveAnimationVelocity
notificationView.addMapCircle(center: realtimeAlert.coordinate.coordinate, radius: waveAnimationCurrentRadius, overlayId: "wave_animation")
}
// MARK: - Helpers
/// Evaluate current position for the wave
/// Used to define initial position for the wave circle
/// - Returns: Distance of the wave from the original earthquake point
private func currentWavePosition() -> Double {
// distanza tra utente e terremoto
let distance = realtimeAlert.distanceFromUser()
// calcoliamo la distanza rimanente da mostrare, perchè la schermata potrebbe anche essere aperta in ritardo
let remainingDistance = realtimeAlert.waveSpeed * Double(realtimeAlert.currentCountdown())
return distance - remainingDistance
}
/// Evaluate wave velocity based on push notification data
/// - Returns: Wave velocity, used for animation
private func evaluateWaveAnimationVelocity() -> Double {
let velocity = realtimeAlert.waveSpeed
return velocity * waveAnimationRefreshRate
}
}
@@ -10,7 +10,7 @@ import UIKit
import MapKit
import CoreLocation
protocol SeismicNetworkTableViewCellDelegate: class {
protocol SeismicNetworkTableViewCellDelegate: AnyObject {
func seismicNetworkCellDidTapShare(_ cell: SeismicNetworkTableViewCell)
func seismicNetworkCellDidTapMap(_ cell: SeismicNetworkTableViewCell)
func seismicNetworkCellDidTapMapDetail(_ cell: SeismicNetworkTableViewCell)
@@ -90,7 +90,7 @@ class SeismicNetworkTableViewCell: UITableViewCell {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.preferredFont(for: .title2, weight: .semibold)
label.numberOfLines = 2
label.numberOfLines = 3
return label
}()
@@ -256,7 +256,9 @@ class SeismicNetworkTableViewCell: UITableViewCell {
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
shareButton.widthAnchor.constraint(equalTo: shareButton.heightAnchor).isActive = true
@@ -8,7 +8,7 @@
import UIKit
@objc protocol SeismicFiltersViewControllerDelegate: class {
protocol SeismicFiltersViewControllerDelegate: AnyObject {
func seismicFiltersControllerDidUpdateFilters(_ controller: SeismicFiltersViewController)
}
@@ -24,7 +24,7 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
case modificaImpostazioni
}
@objc weak var delegate: SeismicFiltersViewControllerDelegate?
weak var delegate: SeismicFiltersViewControllerDelegate?
/// Tells if delegate needs to redownload data when filter is dismissed
@objc private(set) var needsDataUpdate = false
@@ -66,7 +66,8 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
super.viewDidLoad()
setupUI()
updateUI()
loadDataSource()
tableView.reloadData()
}
private func setupUI() {
@@ -83,7 +84,7 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
closeButton.setLocalizedTitle(key: "official_close", uppercased: false)
}
private func updateUI() {
private func loadDataSource() {
currentMagnitudoMinima = EQNData.magitudoDebole(for: EQNSeismic.shared.magnitudoMinima)
if initialMagnitudoMinima == nil {
initialMagnitudoMinima = currentMagnitudoMinima
@@ -97,7 +98,6 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
initialQualsiasiMagnitudo = currentSismiQualsiasiMagnitudo
}
currentModificaImpostazioni = EQNSeismic.shared.modificaImpostazioniAbilitato
tableView.reloadData()
}
// MARK: - Table view delegate and data source
@@ -111,7 +111,7 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
switch setting.type {
case .slider:
let cell = tableView.dequeueReusableCell(withIdentifier: SettingSliderTableViewCell.Identifier, for: indexPath) as! SettingSliderTableViewCell
let cell = SettingSliderTableViewCell(style: .default, reuseIdentifier: nil)
cell.titleLabel.text = setting.displayTitle
if indexPath.row == RowIdentifier.magnitudoMinima.rawValue {
@@ -120,7 +120,6 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
currentMagnitudoMinima = value
EQNSeismic.shared.magnitudoMinima = value.value
EQNSeismic.shared.saveFilters()
updateUI()
}
cell.dragEnded = { [unowned self] in
showWarningAlertIfNeeded(for: currentMagnitudoMinima)
@@ -131,7 +130,6 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
currentDistanzaMassima = value
EQNSeismic.shared.distanzaMassima = value.value
EQNSeismic.shared.saveFilters()
updateUI()
}
} else if indexPath.row == RowIdentifier.periodoTemporale.rawValue {
cell.configureSlider(with: dataSourcePeriodoTemporale, current: currentPeriodoTemporale)
@@ -139,7 +137,6 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
currentPeriodoTemporale = value
EQNSeismic.shared.periodoTemporale = value.value
EQNSeismic.shared.saveFilters()
updateUI()
}
} else if indexPath.row == RowIdentifier.sismiFortiDistanza.rawValue {
cell.isDisabled = !currentSismiFortiAbilitati
@@ -148,13 +145,12 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
currentSismiFortiDistanza = value
EQNSeismic.shared.sismiFortiMagnitudo = value.value
EQNSeismic.shared.saveFilters()
updateUI()
}
}
return cell
case .enable:
let cell = tableView.dequeueReusableCell(withIdentifier: SettingEnableTableViewCell.Identifier, for: indexPath) as! SettingEnableTableViewCell
let cell = SettingEnableTableViewCell(style: .default, reuseIdentifier: nil)
cell.titleLabel.text = setting.displayTitle
cell.detailTextLabel?.text = setting.subtitle
@@ -164,7 +160,9 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
currentSismiFortiAbilitati = value
EQNSeismic.shared.sismiFortiAbilitati = value
EQNSeismic.shared.saveFilters()
updateUI()
loadDataSource()
tableView.reloadData()
}
} else if indexPath.row == RowIdentifier.sismiQualsiasiMagnitudo.rawValue {
cell.toggleSwitch.isOn = currentSismiQualsiasiMagnitudo
@@ -172,7 +170,6 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
currentSismiQualsiasiMagnitudo = value
EQNSeismic.shared.sismiQualsiasiAbilitati = value
EQNSeismic.shared.saveFilters()
updateUI()
}
} else if indexPath.row == RowIdentifier.modificaImpostazioni.rawValue {
cell.toggleSwitch.isOn = currentModificaImpostazioni
@@ -180,7 +177,6 @@ class SeismicFiltersViewController: UIViewController, UITableViewDelegate, UITab
currentModificaImpostazioni = value
EQNSeismic.shared.modificaImpostazioniAbilitato = value
EQNSeismic.shared.saveFilters()
updateUI()
}
}
@@ -8,7 +8,7 @@
import UIKit
protocol SeismicCardSettingsViewControllerDelegate: class {
protocol SeismicCardSettingsViewControllerDelegate: AnyObject {
func seismicCardSettingsDidComplete(_ controller: SeismicCardSettingsViewController)
}
@@ -9,7 +9,7 @@
import UIKit
import MapKit
protocol SeismicNetworksMapDetailViewControllerDelegate: class {
protocol SeismicNetworksMapDetailViewControllerDelegate: AnyObject {
func seismicNetworksMapDetailControllerWillUpdateData(_ controller: SeismicNetworksMapDetailViewController, needsDataUpdate: Bool)
}
@@ -155,10 +155,12 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
let filteredSeismics = EQNSeismic.shared.filterSeismicList(allSeismics ?? [])
rows = filteredSeismics.map { .seismic($0) }
#if ADS_ENABLED
// if is not a pro user, show an advertise
if !EQNPurchaseUtility.isProVersionEnabled() {
loadAd()
}
#endif
// if a map detail is presented, update its data
if let mapController = currentMapController {
@@ -9,13 +9,13 @@
import UIKit
@objc protocol SeismicSettingsNetworksViewControllerDelegate: class {
protocol SeismicSettingsNetworksViewControllerDelegate: AnyObject {
func seismicSettingsNetworksControllerDidComplete(_ controller: SeismicSettingsNetworksViewController)
}
class SeismicSettingsNetworksViewController: UITableViewController {
@objc weak var delegate: SeismicSettingsNetworksViewControllerDelegate?
weak var delegate: SeismicSettingsNetworksViewControllerDelegate?
// MARK: - Private
@@ -86,7 +86,12 @@ class SeismicSettingsNetworksViewController: UITableViewController {
savedNetworks.append(network.acronym)
}
tableView.reloadRows(at: [indexPath], with: .automatic)
// 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
@@ -9,7 +9,7 @@
import Foundation
@objc protocol SeismicSettingsViewControllerDelegate: class {
protocol SeismicSettingsViewControllerDelegate: AnyObject {
func seismicSettingsControllerDidComplete(_ controller: SeismicSettingsViewController)
func seismicSettingsControllerWillOpenProviders(_ controller: SeismicSettingsViewController)
}
@@ -17,7 +17,7 @@ import Foundation
class SeismicSettingsViewController: UIViewController {
@objc weak var delegate: SeismicSettingsViewControllerDelegate?
weak var delegate: SeismicSettingsViewControllerDelegate?
// MARK: - Private
@@ -89,8 +89,6 @@ class SettingDateTableViewCell: UITableViewCell {
// MARK: - Private
private func setupUI() {
translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(titleLabel)
stackView.addArrangedSubview(valuesLabel)
@@ -62,7 +62,6 @@ class SettingEnableTableViewCell: UITableViewCell {
private func setupUI() {
selectionStyle = .none
translatesAutoresizingMaskIntoConstraints = false
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
@@ -54,8 +54,6 @@ class SettingMultivaluesTableViewCell: UITableViewCell {
// MARK: - Private
private func setupUI() {
translatesAutoresizingMaskIntoConstraints = false
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
@@ -55,7 +55,6 @@ class SettingSegmentedTableViewCell: UITableViewCell {
private func setupUI() {
selectionStyle = .none
translatesAutoresizingMaskIntoConstraints = false
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
@@ -66,7 +66,6 @@ class SettingSliderTableViewCell: UITableViewCell {
private func setupUI() {
selectionStyle = .none
translatesAutoresizingMaskIntoConstraints = false
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
@@ -99,6 +98,12 @@ class SettingSliderTableViewCell: UITableViewCell {
let index = Int(sender.value)
let item = items[index]
// make slider with step values
let step: Float = 1
let roundedValue = round(sender.value / step) * step
sender.value = roundedValue
// update value
valueLabel.text = item.display
valueChanged?(item)
}
@@ -75,7 +75,8 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
self.dataSourceSismi = [EQNData seismicToNotify];
self.dataSourceRaggioSisma = [EQNData raggioSismi];
[self updateUI];
[self loadDataSource];
[self.tableView reloadData];
}
#pragma mark - Private
@@ -94,7 +95,7 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
[self.tableView registerClass:[SettingDateTableViewCell class] forCellReuseIdentifier:SettingDateTableViewCell.Identifier];
}
- (void)updateUI
- (void)loadDataSource
{
self.notificationEnabled = [EQNAllertaSismica sharedInstance].isAbilitato;
self.criticalAlertsEnabled = [EQNAllertaSismica sharedInstance].isCriticalAlertsEnabled;
@@ -120,8 +121,6 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
self.currentEndTime = endTime;
[[EQNAllertaSismica sharedInstance] saveUserInfo];
[self.tableView reloadData];
}
@@ -262,35 +261,40 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
{
[EQNAllertaSismica sharedInstance].sismiDaNotificare = seismic.value;
[[EQNAllertaSismica sharedInstance] saveUserInfo];
[self updateUI];
[self loadDataSource];
}
- (void)updateLowSeismicRadius:(EQNGenericValue *)radius
{
[EQNAllertaSismica sharedInstance].raggioSismiLievi = radius.value;
[[EQNAllertaSismica sharedInstance] saveUserInfo];
[self updateUI];
[self loadDataSource];
}
- (void)updateStrongSeismicRadius:(EQNGenericValue *)radius
{
[EQNAllertaSismica sharedInstance].raggioSismiForti = radius.value;
[[EQNAllertaSismica sharedInstance] saveUserInfo];
[self updateUI];
[self loadDataSource];
}
- (void)updateStartTime:(NSDate *)date
{
[EQNAllertaSismica sharedInstance].oraioInizio = date;
[[EQNAllertaSismica sharedInstance] saveUserInfo];
[self updateUI];
[self loadDataSource];
}
- (void)updateEndTime:(NSDate *)date
{
[EQNAllertaSismica sharedInstance].orarioFine = date;
[[EQNAllertaSismica sharedInstance] saveUserInfo];
[self updateUI];
[self loadDataSource];
}
- (void)askForCriticalAlertsPermission
@@ -62,14 +62,16 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
self.dataSourceRaggioSisma = [EQNData raggioSismi];
self.dataSourceMagnitudoForti = [EQNData magitudoForti];
[self updateUI];
[self loadDataSource];
[self.tableView reloadData];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self updateUI];
[self loadDataSource];
[self.tableView reloadData];
}
#pragma mark - Private
@@ -86,7 +88,7 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
[self.tableView registerClass:[SettingMultivaluesTableViewCell class] forCellReuseIdentifier:SettingMultivaluesTableViewCell.Identifier];
}
- (void)updateUI
- (void)loadDataSource
{
self.notificationEnabled = [EQNNotificheReteSismiche sharedInstance].isAbilitato;
self.notificationNearEarthquakeEnabled = [EQNNotificheReteSismiche sharedInstance].isAbilitaVicini;
@@ -110,8 +112,6 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
}
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
[self.tableView reloadData];
}
@@ -229,7 +229,7 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
[EQNNotificheReteSismiche sharedInstance].distanzaPosizione = radius.value;
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
[self updateUI];
[self loadDataSource];
}
- (void)updateSeismicEnergy:(EQNGenericValue *)energy
@@ -237,7 +237,7 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
[EQNNotificheReteSismiche sharedInstance].energiaSisma = energy.value;
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
[self updateUI];
[self loadDataSource];
}
- (void)updateStrongEarthquakeEnergy:(EQNGenericValue *)energy
@@ -245,7 +245,7 @@ typedef NS_ENUM(NSInteger, RowIdentifier) {
[EQNNotificheReteSismiche sharedInstance].energiaTerremotiForti = energy.value;
[[EQNNotificheReteSismiche sharedInstance] saveUserInfo];
[self updateUI];
[self loadDataSource];
}
- (NSString *)stringOfSelectedNetworks
+6 -5
View File
@@ -66,10 +66,14 @@ static NSString * const EQNServerUrlAlertSimulator = @"https://srv.earthquakenet
static NSString * const EQNUserDefaultAppGroupSuite = @"group.com.finazzi.distquake";
static NSString * const EQNUserDefaultKeyAlertsShowAllCards = @"EQNetwork.AlertsShowAllCards";
static NSString * const EQNUserDefaultKeySesmicInformations = @"EQNetwork.SeismicInformations";
static NSString * const EQNUserDefaultKeyOneShotShowCountry = @"EQNetwork.OneShot.CountrySelection";
static NSString * const EQNUserDefaultLastLocation = @"EQNLast_Location";
static NSString * const EQNUserDefaultSeismicNetworkCards = @"EQNData.RetiSismiche";
static NSString * const EQNUserDefaultRealTimeAlertPayload = @"EQNData.RealtimeAlertPayload";
static NSString * const EQNUserDefaultRealTimeAlertDate = @"EQNData.RealtimeAlertDate";
/// Numero di aperture dell'app per sbloccare la versione Pro scontata
static NSString * const EQNUserDefaultProDiscountOpenCounter = @"CONTEGGIO_APERTURE_PER_SCONTO";
/// Prezzo scontato per la versione pro scaduto
@@ -105,6 +109,8 @@ static NSTimeInterval const EQNSeismicDataRefreshInterval = 120.0;
static NSTimeInterval const EQNSendReportDelayBetweenMessages = 5.0;
/// Tempo di attesa (minuti) per l'invio di due commenti
static NSTimeInterval const EQNSendReportDelayBetweenComments = 30.0;
/// Tempo (in minuti) entro cui vengono mostrate allerte in tempo reale ricevute
static NSTimeInterval const EQNRealtimeAlertExpiration = 480;
#ifdef DEBUG
static NSString * const EQNAdMobAppIdAdaptiveBanner = @"ca-app-pub-3940256099942544/2934735716"; // test
@@ -215,11 +221,6 @@ typedef enum : NSInteger {
#define NOTIFICHE_ALLERA_SISMICA_ORA_INIZIO @"NOTIFICHE_ALLERA_SISMICA_ORA_INIZIO"
#define NOTIFICHE_ALLERA_SISMICA_ORA_FINE @"NOTIFICHE_ALLERA_SISMICA_ORA_INIZIO"
// NOTIFICHE RETE SMARTPHONE
#define NOTIFICHE_RETE_SMARTPHONE_DATA_NOTIFICA @"NOTIFICHE_RETE_SMARTPHONE_DATA_NOTIFICA"
#define NOTIFICHE_RETE_SMARTPHONE_DIZIONARIO_NOTIFICA @"NOTIFICHE_RETE_SMARTPHONE_DIZIONARIO_NOTIFICA"
#define TEMPO_VISUALIZZAZIONE_NOTIFICA 10800
// FILTRO ENTI
#define EQN_MAGNITUDO_MINIMA @"EQN_MAGNITUDO_MINIMA"
@@ -0,0 +1,25 @@
//
// UIView+EQNExtensions.swift
// Earthquake Network
//
// Created by Andrea Busi on 23/04/21.
// Copyright © 2021 Earthquake Network. All rights reserved.
//
import UIKit
extension UIView {
func eqn_applyShadowAndRoundedCorners() {
// rounded corners
layer.cornerRadius = AppTheme.shared.cardCornerRadius
layer.masksToBounds = false
// apply a shadow to the current view
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.5
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.shadowRadius = 2
}
}
@@ -10,6 +10,6 @@ import Foundation
@objc
protocol EQNCommandProtocol: class {
protocol EQNCommandProtocol: AnyObject {
@objc func execute()
}
@@ -0,0 +1,91 @@
//
// EQNRealtimeAlert.swift
// Earthquake Network
//
// Created by Andrea Busi on 17/06/22.
// Copyright © 2022 Earthquake Network. All rights reserved.
//
import Foundation
import CoreLocation
@objc
class EQNRealtimeAlert: NSObject {
typealias NotificationPayload = [String: Any]
/// Title to display
var title: String = ""
/// Earthquake coordinate
let coordinate: CLLocation
/// Earthquake intensity
let intensity: Int
/// Earthquake wave speed
let waveSpeed: Double
/// Calculated timestamp for earthquake on user position
let impactTimestamp: Date
// MARK: - Init
@objc
init?(notification: [String: Any]) {
guard let alert = Self.getPushAlertPayload(from: notification),
let coordinate = Self.getCoordinate(from: notification),
let impactTimestamp = EQNUtility.calculateUserSeismicTimestamp(fromUserInfo: notification) else {
return nil
}
self.coordinate = coordinate
self.impactTimestamp = impactTimestamp
if let title = alert["loc-key"] as? String, let args = alert["loc-args"] as? [String], let arg = args.first {
self.title = String(format: NSLocalizedString(title, comment: ""), arg)
}
self.intensity = notification.eqn_intValue(for: "intensity") ?? 0
self.waveSpeed = (notification.eqn_doubleValue(for: "wave_speed") ?? 0) * 1000 // m/s
}
func distanceFromUser() -> CLLocationDistance {
EQNUser.default().lastPosition?.distance(from: coordinate) ?? 0.0
}
/// Remaining time before earthquake gets user position
func currentCountdown() -> Int {
let now = Date()
let difference = lround(max(impactTimestamp.timeIntervalSince(now), 0))
return difference
}
@objc
func isCountdownExpired() -> Bool {
currentCountdown() <= 0
}
// MARK: - Helpers
/// Get `aps.alert` object inside a given notification payload
/// - Parameter notification: Notification payload
/// - Returns: `aps.alert` object if found, nil otherwise
static func getPushAlertPayload(
from notification: NotificationPayload
) -> NotificationPayload? {
guard let aps = notification["aps"] as? [String: Any],
let alert = aps["alert"] as? [String: Any] else {
return nil
}
return alert
}
/// Retrieve coordinate of earthquake from the notification payload
/// - Parameter notification: Notification payload
/// - Returns: Coordinate if found, nil otherwise
static func getCoordinate(
from notification: NotificationPayload
) -> CLLocation? {
guard let latitude = notification.eqn_doubleValue(for: "latitude"),
let longitude = notification.eqn_doubleValue(for: "longitude") else {
return nil
}
return CLLocation(latitude: latitude, longitude: longitude)
}
}
+4 -7
View File
@@ -130,14 +130,11 @@
- (void)inviaPosizioneServer
{
NSLog(@"URLPosizione %@", [EQNGeneratoreURLServer urlPosizione]);
[[ServerRequest defaultServerConnectionSingleton] inviaInformazioniAlServerWithURL:[EQNGeneratoreURLServer urlPosizione] richiesta:EQNTipoChiamataPosizione success:^(id result) {
NSLog(@"inviato");
} failure:^(NSError *errore) {
NSLog(@"[EQNUtility] Position saved on server");
[self saveUserInfo];
} failure:^(NSError *error) {
NSLog(@"[EQNUtility] Unable to save position. Error: %@", error.localizedDescription);
}];
}
@@ -102,6 +102,10 @@
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:keyName];
if (!data) {
NSLog(@"[EQNUtility] No array saved for key '%@'", keyName);
return nil;
}
NSError *error;
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&error];
@@ -119,6 +123,10 @@
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:keyName];
if (!data) {
NSLog(@"[EQNUtility] No dictionary saved for key '%@'", keyName);
return nil;
}
NSError *error;
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&error];
@@ -53,7 +53,7 @@
[userDefaults setBool:self.isAbilitato forKey:NOTIFICHE_ALLERA_SISMICA_ABILITATO];
[userDefaults setObject:self.sismiDaNotificare forKey:NOTIFICHE_ALLERA_SISMICA_SISMI_DA_NOTIFICARE];
[userDefaults setObject:self.raggioSismiLievi forKey:NOTIFICHE_ALLERA_SISMICA_RAGGIO_SISMI_LIEVI];
[userDefaults setObject:self.raggioSismiLievi forKey:NOTIFICHE_ALLERA_SISMICA_RAGGIO_SISMI_FORTI];
[userDefaults setObject:self.raggioSismiForti forKey:NOTIFICHE_ALLERA_SISMICA_RAGGIO_SISMI_FORTI];
[userDefaults setBool:self.isintervalloAllarme forKey:NOTIFICHE_ALLERA_SISMICA_ABILITA_INTERVALLO];
[userDefaults setObject:self.oraioInizio forKey:NOTIFICHE_ALLERA_SISMICA_ORA_INIZIO];
[userDefaults setObject:self.orarioFine forKey:NOTIFICHE_ALLERA_SISMICA_ORA_FINE];
@@ -37,40 +37,66 @@ public struct VersioneProProducts {
static let Subscription10kMonthly = "com.finazzi.distquake.Abbonamento10k.mensileAutomatico"
static let Subscription10kYearly = "com.finazzi.distquake.Abbonamento10k.annualeAutomatico"
static let Subscription10kYearlyDiscounted = "com.finazzi.distquake.Abbonamento10k.annualeAutomaticoScontato"
static let Subscription10kPerpetual = "com.finazzi.distquake.Abbonamento10k.perpetuo"
static let Subscription100kMonthly = "com.finazzi.distquake.Abbonamento100k.mensileAutomatico"
static let Subscription100kYearly = "com.finazzi.distquake.Abbonamento100k.annualeAutomatico"
static let Subscription100kYearlyDiscounted = "com.finazzi.distquake.Abbonamento100k.annualeAutomaticoscontato"
static let Subscription100kPerpetual = "com.finazzi.distquake.Abbonamento100k.perpetuo"
static let identifiers: Set<ProductIdentifier> = [
ProVersionFullPrice, ProVersionDiscounted,
Subscription10kMonthly, Subscription10kYearly, Subscription10kYearlyDiscounted,
Subscription100kMonthly, Subscription100kYearly, Subscription100kYearlyDiscounted
Subscription100kMonthly, Subscription100kYearly, Subscription100kYearlyDiscounted,
Subscription10kPerpetual, Subscription100kPerpetual
]
static let identifierForProVersion: Set<ProductIdentifier> = [
ProVersionFullPrice, ProVersionDiscounted,
Subscription10kYearly, Subscription10kYearlyDiscounted,
Subscription100kYearly, Subscription100kYearlyDiscounted
Subscription100kYearly, Subscription100kYearlyDiscounted,
Subscription10kPerpetual, Subscription100kPerpetual
]
static let identifiersForTop10k: Set<ProductIdentifier> = [
Subscription10kMonthly, Subscription10kYearly, Subscription10kYearlyDiscounted
Subscription10kMonthly, Subscription10kYearly, Subscription10kYearlyDiscounted, Subscription10kPerpetual
]
static let identifiersForTop100k: Set<ProductIdentifier> = [
Subscription100kMonthly, Subscription100kYearly, Subscription100kYearlyDiscounted
Subscription100kMonthly, Subscription100kYearly, Subscription100kYearlyDiscounted, Subscription100kPerpetual
]
static let identifierForSubscriptions: Set<ProductIdentifier> = [
Subscription10kMonthly, Subscription100kMonthly,
Subscription10kYearly, Subscription10kYearlyDiscounted,
Subscription100kYearly, Subscription100kYearlyDiscounted
Subscription100kYearly, Subscription100kYearlyDiscounted,
Subscription10kPerpetual, Subscription100kPerpetual
]
static func isSubscription(for identifier: String) -> Bool {
Self.identifierForSubscriptions.contains(identifier)
}
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)
@@ -80,27 +106,4 @@ func resourceNameForProductIdentifier(_ productIdentifier: String) -> String? {
return productIdentifier.components(separatedBy: ".").last
}
func imageForProductIdentifier(_ productIdentifier: String) -> UIImage? {
let products100k = [VersioneProProducts.Identifier.Subscription100kMonthly,
VersioneProProducts.Identifier.Subscription100kYearly,
VersioneProProducts.Identifier.Subscription100kYearlyDiscounted]
if products100k.contains(productIdentifier) {
return UIImage(named: "top_100k")
}
let products10k = [VersioneProProducts.Identifier.Subscription10kMonthly,
VersioneProProducts.Identifier.Subscription10kYearly,
VersioneProProducts.Identifier.Subscription10kYearlyDiscounted]
if products10k.contains(productIdentifier) {
return UIImage(named: "top_10k")
}
return nil
}
func is100kSubscriptionForProductIdentifier(_ productIdentifier: String) -> Bool {
let products100k = [VersioneProProducts.Identifier.Subscription100kMonthly,
VersioneProProducts.Identifier.Subscription100kYearly,
VersioneProProducts.Identifier.Subscription100kYearlyDiscounted]
return products100k.contains(productIdentifier)
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 12 KiB

@@ -137,6 +137,7 @@
case EQNTipoChiamataRilevamento:
onSuccess([EQNUtility clearStringMessaggi:newStr]);
break;
case EQNTipoChiamataPosizione:
case EQNTipoChiamataCalibrazione:
case EQNTipoChiamataImpostazioniNotifiche:
case EQNTipoChiamataAlertSimulator:
File diff suppressed because it is too large Load Diff
@@ -20,14 +20,7 @@ class EQNBaseTableViewCell: UITableViewCell {
clipsToBounds = true
// rounded corners
containerView.layer.cornerRadius = AppTheme.shared.cardCornerRadius
containerView.layer.masksToBounds = false
// apply a shadow to the container view
containerView.layer.shadowColor = UIColor.black.cgColor
containerView.layer.shadowOpacity = 0.5
containerView.layer.shadowOffset = CGSize(width: 0, height: 2)
containerView.layer.shadowRadius = 2
// rounded corners and shadow
containerView.eqn_applyShadowAndRoundedCorners()
}
}
@@ -61,9 +61,9 @@ class EQNBlurredCloseButton: UIButton {
/// Add constaints to show the button on the upper right corner
func addDefaultConstraint(to view: UIView) {
leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10.0).isActive = true
trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10.0).isActive = true
topAnchor.constraint(equalTo: view.topAnchor, constant: 10.0).isActive = true
widthAnchor.constraint(equalTo: heightAnchor).isActive = true
heightAnchor.constraint(equalToConstant: 40.0).isActive = true
heightAnchor.constraint(equalToConstant: 34.0).isActive = true
}
}
@@ -1,25 +0,0 @@
//
// EQNInsetTableViewCell.swift
// Earthquake Network
//
// Created by Busi Andrea on 29/07/2020.
// Copyright © 2020 Earthquake Network. All rights reserved.
//
import Foundation
class EQNInsetTableViewCell: UITableViewCell {
override var frame: CGRect {
get {
return super.frame
}
set (newFrame) {
let inset: CGFloat = 15
var frame = newFrame
frame.origin.x += inset
frame.size.width -= 2 * inset
super.frame = frame
}
}
}
@@ -209,12 +209,15 @@
"network_pro_terms_conditions" = "Όροι και συνθήκες";
"network_pro_paying" = "Πληρώνετε:";
"inapp_detail_description" = "• Η πληρωμή σας θα χρεωθεί στο λογαριασμό σας στο iTunes κατά την επιβεβαίωση της αγοράς\n• η συνδρομή ανανεώνεται αυτόματα εκτός εάν η αυτόματη ανανέωση απενεργοποιείται τουλάχιστον 24 ώρες πριν από το τέλος της τρέχουσας περιόδου\n• η συνδρομή θα χρεωθεί για ανανέωση εντός 24 Ώρες πριν από το τέλος της τρέχουσας περιόδου και το κόστος ανανέωσης που εντοπίστηκαν\n• Οι συνδρομές μπορούν να διαχειριστούν από τον χρήστη και η αυτόματη ανανέωση μπορεί να απενεργοποιηθεί με την πρόσβαση στις ρυθμίσεις του λογαριασμού του χρήστη μετά την αγορά.";
"inapp_lifetime_detail_description" = "• Η πληρωμή σας θα χρεωθεί στο λογαριασμό σας στο iTunes κατά την επιβεβαίωση της αγοράς";
"inapp_purchase" = "ΕΓΓΡΑΦΕΊΤΕ ΣΤΗΝ ΥΠΗΡΕΣΊΑ";
"official_select_country_placeholder" = "Επιλέξτε τη χώρα";
"inapp_lifetime_subscriptions" = "Συνδρομές διάρκειας ζωής";
"inapp_yearly_subscriptions" = "Ετήσιες συνδρομές";
"inapp_monthly_subscriptions" = "Μηνιαίες συνδρομές";
"inapp_monthly_payment" = "θα πληρώσετε ανά μήνα:";
"inapp_yearly_payment" = "θα πληρώσετε ετησίως:";
"inapp_lifetime_payment" = "θα πληρώσετε:";
"ok" = "Εντάξει";
"critical_alerts_setting" = "Κρίσιμες ειδοποιήσεις. Κάντε έναν ήχο επίσης, δεν διαταράσσετε τη λειτουργία";
"attention" = "Προσοχή";
@@ -209,12 +209,15 @@
"network_pro_terms_conditions" = "Terms and conditions";
"network_pro_paying" = "You are paying:";
"inapp_detail_description" = "• Your payment will be charged to your iTunes account upon confirmation of purchase\n• The subscription is automatically renewed unless the automatic renewal is deactivated at least 24 hours before the end of the current period\n• Subscription will be charged for renewal within 24 hours before the end of the current period and the renewal cost identified\n• Subscriptions can be managed by the user and automatic renewal can be deactivated by accessing the user's account settings after the purchase.";
"inapp_lifetime_detail_description" = "• Your payment will be charged to your iTunes account upon confirmation of purchase";
"inapp_purchase" = "SUBSCRIBE TO SERVICE";
"official_select_country_placeholder" = "Select the country";
"inapp_lifetime_subscriptions" = "Lifetime subscriptions";
"inapp_yearly_subscriptions" = "Annual subscriptions";
"inapp_monthly_subscriptions" = "Monthly subscriptions";
"inapp_monthly_payment" = "you will pay per month:";
"inapp_yearly_payment" = "you will pay per year:";
"inapp_lifetime_payment" = "you will pay:";
"ok" = "Ok";
"critical_alerts_setting" = "Critical alerts. Make a sound also in do not disturb mode";
"attention" = "Attention";
@@ -209,12 +209,15 @@
"network_pro_terms_conditions" = "Términos y condiciones";
"network_pro_paying" = "Estas pagando:";
"inapp_detail_description" = "• Su pago se cargará a su cuenta de iTunes tras la confirmación de la compra\n• La suscripción se renueva automáticamente a menos que la renovación automática se desactive al menos 24 horas antes del final del período actual\n• La suscripción se cobrará por la renovación dentro de las 24 horas antes del final del período actual y el costo de renovación identificado\n• Las suscripciones pueden ser administradas por el usuario y la renovación automática se puede desactivar accediendo a la configuración de la cuenta del usuario después de la compra.";
"inapp_lifetime_detail_description" = "• Su pago se cargará a su cuenta de iTunes tras la confirmación de la compra";
"inapp_purchase" = "SUSCRÍBETE AL SERVICIO";
"official_select_country_placeholder" = "Seleccione el pais";
"inapp_lifetime_subscriptions" = "Suscripciones de por vida";
"inapp_yearly_subscriptions" = "Suscripciones anuales";
"inapp_monthly_subscriptions" = "Suscripciones mensuales";
"inapp_monthly_payment" = "pagarás por mes:";
"inapp_yearly_payment" = "pagarás por año:";
"inapp_lifetime_payment" = "pagarás:";
"ok" = "OK";
"critical_alerts_setting" = "Alertas críticas. Emite un sonido también en el modo no molestar";
"attention" = "Atención";
@@ -209,12 +209,15 @@
"network_pro_terms_conditions" = "Termes et conditions";
"network_pro_paying" = "Vous payez:";
"inapp_detail_description" = "• Votre paiement sera débité de votre compte iTunes lors de la confirmation de l'achat\n• L'abonnement est automatiquement renouvelé sauf si le renouvellement automatique est désactivé au moins 24 heures avant la fin de la période en cours\n• L'abonnement sera facturé pour le renouvellement dans les 24 heures avant la fin de la période en cours et le coût de renouvellement identifié\n• Les abonnements peuvent être gérés par l'utilisateur et le renouvellement automatique peut être désactivé en accédant aux paramètres du compte de l'utilisateur après l'achat.";
"inapp_lifetime_detail_description" = "• Votre paiement sera débité de votre compte iTunes lors de la confirmation de l'achat";
"inapp_purchase" = "ABONNEZ-VOUS AU SERVICE";
"official_select_country_placeholder" = "Sélectionnez le pays";
"inapp_lifetime_subscriptions" = "Abonnements à vie";
"inapp_yearly_subscriptions" = "Abonnements annuels";
"inapp_monthly_subscriptions" = "Abonnements mensuels";
"inapp_monthly_payment" = "vous paierez par mois:";
"inapp_yearly_payment" = "vous paierez par an:";
"inapp_lifetime_payment" = "vous paierez:";
"ok" = "OK";
"critical_alerts_setting" = "Alertes critiques. Émettre un son également en mode Ne pas déranger";
"attention" = "Attention";
@@ -209,12 +209,15 @@
"network_pro_terms_conditions" = "Uvjeti i odredbe";
"network_pro_paying" = "Plaćate:";
"inapp_detail_description" = "• Vaša će uplata biti naplaćena na vaš iTunes račun nakon potvrde kupnje\n• Pretplata se automatski obnavlja, osim ako se automatska obnova ne deaktivira najmanje 24 sata prije kraja tekućeg razdoblja\n • Pretplata će se naplatiti za obnovu u roku od 24 sati prije kraja tekućeg razdoblja i utvrđenih troškova obnove\n • Korisnikom može upravljati pretplatama, a automatskim obnavljanjem može se deaktivirati pristupom postavkama korisničkog računa nakon kupnje.";
"inapp_lifetime_detail_description" = "• Vaša će uplata biti naplaćena na vaš iTunes račun nakon potvrde kupnje";
"inapp_purchase" = "PRETPLATITE SE NA SERVIS";
"official_select_country_placeholder" = "Odaberite zemlju";
"inapp_lifetime_subscriptions" = "Doživotne pretplate";
"inapp_yearly_subscriptions" = "Godišnje pretplate";
"inapp_monthly_subscriptions" = "Mjesečne pretplate";
"inapp_monthly_payment" = "ćete platiti po mjesecu:";
"inapp_yearly_payment" = "ćete platiti godišnje:";
"inapp_lifetime_payment" = "ćete platiti:";
"ok" = "OK";
"critical_alerts_setting" = "Kritična upozorenja. Dajte zvuk i u načinu ne ometaj";
"attention" = "Pažnja";
@@ -209,12 +209,15 @@
"network_pro_terms_conditions" = "Syarat dan ketentuan";
"network_pro_paying" = "Anda membayar:";
"inapp_detail_description" = "• Pembayaran Anda akan dibebankan ke akun iTunes Anda setelah konfirmasi pembelian\n• Langganan diperpanjang secara otomatis kecuali pembaruan otomatis dinonaktifkan setidaknya 24 jam sebelum akhir periode saat ini\n• Langganan akan dikenakan biaya untuk pembaruan dalam waktu 24 jam sebelum akhir periode berjalan dan biaya pembaruan diidentifikasi\n• Langganan dapat dikelola oleh pengguna dan pembaruan otomatis dapat dinonaktifkan dengan mengakses pengaturan akun pengguna setelah pembelian.";
"inapp_lifetime_detail_description" = "• Pembayaran Anda akan dibebankan ke akun iTunes Anda setelah konfirmasi pembelian";
"inapp_purchase" = "BERLANGGANAN LAYANAN";
"official_select_country_placeholder" = "Pilih negaranya";
"inapp_lifetime_subscriptions" = "Langganan seumur hidup";
"inapp_yearly_subscriptions" = "Langganan tahunan";
"inapp_monthly_subscriptions" = "Langganan bulanan";
"inapp_monthly_payment" = "Anda akan membayar per bulan:";
"inapp_yearly_payment" = "Anda akan membayar per tahu:";
"inapp_lifetime_payment" = "Anda akan membayar:";
"ok" = "OK";
"critical_alerts_setting" = "Peringatan kritis. Bersuara juga dalam mode jangan ganggu";
"attention" = "Perhatian";
@@ -209,12 +209,15 @@
"network_pro_terms_conditions" = "Termini e condizioni";
"network_pro_paying" = "Stai pagando:";
"inapp_detail_description" = "• Il pagamento verrà addebitato sul tuo account iTunes alla conferma dell'acquisto\n• L'abbonamento si rinnova automaticamente a meno che il rinnovo automatico non venga disattivato almeno 24 ore prima della fine del periodo corrente\n• L'abbonamento verrà addebitato per il rinnovo entro 24 ore prima della fine del periodo corrente e al costo di rinnovo indicato\n• Gli abbonamenti possono essere gestiti dall'utente e il rinnovo automatico può essere disattivato accedendo alle impostazioni dell'account dell'utente dopo l'acquisto.";
"inapp_lifetime_detail_description" = "• Il pagamento verrà addebitato sul tuo account iTunes alla conferma dell'acquisto";
"inapp_purchase" = "ISCRIVITI AL SERVIZIO";
"official_select_country_placeholder" = "Scegli la nazione";
"inapp_lifetime_subscriptions" = "Abbonamenti a vita";
"inapp_yearly_subscriptions" = "Abbonamenti annuali";
"inapp_monthly_subscriptions" = "Abbonamenti mensili";
"inapp_monthly_payment" = "pagherai al mese:";
"inapp_yearly_payment" = "pagherai all'anno:";
"inapp_lifetime_payment" = "pagherai:";
"ok" = "OK";
"critical_alerts_setting" = "Allerte critiche. Produci un suono anche in modalità non disturbare";
"attention" = "Attenzione";
@@ -209,12 +209,15 @@
"network_pro_terms_conditions" = "Şartlar ve koşullar";
"network_pro_paying" = "Ödüyorsunuz:";
"inapp_detail_description" = "• Satın alma onayının ardından ödemeniz iTunes hesabınızdan tahsil edilecektir\n• Otomatik yenileme, cari dönemin bitiminden en az 24 saat önce devre dışı bırakılmadığı sürece abonelik otomatik olarak yenilenir\n• Abonelik, 24 saat içinde yenileme için ücretlendirilir cari dönemin bitiminden saatler önce ve belirlenen yenileme maliyeti\n• Satın alma işleminden sonra kullanıcının hesap ayarlarına girilerek abonelikler kullanıcı tarafından yönetilebilir ve otomatik yenileme devre dışı bırakılabilir.";
"inapp_lifetime_detail_description" = "• Satın alma onayının ardından ödemeniz iTunes hesabınızdan tahsil edilecektir";
"inapp_purchase" = "HİZMETE ABONE OL";
"official_select_country_placeholder" = "Ülkeyi seçin";
"inapp_lifetime_subscriptions" = "Ömür boyu abonelikler";
"inapp_yearly_subscriptions" = "Yıllık abonelikler";
"inapp_monthly_subscriptions" = "Aylık abonelikler";
"inapp_monthly_payment" = "aylık ödeyeceksiniz:";
"inapp_yearly_payment" = "senelik ödeyeceksin:";
"inapp_lifetime_payment" = "ödeyeceksin:";
"ok" = "OK";
"critical_alerts_setting" = "Kritik uyarılar. Rahatsız etmeyin modunda da ses çıkar";
"attention" = "Dikkat";
+116 -92
View File
@@ -1,96 +1,120 @@
PODS:
- DZNEmptyDataSet (1.8.1)
- Firebase/Core (7.10.0):
- Firebase/Core (9.1.0):
- Firebase/CoreOnly
- FirebaseAnalytics (~> 7.10.0)
- Firebase/CoreOnly (7.10.0):
- FirebaseCore (= 7.10.0)
- Firebase/Crashlytics (7.10.0):
- FirebaseAnalytics (~> 9.1.0)
- Firebase/CoreOnly (9.1.0):
- FirebaseCore (= 9.1.0)
- Firebase/Crashlytics (9.1.0):
- Firebase/CoreOnly
- FirebaseCrashlytics (~> 7.10.0)
- Firebase/Messaging (7.10.0):
- FirebaseCrashlytics (~> 9.1.0)
- Firebase/Messaging (9.1.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 7.10.0)
- FirebaseAnalytics (7.10.0):
- FirebaseCore (~> 7.0)
- FirebaseInstallations (~> 7.0)
- GoogleAppMeasurement (= 7.10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
- GoogleUtilities/MethodSwizzler (~> 7.0)
- GoogleUtilities/Network (~> 7.0)
- "GoogleUtilities/NSData+zlib (~> 7.0)"
- nanopb (~> 2.30908.0)
- FirebaseCore (7.10.0):
- FirebaseCoreDiagnostics (~> 7.4)
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/Logger (~> 7.0)
- FirebaseCoreDiagnostics (7.10.0):
- GoogleDataTransport (~> 8.4)
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/Logger (~> 7.0)
- nanopb (~> 2.30908.0)
- FirebaseCrashlytics (7.10.0):
- FirebaseCore (~> 7.0)
- FirebaseInstallations (~> 7.0)
- GoogleDataTransport (~> 8.4)
- nanopb (~> 2.30908.0)
- PromisesObjC (~> 1.2)
- FirebaseInstallations (7.10.0):
- FirebaseCore (~> 7.0)
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/UserDefaults (~> 7.0)
- PromisesObjC (~> 1.2)
- FirebaseInstanceID (7.10.0):
- FirebaseCore (~> 7.0)
- FirebaseInstallations (~> 7.0)
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/UserDefaults (~> 7.0)
- FirebaseMessaging (7.10.0):
- FirebaseCore (~> 7.0)
- FirebaseInstanceID (~> 7.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/Reachability (~> 7.0)
- GoogleUtilities/UserDefaults (~> 7.0)
- Google-Mobile-Ads-SDK (8.3.0):
- GoogleAppMeasurement (~> 7.0)
- FirebaseMessaging (~> 9.1.0)
- FirebaseAnalytics (9.1.0):
- FirebaseAnalytics/AdIdSupport (= 9.1.0)
- FirebaseCore (~> 9.0)
- FirebaseInstallations (~> 9.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- GoogleUtilities/MethodSwizzler (~> 7.7)
- GoogleUtilities/Network (~> 7.7)
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- FirebaseAnalytics/AdIdSupport (9.1.0):
- FirebaseCore (~> 9.0)
- FirebaseInstallations (~> 9.0)
- GoogleAppMeasurement (= 9.1.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- GoogleUtilities/MethodSwizzler (~> 7.7)
- GoogleUtilities/Network (~> 7.7)
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- FirebaseCore (9.1.0):
- FirebaseCoreDiagnostics (~> 9.0)
- FirebaseCoreInternal (~> 9.0)
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/Logger (~> 7.7)
- FirebaseCoreDiagnostics (9.1.0):
- GoogleDataTransport (< 10.0.0, >= 9.1.4)
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/Logger (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- FirebaseCoreInternal (9.1.0):
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- FirebaseCrashlytics (9.1.0):
- FirebaseCore (~> 9.0)
- FirebaseInstallations (~> 9.0)
- GoogleDataTransport (< 10.0.0, >= 9.1.4)
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (~> 2.1)
- FirebaseInstallations (9.1.0):
- FirebaseCore (~> 9.0)
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/UserDefaults (~> 7.7)
- PromisesObjC (~> 2.1)
- FirebaseMessaging (9.1.0):
- FirebaseCore (~> 9.0)
- FirebaseInstallations (~> 9.0)
- GoogleDataTransport (< 10.0.0, >= 9.1.4)
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/Reachability (~> 7.7)
- GoogleUtilities/UserDefaults (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- Google-Mobile-Ads-SDK (9.6.0):
- GoogleAppMeasurement (< 10.0, >= 7.0)
- GoogleUserMessagingPlatform (>= 1.1)
- GoogleAppMeasurement (7.10.0):
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
- GoogleUtilities/MethodSwizzler (~> 7.0)
- GoogleUtilities/Network (~> 7.0)
- "GoogleUtilities/NSData+zlib (~> 7.0)"
- nanopb (~> 2.30908.0)
- GoogleDataTransport (8.4.0):
- GoogleUtilities/Environment (~> 7.2)
- nanopb (~> 2.30908.0)
- PromisesObjC (~> 1.2)
- GoogleAppMeasurement (9.1.0):
- GoogleAppMeasurement/AdIdSupport (= 9.1.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- GoogleUtilities/MethodSwizzler (~> 7.7)
- GoogleUtilities/Network (~> 7.7)
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- GoogleAppMeasurement/AdIdSupport (9.1.0):
- GoogleAppMeasurement/WithoutAdIdSupport (= 9.1.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- GoogleUtilities/MethodSwizzler (~> 7.7)
- GoogleUtilities/Network (~> 7.7)
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- GoogleAppMeasurement/WithoutAdIdSupport (9.1.0):
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- GoogleUtilities/MethodSwizzler (~> 7.7)
- GoogleUtilities/Network (~> 7.7)
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- GoogleDataTransport (9.1.4):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUserMessagingPlatform (2.0.0)
- GoogleUtilities/AppDelegateSwizzler (7.3.1):
- GoogleUtilities/AppDelegateSwizzler (7.7.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Environment (7.3.1):
- PromisesObjC (~> 1.2)
- GoogleUtilities/Logger (7.3.1):
- GoogleUtilities/Environment (7.7.0):
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.7.0):
- GoogleUtilities/Environment
- GoogleUtilities/MethodSwizzler (7.3.1):
- GoogleUtilities/MethodSwizzler (7.7.0):
- GoogleUtilities/Logger
- GoogleUtilities/Network (7.3.1):
- GoogleUtilities/Network (7.7.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.3.1)"
- GoogleUtilities/Reachability (7.3.1):
- "GoogleUtilities/NSData+zlib (7.7.0)"
- GoogleUtilities/Reachability (7.7.0):
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.3.1):
- GoogleUtilities/UserDefaults (7.7.0):
- GoogleUtilities/Logger
- nanopb (2.30908.0):
- nanopb/decode (= 2.30908.0)
- nanopb/encode (= 2.30908.0)
- nanopb/decode (2.30908.0)
- nanopb/encode (2.30908.0)
- PromisesObjC (1.2.12)
- nanopb (2.30909.0):
- nanopb/decode (= 2.30909.0)
- nanopb/encode (= 2.30909.0)
- nanopb/decode (2.30909.0)
- nanopb/encode (2.30909.0)
- PromisesObjC (2.1.0)
- Solar (2.1.0)
DEPENDENCIES:
@@ -108,9 +132,9 @@ SPEC REPOS:
- FirebaseAnalytics
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseCoreInternal
- FirebaseCrashlytics
- FirebaseInstallations
- FirebaseInstanceID
- FirebaseMessaging
- Google-Mobile-Ads-SDK
- GoogleAppMeasurement
@@ -123,23 +147,23 @@ SPEC REPOS:
SPEC CHECKSUMS:
DZNEmptyDataSet: 9525833b9e68ac21c30253e1d3d7076cc828eaa7
Firebase: fffddd0bab8677d07376538365faa93ff3889b39
FirebaseAnalytics: 4641d7ae4220174f6ca5626163ffc5de2e90391e
FirebaseCore: ec566d917b2195fc2610aeb148dae99f57a788f9
FirebaseCoreDiagnostics: 5662a3823ffcc0acbaa9a21ba5ed302fac634705
FirebaseCrashlytics: e7669d368a22d202f1d0c7546ffdfdff496e1a8c
FirebaseInstallations: bf2ec8dbf36ff4c91af6b9a003d15855757680c1
FirebaseInstanceID: 5ad92c898e1328b66e8dd58811964d6fe4d334c3
FirebaseMessaging: 76b3058cef7f339cf10db196e03bbbb2165fb5d7
Google-Mobile-Ads-SDK: c14f5a63db1414b4ca0ee1539c9f3d700ace96c2
GoogleAppMeasurement: 1c863b1161fc3c8cf614a7460d1be6a7c262aab3
GoogleDataTransport: cd9db2180fcecd8da1b561aea31e3e56cf834aa7
Firebase: 91c243d75573ac6e7c9735ec859b72bffb61347d
FirebaseAnalytics: bf11064790ac96804df1df9ddc0ae45af950d9fc
FirebaseCore: b7bfc258e996eada23b3666bd6b9a22ca092acb8
FirebaseCoreDiagnostics: 2dabba3412b23b524823325739f45e520f67d1e7
FirebaseCoreInternal: f3c838ae0b41cd840bbf34f90debfede78d352e5
FirebaseCrashlytics: 8e21736dcf15d814b79229eb7e79ba3a5eec5f30
FirebaseInstallations: a91c74276b544524ce144c8315d8cdbce2dbe30b
FirebaseMessaging: 0bf5caa621182ccc66ba3be3b15e68d800d98e9f
Google-Mobile-Ads-SDK: bdf13d37aa77e368510687b5305d4972b4f9e9c7
GoogleAppMeasurement: 8ecc717f2abe3f9ee95a5d38db08827852894acc
GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b
GoogleUserMessagingPlatform: ab890ce5f6620f293a21b6bdd82e416a2c73aeca
GoogleUtilities: e1d9ed4e544fc32a93e00e721400cbc3f377200d
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72
Solar: 2dc6e7cc39186cb0c8228fa08df76fb50c7d8f24
PODFILE CHECKSUM: dd5131b6d7a83fb7c22ecc161ed4fc143eda0ac1
COCOAPODS: 1.10.1
COCOAPODS: 1.11.3
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB