Compare commits

...

39 Commits

Author SHA1 Message Date
Andrea Busi 6be5f72360 release: Increase version for release 2024-07-16 11:45:52 +02:00
Andrea Busi ccd1b9de59 dependency: Update Firebase 2024-07-16 11:45:43 +02:00
Andrea Busi 5737eb5b02 feat: Sort user subscriptions (top10k first) 2024-07-16 11:43:58 +02:00
Andrea Busi c549bb6ea5 fix: Solve wrong localized AR string 2024-07-16 09:23:39 +02:00
Andrea Busi ff80905033 fix: Solve crash due to wrong string format 2024-07-16 09:09:57 +02:00
Andrea Busi dad2bc5648 release: Increase version for release 2024-07-08 15:04:01 +02:00
Andrea Busi 10c74e278e refactor: Rework layout for restore subscriptions 2024-07-08 13:51:54 +02:00
Andrea Busi 96dbf960d2 refactor: Change tab official translations 2024-07-08 13:51:39 +02:00
Andrea Busi 81bfdd02a6 release: Increase version for release 2024-07-05 11:51:52 +02:00
Andrea Busi 2ab3267981 dependency: SPM 2024-07-05 11:45:29 +02:00
Andrea Busi 48b6941ed5 feat: Change nav bar color 2024-07-05 11:45:23 +02:00
Andrea Busi 669cb3c4f3 fix: Improve translation 2024-07-05 11:40:52 +02:00
Andrea Busi 638d819d35 refactor: Improve log 2024-07-05 09:03:48 +02:00
Andrea Busi a9884d8a8d release: Increase version for release 2024-07-04 15:22:58 +02:00
Andrea Busi 2ef3560011 feat: Scroll to opened seismic 2024-07-04 15:20:05 +02:00
Andrea Busi 05093bb7a4 chore: Update push payloads 2024-07-04 15:19:55 +02:00
Andrea Busi 55f84ab46d feat: Add new string for notification body 2024-07-04 15:19:45 +02:00
Andrea Busi 03b4d0ddd6 feat: Show right arrow to priority cell 2024-07-03 11:18:50 +02:00
Andrea Busi 3c5f26bc94 fix: Set background color to the proper container 2024-07-03 11:18:41 +02:00
Andrea Busi 8c79d45b19 release: Increase version for release 2024-07-03 10:10:37 +02:00
Andrea Busi 931d04c5e1 refactor: Reorganize files 2024-07-03 10:10:04 +02:00
Andrea Busi 4d62fbbbd3 fix: Solve wrong distance in filter evaluation 2024-07-03 10:00:55 +02:00
Andrea Busi 1c7065ece7 release: Increase version for release 2024-07-02 20:59:37 +02:00
Andrea Busi 6dfa51e013 refactor: Bigger fonts 2024-07-02 19:13:10 +02:00
Andrea Busi b8b21d1458 fix: Remove separator from table view 2024-07-02 18:15:03 +02:00
Andrea Busi 88317f79e8 fix: Missing rounded corners 2024-07-02 17:57:01 +02:00
Andrea Busi 4e1147e782 refactor: Remove no longer used class 2024-07-02 17:56:55 +02:00
Andrea Busi 579969d507 fix: Missing callback 2024-07-02 17:55:25 +02:00
Andrea Busi 4d991d9a10 refactor: Recreate expanded notification cell via code and change some UI elements 2024-07-02 17:55:19 +02:00
Andrea Busi 41491b5ee7 refactor: Change colors as per specifications 2024-07-02 12:25:18 +02:00
Andrea Busi 197b375c28 refactor: Remove setting for filter type in seismic notifications 2024-07-01 11:18:47 +02:00
Andrea Busi f41e6b50ec refactor: Create UI in code to properly manage filter view 2024-07-01 10:40:50 +02:00
Andrea Busi 796e4b5895 release: Increase version for release 2024-07-01 10:40:26 +02:00
Andrea Busi e43a93979d fix: Solve layout issue with gradient background 2024-06-29 16:16:47 +02:00
Andrea Busi ef1aaa7d71 refactor: Use extension for view rounded corners and shadow 2024-06-29 16:16:47 +02:00
Andrea Busi 22d78baa8a feat: Highlight seismic card title for push notification
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/76
2024-06-29 16:16:47 +02:00
Andrea Busi e4588aa731 chore: Update payload for official push notification 2024-06-29 16:16:47 +02:00
Andrea Busi 07764f91ed feat: Add logic to update filter when push is opened
Resolves: https://gitlab.steamware.net/eqn/eqn.ios/-/issues/76
2024-06-29 16:16:47 +02:00
Andrea Busi a0a238e384 refactor" Don't show image for official notifications 2024-06-27 18:19:30 +02:00
41 changed files with 945 additions and 575 deletions
+4
View File
@@ -1,5 +1,9 @@
# Changelog
## Versione 5.8.1
- Corrette traduzioni errate (causavano crash)
- Aggiunto ordinamento in sottoscrizioni utente (prima Top10k)
## Versione 5.8
- Modifica algoritmo filtro lista (issue #70)
- Modifica impostazioni "Notifiche da reti sismiche" (issue #66)
+20 -18
View File
@@ -1,32 +1,34 @@
{
"Simulator Target Bundle": "com.finazzi.distquake",
"magnitude_range" : "0",
"provider" : "SGC",
"google.c.a.e" : "1",
"google.c.fid" : "d3PS1dEvrUA-tmLLpl5E5f",
"provider" : "INGV",
"google.c.fid" : "fFjFx_Em8E-op_zHYXZpSr",
"preliminary" : "0",
"longitude" : "-75.5157",
"gcm.message_id" : "1668682445010677",
"latitude" : "4.35306",
"type" : "official",
"longitude" : "15.2917",
"gcm.message_id" : "1719991146578422",
"latitude" : "40.7738",
"google.c.sender.id" : "899482329945",
"difference" : "6",
"data" : "2022-11-17 11:48:00",
"depth" : "26",
"type" : "official",
"magnitude" : "1.4",
"difference" : "13",
"depth" : "14.6",
"aps" : {
"content-available" : 1,
"mutable-content" : 1,
"alert" : {
"loc-key" : "Sisma rilevato a",
"body" : "Sisma rilevato a",
"title-loc-key" : "Segnalazione da rete sismica",
"title" : "Segnalazione da rete sismica",
"loc-key" : "Sisma rilevato a",
"action-loc-key" : "",
"loc-args" : [
"Cajamarca - Tolima, Colombia - M2.2"
"2 km SW Laviano (SA) - M1.4"
]
},
"mutable-content" : 1,
"content-available" : 1,
"sound" : "default"
},
"magnitude" : "2.2",
"magnitude_type" : "M",
"place" : "Cajamarca - Tolima, Colombia",
"pop100" : "6622"
"data" : "2024-07-03 09:05:52",
"magnitude_type" : "ML",
"place" : "2 km SW Laviano (SA)",
"pop100" : "6824"
}
@@ -5,7 +5,7 @@
"loc-args": [
"2 km da Foligno"
],
"loc-key": "Rilevato sisma forte a",
"loc-key": "Sisma segnalato da utente a",
"title-loc-key": "Allerta sismica in tempo reale"
},
"category": "notifica_con_mappa",
@@ -97,23 +97,8 @@ class NotificationService: UNNotificationServiceExtension {
// use a generic warning icon instead
iconName = "warning_yellow.png"
case "official":
let provider = userInfo.string(forKey: "provider", orDefault: "")
let intensity = userInfo.double(forKey: "magnitude", orDefault: 0)
let color: String
if intensity < 2.0 {
color = "_white"
} else if intensity < 3.5 {
color = "_green"
} else if intensity < 4.5 {
color = "_yellow"
} else if intensity < 5.5 {
color = "_red"
} else {
color = "_purple"
}
iconName = manualIconName(for: provider, color: color)
// don't show any images
break
default:
break
}
@@ -45,8 +45,8 @@
658BAB7B25FE67930015C454 /* EQNBaseMapRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BAB7A25FE67930015C454 /* EQNBaseMapRepresentable.swift */; };
658BC0292859A456009EECAA /* RealtimeAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BC0282859A456009EECAA /* RealtimeAlertViewController.swift */; };
658BC02B2859A4D3009EECAA /* RealtimeAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BC02A2859A4D3009EECAA /* RealtimeAlertView.swift */; };
6590EFF82C3004EA00F41420 /* EQNOfficialPushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6590EFF72C3004EA00F41420 /* EQNOfficialPushNotification.swift */; };
65AB4A952C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AB4A942C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift */; };
65AB4A972C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AB4A962C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift */; };
65AB4A992C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AB4A982C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift */; };
65AD23CE261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AD23CD261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift */; };
65B16E1E2BDFA88D0020527E /* Solar in Frameworks */ = {isa = PBXBuildFile; productRef = 65B16E1D2BDFA88D0020527E /* Solar */; };
@@ -246,7 +246,6 @@
DC99A50324E66E270071BC9F /* EQNCommandProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC99A50224E66E270071BC9F /* EQNCommandProtocol.swift */; };
DC99A50524E66E430071BC9F /* EQNAppearanceCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC99A50424E66E430071BC9F /* EQNAppearanceCommand.swift */; };
DC99A50724E66E5F0071BC9F /* EQNStartupCommandsBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC99A50624E66E5F0071BC9F /* EQNStartupCommandsBuilder.swift */; };
DCA5B6E7252E4BD8002AEC96 /* EQNBaseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA5B6E6252E4BD8002AEC96 /* EQNBaseTableViewCell.swift */; };
DCAA913F24F68A1D00145A3D /* SettingMultivaluesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAA913E24F68A1D00145A3D /* SettingMultivaluesTableViewCell.swift */; };
DCB28CEE24FB8400001F557E /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB28CED24FB8400001F557E /* SettingsViewController.swift */; };
DCB528212560161C005288E5 /* AlertSimulatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB528202560161C005288E5 /* AlertSimulatorViewController.swift */; };
@@ -345,6 +344,7 @@
658BC02A2859A4D3009EECAA /* RealtimeAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealtimeAlertView.swift; sourceTree = "<group>"; };
658F19692A0D1F8F00BECC05 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = "<group>"; };
658F196A2A0D1F8F00BECC05 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
6590EFF72C3004EA00F41420 /* EQNOfficialPushNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNOfficialPushNotification.swift; sourceTree = "<group>"; };
65A4D5AA26280A24003918E0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
65A4D5AB26280A24003918E0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
65A4D5AC26280A56003918E0 /* el-GR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "el-GR"; path = "el-GR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
@@ -356,7 +356,6 @@
65A4D5B526281126003918E0 /* id-ID */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "id-ID"; path = "id-ID.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
65A4D5B626281126003918E0 /* id-ID */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "id-ID"; path = "id-ID.lproj/Localizable.strings"; sourceTree = "<group>"; };
65AB4A942C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSeismicNetworkNotificationsViewController.swift; sourceTree = "<group>"; };
65AB4A962C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSeismicNetworkNotificationsFilterViewController.swift; sourceTree = "<group>"; };
65AB4A982C11DFC200950DF7 /* EQNSettingSeismicNetworkNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNSettingSeismicNetworkNotification.swift; sourceTree = "<group>"; };
65AD23CD261B03D400E3B57C /* SubscriptionsDescriptionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsDescriptionTableViewCell.swift; sourceTree = "<group>"; };
65BBB22B26064BE6005D6CDF /* SegnalazioniLast24HoursCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegnalazioniLast24HoursCell.swift; sourceTree = "<group>"; };
@@ -574,7 +573,6 @@
DC99A50224E66E270071BC9F /* EQNCommandProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNCommandProtocol.swift; sourceTree = "<group>"; };
DC99A50424E66E430071BC9F /* EQNAppearanceCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNAppearanceCommand.swift; sourceTree = "<group>"; };
DC99A50624E66E5F0071BC9F /* EQNStartupCommandsBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNStartupCommandsBuilder.swift; sourceTree = "<group>"; };
DCA5B6E6252E4BD8002AEC96 /* EQNBaseTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EQNBaseTableViewCell.swift; sourceTree = "<group>"; };
DCAA913E24F68A1D00145A3D /* SettingMultivaluesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingMultivaluesTableViewCell.swift; sourceTree = "<group>"; };
DCB28CED24FB8400001F557E /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
DCB528202560161C005288E5 /* AlertSimulatorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertSimulatorViewController.swift; sourceTree = "<group>"; };
@@ -1114,6 +1112,7 @@
8CF4F4DA216D44930057110B /* EQNPastquakes.m */,
65EA58812A60360D0038EE9D /* EQNRealtimePushNotification.swift */,
6552C1452926DBA1008E723C /* AppPreferences.swift */,
6590EFF72C3004EA00F41420 /* EQNOfficialPushNotification.swift */,
);
path = Models;
sourceTree = "<group>";
@@ -1141,13 +1140,12 @@
DCC23DED24D28F41003A2404 /* UI */ = {
isa = PBXGroup;
children = (
DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */,
DCC23DEE24D28F58003A2404 /* EQNEdgeInsetLabel.swift */,
DC03BEAA250BC0A60084769B /* EQNRoundedButton.swift */,
DC52B8A424FCCD6900ABEBA6 /* AppTheme.swift */,
DCA5B6E6252E4BD8002AEC96 /* EQNBaseTableViewCell.swift */,
6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */,
656E02152C1C4DF2008D0E92 /* EQNBaseContainerTableViewCell.swift */,
653C67E125F3CC2E00FE52AC /* EQNCustomAnnotationView.swift */,
6586971025F44C26009C0182 /* EQNBlurredCloseButton.swift */,
65172F522C25C496006D2A5C /* EQNSeismicAnnotationView.swift */,
);
path = UI;
@@ -1175,7 +1173,6 @@
65DB60EF2C16F5B100164366 /* SettingsBaseTableViewController.swift */,
65DB60F92C17158D00164366 /* SettingsUserReportNotificationsViewController.swift */,
65AB4A942C11BED400950DF7 /* SettingsSeismicNetworkNotificationsViewController.swift */,
65AB4A962C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift */,
65DB60F12C16FA3600164366 /* SettingsRealTimeAlertsViewController.swift */,
);
path = Settings;
@@ -1574,8 +1571,8 @@
6562C80725FFA6B100C85273 /* SeismicNetworkViewModel.swift in Sources */,
DCDE0BD924E58CCE00209778 /* EQNMainTabBarController.m in Sources */,
8C4E344B2152EE5B008B0D2A /* EQNGeneratoreURLServer.m in Sources */,
6590EFF82C3004EA00F41420 /* EQNOfficialPushNotification.swift in Sources */,
DC99A50724E66E5F0071BC9F /* EQNStartupCommandsBuilder.swift in Sources */,
DCA5B6E7252E4BD8002AEC96 /* EQNBaseTableViewCell.swift in Sources */,
8CF66058214C566B009F4314 /* ServerRequest.m in Sources */,
DCF9E14D24F6D1AA002B6B1D /* EQNData.swift in Sources */,
DC52B8A524FCCD6900ABEBA6 /* AppTheme.swift in Sources */,
@@ -1607,7 +1604,6 @@
65BBB22C26064BE6005D6CDF /* SegnalazioniLast24HoursCell.swift in Sources */,
DC47D1BC252A0C2B004119F6 /* AlertsPastEartquakesTableViewCell.swift in Sources */,
654D18C925F93CD700BB6DB0 /* EQNMapAnnotationPastquake.swift in Sources */,
65AB4A972C11DEB300950DF7 /* SettingsSeismicNetworkNotificationsFilterViewController.swift in Sources */,
DCEFF21724F58569009D3FE1 /* SettingSectionHeaderView.swift in Sources */,
65DB60FD2C172C4A00164366 /* EQNSettingRealTimeAlert.swift in Sources */,
DCBB267A24D1E7F500F04559 /* SubscriptionsHeaderTableViewCell.swift in Sources */,
@@ -1777,7 +1773,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 129;
CURRENT_PROJECT_VERSION = 136;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WJA4MR4CPC;
GCC_PREPROCESSOR_DEFINITIONS = (
@@ -1794,7 +1790,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationservice;
@@ -1819,7 +1815,7 @@
CODE_SIGN_IDENTITY = "Apple Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 129;
CURRENT_PROJECT_VERSION = 136;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WJA4MR4CPC;
GENERATE_INFOPLIST_FILE = YES;
@@ -1832,7 +1828,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationservice;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1974,7 +1970,7 @@
CODE_SIGN_ENTITLEMENTS = "Earthquake Network/Earthquake Network.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 129;
CURRENT_PROJECT_VERSION = 136;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = WJA4MR4CPC;
@@ -1985,7 +1981,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -2061,7 +2057,7 @@
CODE_SIGN_ENTITLEMENTS = "Earthquake Network/Earthquake Network.entitlements";
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 129;
CURRENT_PROJECT_VERSION = 136;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = WJA4MR4CPC;
GCC_PREFIX_HEADER = "Earthquake Network/Earthquake Network-Prefix.pch";
@@ -2071,7 +2067,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -2144,7 +2140,7 @@
CODE_SIGN_ENTITLEMENTS = EQNNotificationContent/EQNNotificationContent.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 129;
CURRENT_PROJECT_VERSION = 136;
DEVELOPMENT_TEAM = WJA4MR4CPC;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -2159,7 +2155,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationcontent;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Content - Development";
@@ -2178,7 +2174,7 @@
CODE_SIGN_ENTITLEMENTS = EQNNotificationContent/EQNNotificationContent.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 129;
CURRENT_PROJECT_VERSION = 136;
DEVELOPMENT_TEAM = WJA4MR4CPC;
GCC_PREPROCESSOR_DEFINITIONS = (
"ADS_ENABLED=0",
@@ -2191,7 +2187,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
PRODUCT_BUNDLE_IDENTIFIER = com.finazzi.distquake.notificationcontent;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "EQNetwork Extension Content - AppStore";
@@ -1,5 +1,5 @@
{
"originHash" : "702893df2780e15a380fe3df120a583fefc365501dca7487eaf0c2b967baf71c",
"originHash" : "c29b9b16ee6b4d1a6fec2debc59749097860256c8cbb2addc2abc08d3adba59d",
"pins" : [
{
"identity" : "abseil-cpp-binary",
@@ -42,8 +42,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk.git",
"state" : {
"revision" : "e57841b296d04370ea23580f908881b0ccab17b9",
"version" : "10.28.1"
"revision" : "eca84fd638116dd6adb633b5a3f31cc7befcbb7d",
"version" : "10.29.0"
}
},
{
+10 -8
View File
@@ -170,20 +170,22 @@
{
NSString *type = content.userInfo[@"type"];
// Store both original payload and modified title/body
// This will be usefull to avoid to re-evaluate logic for title display.
NSDictionary *notification = @{
@"title": content.title,
@"body": content.body,
@"userInfo": content.userInfo
};
EQNTabBarSection section = EQNTabBarSectionAllerte;
if ([type isEqualToString:@"eqn"]) {
// Store both original payload and modified title/body
// This will be usefull to avoid to re-evaluate logic for title display.
NSDictionary *notification = @{
@"title": content.title,
@"body": content.body,
@"userInfo": content.userInfo
};
if ([type isEqualToString:@"eqn"]) {
[EQNRealtimePushNotification storeNotificationWithPayload:notification];
section = EQNTabBarSectionAllerte;
} else if([type isEqualToString:@"manual"]) {
section = EQNTabBarSectionSegnalazioni;
} else if([type isEqualToString:@"official"]) {
[EQNOfficialPushNotification storeNotificationWithPayload:notification];
section = EQNTabBarSectionRetiSismiche;
}
@@ -69,6 +69,8 @@ extension UserDefaults {
// Notifica allerta salvata
static let RealTimeAlertPayload = "EQNData.RealtimePushNotificationPayload"
static let RealTimeAlertDate = "EQNData.RealtimeAlertDate"
// Notifica rete sismica aperta
static let OfficialAlertPayload = "EQNData.OfficialPushNotificationPayload"
// Filtri sezioni reti sismiche
static let SeismicFilterOption = "EQN_SISMI_TIPOLOGIA_FILTRO"
@@ -106,7 +106,8 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
[self.tableView registerClass:[AlertsPriorityServiceTableViewCell class] forCellReuseIdentifier:@"PriorityCell"];
[self.tableView registerClass:[AlertsNoLocationTableViewCell class] forCellReuseIdentifier:@"NoLocationCell"];
[self.tableView registerClass:[AlertsPastEartquakesTableViewCell class] forCellReuseIdentifier:@"PastEarthquakesCell"];
[self.tableView registerClass:[AlertsSeismicNotificationCompactTableViewCell class] forCellReuseIdentifier:@"SeismicNotificationCell"];
[self.tableView registerClass:[AlertsSeismicNotificationCompactTableViewCell class] forCellReuseIdentifier:@"SeismicNotificationCompactCell"];
[self.tableView registerClass:[AlertsSeismicNotificationExpandedTableViewCell class] forCellReuseIdentifier:@"SeismicNotificationExpandedCell"];
[self.tableView registerClass:[AlertsPositionDataTableViewCell class] forCellReuseIdentifier:@"PositionDataCell"];
if (EQNBackgroundPositionDebugHelper.shared.isEnabled) {
@@ -278,7 +279,7 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
AlertsSeismicNotificationExpandedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SeismicNotificationExpandedCell" forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
EQNRealtimePushNotification *notification = [EQNRealtimePushNotification storedNotification];
cell.notification = notification;
[cell updateWith:notification];
__weak AllerteViewController *weakSelf = self;
cell.onTapClose = ^{
@@ -297,7 +298,7 @@ typedef NS_ENUM(NSInteger, AllerteTableRow) {
return cell;
}
AlertsSeismicNotificationCompactTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SeismicNotificationCell" forIndexPath:indexPath];
AlertsSeismicNotificationCompactTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SeismicNotificationCompactCell" forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
__weak AllerteViewController *weakSelf = self;
@@ -12,6 +12,7 @@ import UIKit
class AlertsPriorityServiceTableViewCell: EQNBaseContainerTableViewCell {
override var headerText: String { NSLocalizedString("inapp_list", comment: "") }
override var isRightArrowVisbile: Bool { true }
// MARK: - UI
@@ -28,7 +29,7 @@ class AlertsPriorityServiceTableViewCell: EQNBaseContainerTableViewCell {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textColor = AppTheme.Colors.red
label.textColor = AppTheme.Colors.pureRed
label.font = .preferredFont(forTextStyle: .body)
return label
}()
@@ -54,7 +55,7 @@ class AlertsPriorityServiceTableViewCell: EQNBaseContainerTableViewCell {
override func updateUI() {
super.updateUI()
containerView.backgroundColor = AppTheme.Colors.cardBackgroundRed
backgroundColor = AppTheme.Colors.cardBackgroundOrange
descriptionLabel.text = NSLocalizedString("inapp_adv", comment: "")
}
@@ -92,7 +92,7 @@ class AlertsSeismicNotificationCompactTableViewCell: EQNBaseContainerTableViewCe
override func updateUI() {
super.updateUI()
containerView.backgroundColor = AppTheme.Colors.cardBackgroundGreen
backgroundColor = AppTheme.Colors.cardBackgroundGreen
descriptionLabel.text = NSLocalizedString("main_nodetection", comment: "")
testAlertButton.setLocalizedTitle(key: "main_alerttest", uppercased: true, emoji: "🚨")
simulatorAlertButton.setLocalizedTitle(key: "main_simulator", uppercased: true, emoji: "")
@@ -10,78 +10,173 @@ import UIKit
import MapKit
import Shogun
class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMapViewDelegate {
class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseContainerTableViewCell, MKMapViewDelegate {
override var isHeaderVisible: Bool { false }
typealias DefaultCompletion = () -> Void
@objc var notification: EQNRealtimePushNotification? {
didSet {
updateUI()
}
}
@objc var onTapOpenTwitter: DefaultCompletion?
@objc var onTapRateApp: DefaultCompletion?
@objc var onTapClose: DefaultCompletion?
@objc var onTapShareApp: DefaultCompletion?
// MARK: - UI
private lazy var notificationTitleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textColor = AppTheme.shared.cardTextColor
label.font = .preferredFont(forTextStyle: .title1)
label.textAlignment = .center
return label
}()
private lazy var notificationIntensityLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textColor = AppTheme.shared.cardTextColor
label.font = .preferredFont(forTextStyle: .title1)
label.textAlignment = .center
return label
}()
private lazy var notificationDescriptionLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textColor = AppTheme.shared.cardTextColor
label.font = .preferredFont(forTextStyle: .body)
label.textAlignment = .center
return label
}()
private lazy var mapView: MKMapView = {
let mapView = MKMapView()
mapView.translatesAutoresizingMaskIntoConstraints = false
mapView.delegate = self
mapView.isScrollEnabled = false
mapView.isZoomEnabled = false
mapView.register(EQNCustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SingleLineIdentifier)
return mapView
}()
private lazy var shareButton: UIButton = {
let button = EQNRoundedButton.make(target: self, action: #selector(shareAppTapped(_:)))
return button
}()
private lazy var rateAppButton: UIButton = {
let button = EQNRoundedButton.make(target: self, action: #selector(rateAppTapped(_:)))
return button
}()
private lazy var viewOnTwitterButton: UIButton = {
let button = EQNRoundedButton.make(target: self, action: #selector(viewInTwitterTapped(_:)))
return button
}()
private lazy var closeButton: UIButton = {
let button = EQNRoundedButton.make(target: self, action: #selector(closeTapped(_:)))
return button
}()
private lazy var descriptionLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textColor = AppTheme.shared.cardTextColor
label.font = .preferredFont(forTextStyle: .body)
label.textAlignment = .center
return label
}()
// MARK: - Internal
@IBOutlet weak var notificationTitleLabel: UILabel!
@IBOutlet weak var notificationDescriptionLabel: UILabel!
@IBOutlet weak var notificationIntensityLabel: UILabel!
@IBOutlet weak var waveTimeLabel: UILabel!
@IBOutlet weak var mapView: MKMapView! {
didSet {
mapView.delegate = self
mapView.isScrollEnabled = false
mapView.isZoomEnabled = false
mapView.register(EQNCustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: EQNCustomAnnotationView.SingleLineIdentifier)
}
}
@IBOutlet private weak var shareButton: UIButton!
@IBOutlet private weak var rateAppButton: UIButton!
@IBOutlet private weak var viewOnTwitterButton: UIButton!
@IBOutlet private weak var closeButton: UIButton!
@IBOutlet private weak var descriptionLabel: UILabel!
private var impactTimestamp: Date?
private var countdownTimer: Timer?
// MARK: - View Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
override func setupUI() {
super.setupUI()
localizeUI()
setUI()
let stackView = UIStackView(arrangedSubviews: [shareButton, rateAppButton])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.distribution = .fillEqually
stackView.spacing = .cardVerticalSpacing
containerView.addSubview(notificationTitleLabel)
containerView.addSubview(notificationIntensityLabel)
containerView.addSubview(notificationDescriptionLabel)
containerView.addSubview(mapView)
containerView.addSubview(stackView)
containerView.addSubview(viewOnTwitterButton)
containerView.addSubview(descriptionLabel)
containerView.addSubview(closeButton)
notificationTitleLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: .cardPadding).isActive = true
notificationTitleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
notificationTitleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
notificationIntensityLabel.topAnchor.constraint(equalTo: notificationTitleLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
notificationIntensityLabel.leadingAnchor.constraint(equalTo: notificationTitleLabel.leadingAnchor).isActive = true
notificationIntensityLabel.trailingAnchor.constraint(equalTo: notificationTitleLabel.trailingAnchor).isActive = true
notificationDescriptionLabel.topAnchor.constraint(equalTo: notificationIntensityLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
notificationDescriptionLabel.leadingAnchor.constraint(equalTo: notificationTitleLabel.leadingAnchor).isActive = true
notificationDescriptionLabel.trailingAnchor.constraint(equalTo: notificationTitleLabel.trailingAnchor).isActive = true
mapView.topAnchor.constraint(equalTo: notificationDescriptionLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
mapView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
mapView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
mapView.heightAnchor.constraint(greaterThanOrEqualToConstant: 240.0).isActive = true
shareButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 40.0).isActive = true
rateAppButton.heightAnchor.constraint(equalTo: shareButton.heightAnchor).isActive = true
viewOnTwitterButton.heightAnchor.constraint(equalTo: shareButton.heightAnchor).isActive = true
closeButton.heightAnchor.constraint(equalTo: shareButton.heightAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: mapView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
stackView.leadingAnchor.constraint(equalTo: notificationDescriptionLabel.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: notificationDescriptionLabel.trailingAnchor).isActive = true
viewOnTwitterButton.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
viewOnTwitterButton.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true
viewOnTwitterButton.trailingAnchor.constraint(equalTo: stackView.trailingAnchor).isActive = true
descriptionLabel.topAnchor.constraint(equalTo: viewOnTwitterButton.bottomAnchor, constant: .cardPadding).isActive = true
descriptionLabel.leadingAnchor.constraint(equalTo: viewOnTwitterButton.leadingAnchor).isActive = true
descriptionLabel.trailingAnchor.constraint(equalTo: viewOnTwitterButton.trailingAnchor).isActive = true
closeButton.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
closeButton.leadingAnchor.constraint(equalTo: descriptionLabel.leadingAnchor).isActive = true
closeButton.trailingAnchor.constraint(equalTo: descriptionLabel.trailingAnchor).isActive = true
closeButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: .cardVerticalSpacing.negative).isActive = true
}
// MARK: - Private
private func localizeUI() {
override func updateUI() {
super.updateUI()
shareButton.setLocalizedTitle(key: "main_share_app")
rateAppButton.setLocalizedTitle(key: "main_vote")
viewOnTwitterButton.setLocalizedTitle(key: "main_twitter_see")
closeButton.setLocalizedTitle(key: "official_close")
descriptionLabel.text = NSLocalizedString("map_smartphone_magnitude", comment: "")
}
// MARK: - Public
private func setUI() {
shareButton.layer.borderColor = AppTheme.Colors.darkGray.cgColor
rateAppButton.layer.borderColor = AppTheme.Colors.darkGray.cgColor
viewOnTwitterButton.layer.borderColor = AppTheme.Colors.darkGray.cgColor
closeButton.layer.borderColor = AppTheme.Colors.darkGray.cgColor
}
private func updateUI() {
@objc
func update(with notification: EQNRealtimePushNotification?) {
// clearn any other previous notifications
notificationTitleLabel.text = ""
notificationDescriptionLabel.text = ""
notificationTitleLabel.text = "Sisma rilevato a 150km (TEST)"
notificationIntensityLabel.text = "Previsto uno scuotimento forte"
notificationDescriptionLabel.text = "Distanza 150 km - 13 minuti fa"
mapView.removeAnnotations(mapView.annotations)
guard let notification = notification else { return }
containerView.backgroundColor = backgroundColor(for: notification.relativeIntensity())
backgroundColor = backgroundColor(for: notification.relativeIntensity())
notificationTitleLabel.text = notification.title
notificationIntensityLabel.text = notification.displayBody
notificationIntensityLabel.textColor = notification.relativeIntensityColor
@@ -95,7 +190,6 @@ class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMa
notificationDescriptionLabel.text = ""
+ NSLocalizedString("official_card_distance", comment: "") + " \(distanceRound) km"
+ " - " + EQNUtility.formattedString(forTimeDifference: difference)
+ "\n" + String(format: NSLocalizedString("map_number", comment: ""), "\(notification.counter)")
}
let span = MKCoordinateSpan(latitudeDelta: 10.5, longitudeDelta: 10.5)
@@ -118,37 +212,37 @@ class AlertsSeismicNotificationExpandedTableViewCell: EQNBaseTableViewCell, MKMa
annotationView.title = annotation.title
return annotationView
}
// MARK: - Actions
@IBAction private func shareAppTapped(_ sender: UIButton) {
@objc private func shareAppTapped(_ sender: UIButton) {
onTapShareApp?()
}
@IBAction private func rateAppTapped(_ sender: UIButton) {
@objc private func rateAppTapped(_ sender: UIButton) {
onTapRateApp?()
}
@IBAction private func viewInTwitterTapped(_ sender: UIButton) {
@objc private func viewInTwitterTapped(_ sender: UIButton) {
onTapOpenTwitter?()
}
@IBAction private func closeTapped(_ sender: UIButton) {
@objc private func closeTapped(_ sender: UIButton) {
onTapClose?()
}
// MARK: - Helpers
// MARK: - Private
private func backgroundColor(for intensity: Double) -> UIColor {
switch intensity {
case _ where intensity < 0.004:
return UIColor(named: "Gray (card background)")!
return AppTheme.Colors.cardBackgroundGray
case _ where intensity < 0.30:
return UIColor(named: "Green (card background)")!
return AppTheme.Colors.cardBackgroundGreen
case _ where intensity < 0.70:
return UIColor(named: "Yellow (card background)")!
return AppTheme.Colors.cardBackgroundYellow
default:
return UIColor(named: "Red (card background)")!
return AppTheme.Colors.cardBackgroundRed
}
}
}
@@ -14,6 +14,8 @@ class SubscriptionsActiveTableViewCell: EQNBaseContainerTableViewCell {
override var headerText: String { NSLocalizedString("inapp_active", comment: "") }
var onTapRestore: () -> Void = { }
// MARK: - UI
private lazy var noSubscriptionsLabel: UILabel = {
@@ -32,22 +34,36 @@ class SubscriptionsActiveTableViewCell: EQNBaseContainerTableViewCell {
imageView.contentMode = .scaleAspectFit
return imageView
}()
private lazy var restoreButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(restoreSubscriptionsTapped(_:)), for: .touchUpInside)
button.titleLabel?.font = .preferredFont(forTextStyle: .headline)
button.backgroundColor = .systemGroupedBackground
button.eqn_applyShadowAndRoundedCorners()
return button
}()
// MARK: - Internal
override func setupUI() {
super.setupUI()
let stackView = UIStackView(arrangedSubviews: [ activeSubscriptionImageView, noSubscriptionsLabel ])
let stackView = UIStackView(arrangedSubviews: [ activeSubscriptionImageView, noSubscriptionsLabel, restoreButton ])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.alignment = .center
stackView.distribution = .equalSpacing
stackView.axis = .vertical
stackView.spacing = 20.0
containerView.addSubview(stackView)
activeSubscriptionImageView.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
activeSubscriptionImageView.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
restoreButton.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
restoreButton.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true
restoreButton.trailingAnchor.constraint(equalTo: stackView.trailingAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: .cardVerticalSpacing).isActive = true
stackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: .cardPadding).isActive = true
stackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: .cardPadding.negative).isActive = true
@@ -58,6 +74,13 @@ class SubscriptionsActiveTableViewCell: EQNBaseContainerTableViewCell {
super.updateUI()
noSubscriptionsLabel.text = NSLocalizedString("inapp_nosub", comment: "")
restoreButton.setTitle(NSLocalizedString("purchase_pro_restore", comment: ""), for: .normal)
}
// MARK: - Actions
@objc private func restoreSubscriptionsTapped(_ sender: UIButton) {
onTapRestore()
}
// MARK: - Public
@@ -80,12 +80,6 @@ class SubscriptionsViewController: UITableViewController {
}
private func configureUI() {
let restoreButton = UIBarButtonItem(title: NSLocalizedString("purchase_pro_restore", comment: ""),
style: .plain,
target: self,
action: #selector(restoreTapped(_:)))
navigationItem.rightBarButtonItem = restoreButton
// if is presented in Simulator, add done button
if navigationController?.viewControllers.first == self {
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(closeTapped(_:)))
@@ -113,11 +107,22 @@ class SubscriptionsViewController: UITableViewController {
let products = storeProducts.compactMap { EQNInAppProducts.from(product: $0) }
let purchased = products.filter { (product) -> Bool in
let isPurchased = EQNInAppProducts.store.isProductPurchased(product.productIdentifier)
let isSubscription = product.isSubscription
return isPurchased && isSubscription
}
let purchased = products
.filter { (product) -> Bool in
// filter for subscriptions
let isPurchased = EQNInAppProducts.store.isProductPurchased(product.productIdentifier)
let isSubscription = product.isSubscription
return isPurchased && isSubscription
}.sorted { lProduct, rProduct in
// if user has more than one subscriptions,
// show first the Top10k
let lIs10k = lProduct.isTop100k
let rIs10k = rProduct.isTop100k
if lIs10k {
return lIs10k
}
return rIs10k
}
self.productSubscribed = purchased.first
self.products = products.sorted(by: { $0.productIdentifier > $1.productIdentifier })
self.tableView.reloadData()
@@ -140,11 +145,6 @@ class SubscriptionsViewController: UITableViewController {
// MARK: - Actions
@objc func restoreTapped(_ sender: AnyObject) {
isRestorePurchase = true
EQNInAppProducts.store.restorePurchases()
}
@objc func closeTapped(_ sender: AnyObject) {
dismiss(animated: true, completion: nil)
}
@@ -220,6 +220,12 @@ class SubscriptionsViewController: UITableViewController {
let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionsActiveTableViewCell.self, for: indexPath)
cell.selectionStyle = .none
cell.update(with: productSubscribed)
cell.onTapRestore = { [weak self] in
guard let self else { return }
self.isRestorePurchase = true
EQNInAppProducts.store.restorePurchases()
}
return cell
case .description:
let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionsDescriptionTableViewCell.self, for: indexPath)
@@ -15,6 +15,8 @@ class RealtimeAlertContainerView: UIView {
lazy var alertView: RealtimeAlertView = {
let view = RealtimeAlertView()
view.translatesAutoresizingMaskIntoConstraints = false
view.eqn_applyRoundedCorners()
view.clipsToBounds = true
return view
}()
@@ -78,10 +80,11 @@ class RealtimeAlertView: UIView {
let waveTimeLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .preferredFont(forTextStyle: .title2)
label.font = .preferredFont(forTextStyle: .largeTitle)
label.textColor = AppTheme.Colors.red
label.text = String.localizedStringWithFormat(NSLocalizedString("alert_wave", comment: ""), 0)
label.textAlignment = .center
label.numberOfLines = 2
label.isHidden = true
return label
}()
@@ -89,7 +92,7 @@ class RealtimeAlertView: UIView {
let intensityLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .preferredFont(forTextStyle: .title3)
label.font = .preferredFont(forTextStyle: .largeTitle)
label.textColor = AppTheme.Colors.red
label.textAlignment = .center
label.numberOfLines = 2
@@ -57,6 +57,7 @@ class SeismicNetworkTableViewCell: UITableViewCell {
private var seismic: EQNSisma?
private(set) var displayType = DisplayType.normal
private var informationTypes = [InformationType]()
private var isPushSelected = false
private var colors: MagnitudeColors?
@@ -65,14 +66,8 @@ class SeismicNetworkTableViewCell: UITableViewCell {
private lazy var containerView: UIView = {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = AppTheme.shared.cardCornerRadius
view.layer.masksToBounds = false
// add shadow
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.5
view.layer.shadowOffset = CGSize(width: 0, height: 2)
view.layer.shadowRadius = 2
view.backgroundColor = .white
view.clipsToBounds = true
return view
}()
@@ -83,7 +78,7 @@ class SeismicNetworkTableViewCell: UITableViewCell {
// disegnare la view non abbiamo le misure corrette.
let view = UIImageView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.contentMode = .scaleAspectFill
view.contentMode = .scaleToFill
return view
}()
@@ -194,6 +189,15 @@ class SeismicNetworkTableViewCell: UITableViewCell {
setupUI()
}
// MARK: - View Lifecycle
override func layoutSubviews() {
super.layoutSubviews()
containerView.eqn_applyShadowAndRoundedCorners()
gradientView.eqn_applyRoundedCorners()
}
// MARK: - Setup
private func setupUI() {
@@ -206,7 +210,6 @@ class SeismicNetworkTableViewCell: UITableViewCell {
containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8.0).isActive = true
containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0).isActive = true
containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4.0).isActive = true
containerView.clipsToBounds = true
containerView.addSubview(gradientView)
gradientView.constraint(to: containerView)
@@ -379,6 +382,9 @@ class SeismicNetworkTableViewCell: UITableViewCell {
else {
previousView.bottomAnchor.constraint(equalTo: containerView.layoutMarginsGuide.bottomAnchor).isActive = true
}
containerView.eqn_applyShadowAndRoundedCorners()
gradientView.eqn_applyRoundedCorners()
}
private func recreateUI() {
@@ -393,13 +399,14 @@ class SeismicNetworkTableViewCell: UITableViewCell {
let viewModel = SeismicNetworkViewModel(seismic: seismic)
if let colors = colors {
gradientView.image = .gradient(from: colors.startColor, to: colors.endColor, with: .init(origin: .zero, size: .init(width: 400, height: 300)))
gradientView.image = .gradient(from: colors.startColor, to: colors.endColor, with: .init(origin: .zero, size: .init(width: 500, height: 1)))
} else {
gradientView.image = nil
}
// update seismic data
placeLabel.text = viewModel.place
placeLabel.textColor = isPushSelected ? AppTheme.Colors.pureBlue : AppTheme.shared.cardTextColor
networkLabel.text = String(format: NSLocalizedString("official_provider", comment: ""), viewModel.network)
magnitudeLabel.textColor = colors?.textColor
magnitudeLabel.text = viewModel.magnitude
@@ -447,11 +454,17 @@ class SeismicNetworkTableViewCell: UITableViewCell {
/// - seismic: Seismic to display
/// - type: Type of cell
/// - informations: Informations to show
public func configure(with seismic: EQNSisma, type: DisplayType, informations: [InformationType]) {
public func configure(
with seismic: EQNSisma,
type: DisplayType,
informations: [InformationType],
isPushSelected: Bool
) {
self.seismic = seismic
self.colors = calculateColors(for: seismic.magnitude.doubleValue)
self.displayType = type
self.informationTypes = informations
self.isPushSelected = isPushSelected
if !informations.contains(.time) {
self.informationTypes += [.time]
@@ -23,11 +23,6 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
// MARK: - Internal
@IBOutlet private weak var tableView: UITableView?
@IBOutlet private weak var expandeCollapseButton: UIBarButtonItem!
@IBOutlet private weak var sortButton: UIBarButtonItem!
weak var currentMapController: SeismicNetworksMapDetailViewController?
/// The ad loader
private lazy var adLoader: GADAdLoader = {
let adLoader = GADAdLoader(
@@ -43,15 +38,64 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
private var informations = [SeismicNetworkTableViewCell.InformationType]()
/// Index path of row with map expanded
private var openMapIndexPath: IndexPath?
/// Push notification opened by the user
private var openedPushNotification: EQNOfficialPushNotification? {
didSet {
scrollToOpenedSeismic = true
}
}
private var scrollToOpenedSeismic = false
/// Current displayed controller with map
private weak var currentMapController: SeismicNetworksMapDetailViewController?
// MARK: - UI
@IBOutlet private weak var expandeCollapseButton: UIBarButtonItem!
@IBOutlet private weak var sortButton: UIBarButtonItem!
private var tableViewTopConstraint: NSLayoutConstraint?
private lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.delegate = self
tableView.dataSource = self
return tableView
}()
private lazy var filterChangedView: UIView = {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = AppTheme.Colors.pureBlue
view.addSubview(filterChangedLabel)
filterChangedLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0).isActive = true
filterChangedLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0).isActive = true
filterChangedLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
filterChangedLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
return view
}()
private lazy var filterChangedLabel: UILabel = {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .white
label.font = .preferredFont(forTextStyle: .subheadline)
label.numberOfLines = 0
label.textAlignment = .center
return label
}()
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
configureUI()
checkForLocation()
refreshUI()
configureFilterView(isVisible: false)
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveDownloadCompleteNotification(_:)), name: .EQNDownloadDataDidComplete, object: nil)
}
@@ -60,16 +104,69 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
super.viewWillAppear(animated)
loadData(forced: false)
// check for a push to manage
if let notification = EQNOfficialPushNotification.stored() {
manageFilter(for: notification)
self.openedPushNotification = notification
EQNOfficialPushNotification.removeStored()
} else {
configureFilterView(isVisible: false)
self.openedPushNotification = nil
}
tableView.reloadData()
}
// MARK: - Private
private func setupUI() {
view.addSubview(tableView)
tableViewTopConstraint = tableView.topAnchor.constraint(equalTo: view.topAnchor)
tableViewTopConstraint?.isActive = true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
private func setupFilterView(isVisible: Bool) {
if isVisible && filterChangedView.superview == nil {
view.addSubview(filterChangedView)
tableViewTopConstraint?.isActive = false
filterChangedView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
filterChangedView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
filterChangedView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableViewTopConstraint = filterChangedView.bottomAnchor.constraint(equalTo: tableView.topAnchor)
tableViewTopConstraint?.isActive = true
} else {
filterChangedView.removeFromSuperview()
tableViewTopConstraint?.isActive = false
tableViewTopConstraint = tableView.topAnchor.constraint(equalTo: view.topAnchor)
tableViewTopConstraint?.isActive = true
}
}
private func configureFilterView(isVisible: Bool) {
setupFilterView(isVisible: isVisible)
if isVisible {
filterChangedLabel.text = NSLocalizedString("official_filter_changed", comment: "")
filterChangedView.backgroundColor = AppTheme.Colors.pureBlue
} else {
filterChangedLabel.text = nil
filterChangedView.backgroundColor = .white
}
}
private func configureUI() {
title = NSLocalizedString("tab_official", comment: "").capitalized
tableView?.estimatedRowHeight = 300.0
tableView?.rowHeight = UITableView.automaticDimension
tableView?.registerCell(for: SeismicNetworkTableViewCell.self)
tableView?.registerCell(for: SeismicNetworkAdvertiseTableViewCell.self)
tableView?.emptyDataSetSource = self
tableView.estimatedRowHeight = 300.0
tableView.rowHeight = UITableView.automaticDimension
tableView.registerCell(for: SeismicNetworkTableViewCell.self)
tableView.registerCell(for: SeismicNetworkAdvertiseTableViewCell.self)
tableView.emptyDataSetSource = self
tableView.separatorStyle = .none
setupSortMenu()
}
@@ -92,7 +189,7 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
private func checkForLocation() {
// check if a valid location is available,
// otherwise change the filter settings
if EQNUser.default().lastPosition == nil {
if !isLocationAvailable() {
EQNSeismic.shared.filterOption = .worldWide
EQNSeismic.shared.saveFilters()
}
@@ -148,7 +245,12 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
expandeCollapseButton.image = UIImage(named: "navbar-icon-arrow-expand")
}
tableView?.reloadData()
tableView.reloadData()
if scrollToOpenedSeismic, let index = getSeismics().firstIndex(where: { isSeismicToHighlight(seismic: $0) }) {
tableView.scrollToRow(at: IndexPath(row: index, section: 0), at: .middle, animated: true)
scrollToOpenedSeismic = false
}
}
private func loadAd() {
@@ -196,6 +298,268 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
refreshUI()
}
private func manageFilter(
for notification: EQNOfficialPushNotification
) {
//gestisco i filtri solo se la posizione dell'utente è nota
guard let userPosition = EQNUser.default().lastPosition else {
return
}
var filter_type = EQNSeismic.shared.filterOption
var filter_radius = Double(EQNSeismic.shared.maximumDistance) ?? 0
var filter_min_magnitude = Double(EQNSeismic.shared.minimumMagnitude) ?? 0
var filter_changed = false
//recupero i dati del sisma notificato
let notification_magnitude = notification.magnitude
let notification_latitude = notification.coordinate.coordinate.latitude
let notification_longitude = notification.coordinate.coordinate.longitude
//distanza tra smartphone utente e sisma notificato
let locationNotification = CLLocation(latitude: notification_latitude, longitude: notification_longitude)
let distance = userPosition.distance(from: locationNotification) / 1_000
//verifico se il sisma è significativo in base alla definizione di significativo
var is_significant = true
if notification_magnitude < 7.0 && distance > 2000 {
is_significant = false
} else if notification_magnitude < 6.5 && distance > 1600 {
is_significant = false
} else if notification_magnitude < 6.0 && distance > 1300 {
is_significant = false
} else if notification_magnitude < 5.5 && distance > 1000 {
is_significant = false
} else if notification_magnitude < 5.0 && distance > 700 {
is_significant = false
} else if notification_magnitude < 4.5 && distance > 500 {
is_significant = false
} else if notification_magnitude < 4.0 && distance > 350 {
is_significant = false
} else if notification_magnitude < 3.5 && distance > 200 {
is_significant = false
} else if notification_magnitude < 3.0 && distance > 125 {
is_significant = false
} else if notification_magnitude < 2.5 && distance > 70 {
is_significant = false
} else if notification_magnitude < 2.0 && distance > 35 {
is_significant = false
} else if notification_magnitude < 1.5 && distance > 20 {
is_significant = false
}
//verifico se devo modificare il filtro scelto dall'utente
if filter_type == .inRadius { //filter_type=0 è il filtro basato su raggio e magnitudo
if distance > 2000 && is_significant {
filter_type = .positionRelevant //passo al filtro che mostra i sismi significativi (perché il raggio massimo del filtro basato sul raggio è 2000)
updateFilter(type: filter_type)
filter_changed = true
}
else if distance > 2000 && notification_magnitude >= 2.0 {
filter_type = .worldWide //passo al filtro che mostra tutti i sismi nel mondo
updateFilter(type: filter_type)
filter_changed = true
}
else {
//verifico se devo cambiare il raggio del filtro
if distance > filter_radius {
if distance > 1500 {
filter_radius = 2000
} else if distance > 1000 {
filter_radius = 1500
} else if distance > 750 {
filter_radius = 1000
} else if distance > 500 {
filter_radius = 750
} else if distance > 250 {
filter_radius = 500
} else if distance > 100 {
filter_radius = 250
}
updateFilter(radius: filter_radius)
filter_changed = true
}
//verifico se devo cambiare la mgnitudo del filtro
if notification_magnitude < filter_min_magnitude {
if notification_magnitude < 1.0 {
filter_min_magnitude = 0.0
} else if notification_magnitude < 2.0 {
filter_min_magnitude = 1.0
} else if notification_magnitude < 3.0 {
filter_min_magnitude = 2.0
} else if notification_magnitude < 4.0 {
filter_min_magnitude = 3.0
} else if notification_magnitude < 5.0 {
filter_min_magnitude = 4.0
} else if notification_magnitude < 6.0 {
filter_min_magnitude = 5.0
}
filter_changed = true
updateFilter(magnitude: filter_min_magnitude)
}
}
}
if filter_type == .positionRelevant && !is_significant && distance <= 2000 {
filter_type = .inRadius //passo a filtro basato su raggio e magnitudo
updateFilter(type: filter_type)
if distance > filter_radius {
if distance>1500 {
filter_radius = 2000
}
else if distance > 1000 {
filter_radius = 1500
}
else if distance > 750 {
filter_radius = 1000
}
else if distance > 500 {
filter_radius = 750
}
else if distance > 250 {
filter_radius = 500
}
else if distance > 100 {
filter_radius = 250
}
updateFilter(radius: filter_radius)
}
if notification_magnitude < filter_min_magnitude {
if notification_magnitude < 1.0 {
filter_min_magnitude = 0.0
}
else if notification_magnitude < 2.0 {
filter_min_magnitude = 1.0
}
else if notification_magnitude < 3.0 {
filter_min_magnitude = 2.0
}
else if notification_magnitude < 4.0 {
filter_min_magnitude = 3.0
}
else if notification_magnitude < 5.0 {
filter_min_magnitude = 4.0
}
else if notification_magnitude < 6.0 {
filter_min_magnitude = 5.0
}
updateFilter(magnitude: filter_min_magnitude)
}
filter_changed = true
}
if filter_type == .positionRelevant && !is_significant && distance > 2000 && notification_magnitude >= 2.0 {
filter_type = .worldWide //passo a filtro che mostra tutti i sismi nel mondo
updateFilter(type: filter_type)
filter_changed = true
}
if filter_type == .worldWide && notification_magnitude < 2.0 && is_significant {
filter_type = .positionRelevant //passo a filtro sismi significativi
updateFilter(type: filter_type)
filter_changed = true
}
if filter_type == .worldWide && notification_magnitude < 2.0 && distance <= 2000 && !is_significant {
filter_type = .inRadius
updateFilter(type: filter_type)
if distance > filter_radius {
if distance > 1500 {
filter_radius = 2000
}
else if distance > 1000 {
filter_radius = 1500
}
else if distance > 750 {
filter_radius = 1000
}
else if distance > 500 {
filter_radius = 750
}
else if distance > 250 {
filter_radius = 500
}
else if distance > 100 {
filter_radius = 250
}
updateFilter(radius: filter_radius)
}
if notification_magnitude < filter_min_magnitude {
if notification_magnitude < 1.0 {
filter_min_magnitude = 0.0
}
else if notification_magnitude < 2.0 {
filter_min_magnitude = 1.0
}
else if notification_magnitude < 3.0 {
filter_min_magnitude = 2.0
}
else if notification_magnitude < 4.0 {
filter_min_magnitude = 3.0
}
else if notification_magnitude < 5.0 {
filter_min_magnitude = 4.0
}
else if notification_magnitude < 6.0 {
filter_min_magnitude = 5.0
}
updateFilter(magnitude: filter_min_magnitude)
}
filter_changed = true
}
//mostro all'utente un messaggio per avvisarlo che i filtri sono stati modificati
configureFilterView(isVisible: filter_changed)
if filter_changed {
loadData(forced: true)
}
}
private func updateFilter(
type: EQNSeismic.FilterType? = nil,
radius: Double? = nil,
magnitude: Double? = nil
) {
if let type {
EQNSeismic.shared.filterOption = type
}
if let radius {
EQNSeismic.shared.maximumDistance = String(format: "%.0f", radius)
}
if let magnitude {
EQNSeismic.shared.minimumMagnitude = String(format: "%.1f", magnitude)
}
EQNSeismic.shared.saveFilters()
}
private func isLocationAvailable() -> Bool {
EQNUser.default().lastPosition != nil
}
private func isSeismicToHighlight(seismic: EQNSisma) -> Bool {
guard let notification = openedPushNotification else {
return false
}
guard let seismicDate = seismic.date, let notificationDate = notification.date else { return false }
let deltaTime = abs(seismicDate.timeIntervalSince(notificationDate))
let magnitudeRatio = seismic.magnitude.doubleValue / notification.magnitude
let latitudeDiff = abs(seismic.coordinate.coordinate.latitude - notification.coordinate.coordinate.latitude)
let longitudeDiff = abs(seismic.coordinate.coordinate.longitude - notification.coordinate.coordinate.longitude)
if deltaTime <= 120 && magnitudeRatio > 0.8 && magnitudeRatio < 1.2 && latitudeDiff < 1 && longitudeDiff < 1 { // secondi?
return true
}
return false
}
// MARK: - Actions
@IBAction func refreshDataTapped(_ sender: Any) {
@@ -233,8 +597,9 @@ class SeismicNetworksViewController: UIViewController, UITableViewDelegate, UITa
if openMapIndexPath == indexPath {
type = .mapExpanded
}
cell.configure(with: seismic, type: type, informations: informations)
let isPushSelected = isSeismicToHighlight(seismic: seismic)
cell.configure(with: seismic, type: type, informations: informations, isPushSelected: isPushSelected)
cell.delegate = self
return cell
case .advertise(let nativeAd):
@@ -314,7 +679,7 @@ extension SeismicNetworksViewController: GADNativeAdLoaderDelegate {
let adPosition = min(3, rows.count)
rows.insert(.advertise(nativeAd), at: adPosition)
tableView?.reloadData()
tableView.reloadData()
}
func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
@@ -326,7 +691,7 @@ extension SeismicNetworksViewController: GADNativeAdLoaderDelegate {
extension SeismicNetworksViewController: SeismicNetworkTableViewCellDelegate {
func seismicNetworkCellDidTapShare(_ cell: SeismicNetworkTableViewCell) {
guard let index = tableView?.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
guard let index = tableView.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
// create a snapshot of the cell and share with default share sheet
let snapshot = cell.contentView.createSnapshot()
@@ -343,22 +708,22 @@ extension SeismicNetworksViewController: SeismicNetworkTableViewCellDelegate {
}
func seismicNetworkCellDidTapMap(_ cell: SeismicNetworkTableViewCell) {
guard let index = tableView?.indexPath(for: cell) else { return }
guard let index = tableView.indexPath(for: cell) else { return }
let indexToReloads = [openMapIndexPath, index].compactMap { $0 }
openMapIndexPath = index
tableView?.reloadRows(at: indexToReloads, with: .automatic)
tableView.reloadRows(at: indexToReloads, with: .automatic)
}
func seismicNetworkCellDidTapMapDetail(_ cell: SeismicNetworkTableViewCell) {
guard let index = tableView?.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
guard let index = tableView.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
showMapDetail(for: seismic)
}
func seismicNetworkCellDidTapCalendar(_ cell: SeismicNetworkTableViewCell) {
guard let index = tableView?.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
guard let index = tableView.indexPath(for: cell), case let .seismic(seismic) = rows[index.row] else { return }
openCalendar(for: seismic)
}
@@ -368,12 +733,12 @@ extension SeismicNetworksViewController: SeismicNetworkTableViewCellDelegate {
}
func seismicNetworkCellDidTapClose(_ cell: SeismicNetworkTableViewCell) {
guard let index = tableView?.indexPath(for: cell) else { return }
guard let index = tableView.indexPath(for: cell) else { return }
let indexToReloads = [openMapIndexPath, index].compactMap { $0 }
openMapIndexPath = nil
tableView?.reloadRows(at: indexToReloads, with: .automatic)
tableView.reloadRows(at: indexToReloads, with: .automatic)
}
}
@@ -1,73 +0,0 @@
//
// SettingsSeismicNetworkNotificationsFilterViewController.swift
// Earthquake Network
//
// Created by Andrea Busi on 06/06/24.
// Copyright © 2024 Earthquake Network. All rights reserved.
//
import UIKit
import Shogun
class SettingsSeismicNetworkNotificationsFilterViewController: UITableViewController {
private let filters: [EQNSettingSeismicNetworkNotification.FilterType] = [.soloRilevanti, .condizionati]
private var currentFilter = EQNSettingSeismicNetworkNotification.shared.filtro
// MARK: - Init
convenience init() {
self.init(style: .insetGrouped)
}
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
// MARK: - Private
private func setupUI() {
tableView.estimatedRowHeight = 200.0
tableView.rowHeight = UITableView.automaticDimension
tableView.registerHeaderFooterView(for: SettingSectionHeaderView.self)
tableView.registerCell(for: SettingDetailTableViewCell.self)
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = tableView.dequeueHeaderFooterView(cellIdentifiable: SettingSectionHeaderView.self)
view.titleLabel.text = NSLocalizedString("options_official_type", comment: "")
return view
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
SettingSectionHeaderView.Height
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filters.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let filter = filters[indexPath.row]
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingDetailTableViewCell.self, for: indexPath)
cell.textLabel?.text = filter.displayName
cell.textLabel?.numberOfLines = 0
cell.accessoryType = currentFilter == filter ? .checkmark : .none
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let filter = filters[indexPath.row]
EQNSettingSeismicNetworkNotification.shared.filtro = filter
EQNSettingSeismicNetworkNotification.shared.saveUserInfo()
navigationController?.popViewController(animated: true)
}
}
@@ -13,15 +13,11 @@ class SettingsSeismicNetworkNotificationsViewController: SettingsBaseTableViewCo
private enum RowIdentifier: Int {
case abilitaNotifiche
case filtroNotifiche
case magnitudoMinima
case distanzaMassima
}
private static let SegueFilters = "ShowFilters"
private var isNotificationEnabled = false
private var currentFilter: EQNSettingSeismicNetworkNotification.FilterType = .soloRilevanti
private var currentMinimumMagnitude = EQNData.DefaultSettingSeismicNetworkNotificationMagitude
private var currentMaximumDistance = EQNData.DefaultSettingSeismicNetworkNotificationRadius
private let dataSourceMinimumMagnitude = EQNData.settingSeismicNetworkNotificationMagnitudes
@@ -29,7 +25,6 @@ class SettingsSeismicNetworkNotificationsViewController: SettingsBaseTableViewCo
private let settings: [SettingItem] = [
.init(type: .enable, title: NSLocalizedString("options_notification_enable_official", comment: "")),
.init(type: .multiValues, title: NSLocalizedString("options_official_type", comment: ""), segue: SegueFilters),
.init(type: .slider, title: NSLocalizedString("options_official_minmag", comment: "")),
.init(type: .slider, title: NSLocalizedString("options_official_maxdist", comment: ""))
]
@@ -69,9 +64,6 @@ class SettingsSeismicNetworkNotificationsViewController: SettingsBaseTableViewCo
isNotificationEnabled = saved.isAbilitato
// filtro notifiche
currentFilter = saved.filtro
// magnitudo minima
let magnitudoMinima = EQNData.getSettingSeismicNetworkNotificationMagnitudes(for: saved.magnitudoMinima)
currentMinimumMagnitude = magnitudoMinima
@@ -119,28 +111,13 @@ class SettingsSeismicNetworkNotificationsViewController: SettingsBaseTableViewCo
break
}
return cell
case .multiValues:
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingMultivaluesTableViewCell.self, for: indexPath)
cell.accessoryType = .disclosureIndicator
cell.titleLabel.text = setting.title
switch identifier {
case .filtroNotifiche:
cell.isDisabled = !isNotificationEnabled
cell.isUserInteractionEnabled = isNotificationEnabled
cell.valuesLabel.text = currentFilter.displayName
default:
break
}
return cell
case .slider:
let cell = tableView.dequeueReusableCell(cellIdentifiable: SettingSliderTableViewCell.self, for: indexPath)
cell.titleLabel.text = setting.displayTitle
let filtersEnabled = isNotificationEnabled && currentFilter == .condizionati
let filtersEnabled = isNotificationEnabled
switch identifier {
case .magnitudoMinima:
cell.isDisabled = !filtersEnabled
@@ -165,17 +142,6 @@ class SettingsSeismicNetworkNotificationsViewController: SettingsBaseTableViewCo
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let setting = settings[indexPath.row]
switch setting.segue {
case Self.SegueFilters:
let controller = SettingsSeismicNetworkNotificationsFilterViewController()
navigationController?.pushViewController(controller, animated: true)
default:
break
}
}
private func onChangeNotificationEnabled(_ enabled: Bool) {
isNotificationEnabled = enabled
EQNSettingSeismicNetworkNotification.shared.isAbilitato = isNotificationEnabled
@@ -12,9 +12,7 @@ import UIKit
extension UIView {
func eqn_applyShadowAndRoundedCorners() {
// rounded corners
layer.cornerRadius = AppTheme.shared.cardCornerRadius
layer.masksToBounds = false
eqn_applyRoundedCorners()
// apply a shadow to the current view
layer.shadowColor = UIColor.black.cgColor
@@ -22,4 +20,10 @@ extension UIView {
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.shadowRadius = 2
}
func eqn_applyRoundedCorners() {
// rounded corners
layer.cornerRadius = AppTheme.shared.cardCornerRadius
layer.masksToBounds = false
}
}
@@ -14,7 +14,7 @@ public class EQNAppearanceCommand: EQNCommandProtocol {
// MARK: - Public
func execute() {
print("EQNAppearanceCommand: start execute")
print("[EQNAppearanceCommand] Start execute")
applyAppearance()
}
@@ -32,7 +32,7 @@ public class EQNAppearanceCommand: EQNCommandProtocol {
navAppearance.largeTitleTextAttributes = [
NSAttributedString.Key.foregroundColor: AppTheme.Colors.darkGray
]
navAppearance.backgroundColor = AppTheme.Colors.primary
navAppearance.backgroundColor = AppTheme.Colors.navBar
navAppearance.shadowColor = UIColor.clear
proxyNavBar.isTranslucent = false
@@ -15,7 +15,7 @@ public class EQNUserDefaultsCommand: EQNCommandProtocol {
// MARK: - Public
func execute() {
print("EQNUserDefaultsCommand: start execute")
print("[EQNUserDefaultsCommand] Start execute")
applyDefaultSettings()
saveMissingValues()
@@ -0,0 +1,130 @@
//
// EQNOfficialPushNotification.swift
// Earthquake Network
//
// Created by Andrea Busi on 29/06/24.
// Copyright © 2024 Earthquake Network. All rights reserved.
//
import Foundation
import Shogun
@objc
class EQNOfficialPushNotification: NSObject, Codable {
private enum CodingKeys: String, CodingKey {
case latitude
case longitude
case magnitude
case date
}
private let latitude: Double
private let longitude: Double
let magnitude: Double
let date: Date?
var coordinate: CLLocation {
.init(latitude: latitude, longitude: longitude)
}
// MARK: - Init
init(
latitude: Double,
longitude: Double,
magnitude: Double,
date: Date?
) {
self.latitude = latitude
self.longitude = longitude
self.magnitude = magnitude
self.date = date
}
// MARK: - Class
/// Remove any saved notification
static func removeStored() {
UserDefaults.standard.removeObject(forKey: UserDefaults.OfficialAlertPayload)
}
/// Retrieve stored notification (if any)
static func stored() -> EQNOfficialPushNotification? {
guard let data = UserDefaults.standard.object(forKey: UserDefaults.OfficialAlertPayload) as? Data else {
print("[EQNOfficialPushNotification] No notification saved for key '\(UserDefaults.OfficialAlertPayload)'")
return nil
}
guard let notification = try? JSONDecoder().decode(EQNOfficialPushNotification.self, from: data) else {
print("[EQNOfficialPushNotification] Unable to decode given notification")
return nil
}
return notification
}
/// Convert and store a push notification payload.
/// Expected payload has the following structure:
/// ```
/// {
/// "title": "Segnalazione da rete sismica",
/// "body": "Sisma rilevato a 4km S Valfabbrica (PG)",
/// "userInfo": {
/// "data" : "2024-06-29 11:21:30",
/// ...
/// "aps": {
/// "alert" : {
/// "loc-key" : "Sisma rilevato a",
/// "title-loc-key" : "Segnalazione da rete sismica",
/// "title" : "Segnalazione da rete sismica",
/// "action-loc-key" : "",
/// "loc-args" : [
/// "6 km S Acate (RG) - M1.9"
/// ]
/// },
/// }
/// }
/// }
/// ```
/// - Parameter payload: Notification payload
/// - Returns: `true` if save succeed, `false` otherwise
@objc(storeNotificationWithPayload:)
@discardableResult
static func store(payload: [String: Any]) -> Bool {
guard let notification = from(payload: payload) else {
print("[EQNOfficialPushNotification] Unable to convert received notification")
return false
}
guard let data = try? JSONEncoder().encode(notification) else {
print("[EQNOfficialPushNotification] Unable to encode given notification")
return false
}
UserDefaults.standard.set(data, forKey: UserDefaults.OfficialAlertPayload)
return true
}
@objc
private static func from(payload: [String: Any]) -> EQNOfficialPushNotification? {
guard let userInfo = payload["userInfo"] as? [String: Any] else {
print("[EQNOfficialPushNotification] Missing required info to parse push notification")
return nil
}
let latitude = userInfo.double(forKey: "latitude") ?? 0
let longitude = userInfo.double(forKey: "longitude") ?? 0
let magnitude = userInfo.double(forKey: "magnitude") ?? 0
let dateString = userInfo.string(forKey: "data") ?? ""
let date = EQNUtility.getDateFrom(dateString)
return .init(
latitude: latitude,
longitude: longitude,
magnitude: magnitude,
date: date
)
}
}
@@ -11,29 +11,15 @@ import Foundation
@objc
class EQNSettingSeismicNetworkNotification: NSObject {
enum FilterType: Int {
case soloRilevanti
case condizionati
var displayName: String {
switch self {
case .soloRilevanti: NSLocalizedString("options_official_type_relevant", comment: "")
case .condizionati: NSLocalizedString("options_official_type_area", comment: "")
}
}
}
@objc(sharedInstance)
static let shared = EQNSettingSeismicNetworkNotification()
@objc var isAbilitato: Bool
@objc var magnitudoMinima: String
@objc var distanzaMassima: String
var filtro: FilterType
private static let DefaultMagnitudoMinima = EQNData.DefaultFilterMagnitude.value
private static let DefaultDistanzaMassima = EQNData.DefaultFilterRadius.value
private static let DefaultFiltro = FilterType.soloRilevanti
// MARK: - Init
@@ -44,7 +30,6 @@ class EQNSettingSeismicNetworkNotification: NSObject {
self.isAbilitato = defaults.bool(forKey: UserDefaults.NotificheRetiSismicheAbilitato)
self.magnitudoMinima = defaults.object(forKey: UserDefaults.NotificheRetiSismicheMagnitudoMinima, or: Self.DefaultMagnitudoMinima)
self.distanzaMassima = defaults.object(forKey: UserDefaults.NotificheRetiSismicheDistanzaMassima, or: Self.DefaultDistanzaMassima)
self.filtro = defaults.enumObject(forKey: UserDefaults.NotificheRetiSismicheFiltroNotifiche, or: Self.DefaultFiltro)
}
// MARK: - Public
@@ -54,14 +39,12 @@ class EQNSettingSeismicNetworkNotification: NSObject {
defaults.set(isAbilitato, forKey: UserDefaults.NotificheRetiSismicheAbilitato)
defaults.set(magnitudoMinima, forKey: UserDefaults.NotificheRetiSismicheMagnitudoMinima)
defaults.set(distanzaMassima, forKey: UserDefaults.NotificheRetiSismicheDistanzaMassima)
defaults.set(filtro.rawValue, forKey: UserDefaults.NotificheRetiSismicheFiltroNotifiche)
}
@objc class func saveDefaultValues() {
shared.isAbilitato = true
shared.magnitudoMinima = DefaultMagnitudoMinima
shared.distanzaMassima = DefaultDistanzaMassima
shared.filtro = DefaultFiltro
shared.saveUserInfo()
}
@@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "130",
"green" : "212",
"red" : "148"
"blue" : "196",
"green" : "226",
"red" : "200"
}
},
"idiom" : "universal"
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "167",
"green" : "231",
"red" : "255"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.318",
"green" : "0.565",
"red" : "0.000"
"blue" : "35",
"green" : "160",
"red" : "12"
}
},
"idiom" : "universal"
@@ -134,6 +134,7 @@
case EQNTipoChiamataCalibrazione:
case EQNTipoChiamataImpostazioniNotifiche:
case EQNTipoChiamataAlertSimulator:
case EQNTipoChiamataAlertPushTest:
case EQNTipoChiamataRegisterSubscription:
onSuccess(newStr);
default:
@@ -4,7 +4,6 @@
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -17,23 +16,8 @@
<view key="view" contentMode="scaleToFill" id="yYN-HE-bpD">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="q4o-YO-KLX">
<rect key="frame" x="0.0" y="144" width="414" height="669"/>
<connections>
<outlet property="dataSource" destination="tVM-DH-fmv" id="XVf-fb-5Kl"/>
<outlet property="delegate" destination="tVM-DH-fmv" id="dWO-2A-Ukg"/>
</connections>
</tableView>
</subviews>
<viewLayoutGuide key="safeArea" id="VUD-fs-xgm"/>
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
<constraints>
<constraint firstItem="VUD-fs-xgm" firstAttribute="bottom" secondItem="q4o-YO-KLX" secondAttribute="bottom" id="3P1-fP-chi"/>
<constraint firstItem="q4o-YO-KLX" firstAttribute="top" secondItem="VUD-fs-xgm" secondAttribute="top" id="IeK-TW-jL5"/>
<constraint firstItem="q4o-YO-KLX" firstAttribute="leading" secondItem="VUD-fs-xgm" secondAttribute="leading" id="Yyx-Tc-hnn"/>
<constraint firstItem="VUD-fs-xgm" firstAttribute="trailing" secondItem="q4o-YO-KLX" secondAttribute="trailing" id="yd6-Pa-c2s"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="6kD-jk-5Aw">
<rightBarButtonItems>
@@ -58,14 +42,13 @@
<connections>
<outlet property="expandeCollapseButton" destination="HTN-07-s5p" id="lxP-Im-NME"/>
<outlet property="sortButton" destination="LyU-KI-3Mb" id="969-Zg-YBB"/>
<outlet property="tableView" destination="q4o-YO-KLX" id="tee-h5-dZi"/>
<segue destination="6LP-zk-O1z" kind="presentation" identifier="ShowFilters" modalPresentationStyle="overCurrentContext" modalTransitionStyle="crossDissolve" id="Nzu-iH-UgB"/>
<segue destination="Rfp-kt-2Kx" kind="presentation" identifier="ShowCardSettings" modalPresentationStyle="overCurrentContext" modalTransitionStyle="crossDissolve" id="VWw-16-xGw"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="34i-9D-p3O" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-8709" y="-5464"/>
<point key="canvasLocation" x="-8710.144927536232" y="-5464.2857142857138"/>
</scene>
<!--Segnalazioni View Controller-->
<scene sceneID="2v7-dY-aHc">
@@ -582,154 +565,8 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="200" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="a35-sg-TCr">
<rect key="frame" x="0.0" y="92" width="414" height="666"/>
<rect key="frame" x="0.0" y="144" width="414" height="614"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="SeismicNotificationExpandedCell" rowHeight="700" id="C7v-rs-1fb" customClass="AlertsSeismicNotificationExpandedTableViewCell" customModule="Earthquake_Network" customModuleProvider="target">
<rect key="frame" x="0.0" y="50" width="414" height="700"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="C7v-rs-1fb" id="aEH-vE-u7m">
<rect key="frame" x="0.0" y="0.0" width="414" height="700"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TfA-6E-CQc">
<rect key="frame" x="8" y="8" width="398" height="684"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Rilevato un sisma debole a 150 km (Test)" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="M7i-e5-N6v">
<rect key="frame" x="8" y="8" width="382" height="67.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
<color key="textColor" name="Gray (dark)"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DyB-fs-sPo">
<rect key="frame" x="8" y="87.5" width="382" height="42.5"/>
<string key="text">Distanza 149 km - 0 minuti fa
Sisma rilevato da 10 smartphone</string>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" name="Gray (dark)"/>
<nil key="highlightedColor"/>
</label>
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="tqM-QH-LJ3">
<rect key="frame" x="0.0" y="172.5" width="398" height="287"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="240" id="w6M-Ao-KHo"/>
</constraints>
</mapView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="Q2V-3p-DUh">
<rect key="frame" x="8" y="467.5" width="382" height="40"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="V2G-UH-Ibe" customClass="EQNRoundedButton" customModule="Earthquake_Network" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="187" height="40"/>
<color key="backgroundColor" white="1" alpha="0.5" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="SHARE APP">
<color key="titleColor" name="Gray (dark)"/>
</state>
<connections>
<action selector="shareAppTapped:" destination="C7v-rs-1fb" eventType="touchUpInside" id="Igp-0D-llw"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="n9y-jx-2xG" customClass="EQNRoundedButton" customModule="Earthquake_Network" customModuleProvider="target">
<rect key="frame" x="195" y="0.0" width="187" height="40"/>
<color key="backgroundColor" white="1" alpha="0.5" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="RATE THE APP">
<color key="titleColor" name="Gray (dark)"/>
</state>
<connections>
<action selector="rateAppTapped:" destination="C7v-rs-1fb" eventType="touchUpInside" id="xgm-dy-Uy3"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="40" id="Qe8-J8-tY6"/>
</constraints>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jwx-kf-che" customClass="EQNRoundedButton" customModule="Earthquake_Network" customModuleProvider="target">
<rect key="frame" x="8" y="515.5" width="382" height="40"/>
<color key="backgroundColor" white="1" alpha="0.5" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="VIEW ON TWITTER">
<color key="titleColor" name="Gray (dark)"/>
</state>
<connections>
<action selector="viewInTwitterTapped:" destination="C7v-rs-1fb" eventType="touchUpInside" id="djx-1X-bbD"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="The magnitude will be estimated by the national seismic network and it will appear in the Seismic Networks tab of the app" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GIh-sK-KX1">
<rect key="frame" x="8" y="563.5" width="382" height="64.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" name="Gray (dark)"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3Ga-UF-Cr7" customClass="EQNRoundedButton" customModule="Earthquake_Network" customModuleProvider="target">
<rect key="frame" x="8" y="636" width="382" height="40"/>
<color key="backgroundColor" white="1" alpha="0.5" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="CLOSE">
<color key="titleColor" name="Gray (dark)"/>
</state>
<connections>
<action selector="closeTapped:" destination="C7v-rs-1fb" eventType="touchUpInside" id="y39-44-3gS"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Rilevato scuotimento forte" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xb4-4c-oEd">
<rect key="frame" x="8" y="138" width="382" height="26.5"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="22"/>
<color key="textColor" name="Gray (dark)"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="3Ga-UF-Cr7" firstAttribute="trailing" secondItem="GIh-sK-KX1" secondAttribute="trailing" id="1qg-dS-vGZ"/>
<constraint firstItem="DyB-fs-sPo" firstAttribute="top" secondItem="M7i-e5-N6v" secondAttribute="bottom" constant="12" id="7gG-Y2-tda"/>
<constraint firstAttribute="trailing" secondItem="GIh-sK-KX1" secondAttribute="trailing" constant="8" id="8TC-4t-7fC"/>
<constraint firstItem="tqM-QH-LJ3" firstAttribute="top" secondItem="Xb4-4c-oEd" secondAttribute="bottom" constant="8" id="9Nv-Zb-mlE"/>
<constraint firstItem="Xb4-4c-oEd" firstAttribute="trailing" secondItem="DyB-fs-sPo" secondAttribute="trailing" id="F4e-yh-mKB"/>
<constraint firstAttribute="trailing" secondItem="tqM-QH-LJ3" secondAttribute="trailing" id="Gf0-a2-jaj"/>
<constraint firstItem="3Ga-UF-Cr7" firstAttribute="height" secondItem="Q2V-3p-DUh" secondAttribute="height" id="N2x-vd-6D6"/>
<constraint firstItem="Xb4-4c-oEd" firstAttribute="leading" secondItem="DyB-fs-sPo" secondAttribute="leading" id="QAk-d3-ZOG"/>
<constraint firstItem="Jwx-kf-che" firstAttribute="trailing" secondItem="Q2V-3p-DUh" secondAttribute="trailing" id="Qie-q3-No5"/>
<constraint firstItem="Q2V-3p-DUh" firstAttribute="top" secondItem="tqM-QH-LJ3" secondAttribute="bottom" constant="8" id="TM2-ig-acw"/>
<constraint firstItem="Jwx-kf-che" firstAttribute="top" secondItem="Q2V-3p-DUh" secondAttribute="bottom" constant="8" id="Wjc-dF-bMj"/>
<constraint firstAttribute="trailing" secondItem="M7i-e5-N6v" secondAttribute="trailing" constant="8" id="XHM-kN-PXl"/>
<constraint firstItem="3Ga-UF-Cr7" firstAttribute="leading" secondItem="GIh-sK-KX1" secondAttribute="leading" id="YhB-av-ejA"/>
<constraint firstItem="DyB-fs-sPo" firstAttribute="leading" secondItem="M7i-e5-N6v" secondAttribute="leading" id="ZHJ-oa-DjC"/>
<constraint firstItem="Jwx-kf-che" firstAttribute="height" secondItem="Q2V-3p-DUh" secondAttribute="height" id="Zp0-Q0-p0q"/>
<constraint firstItem="Q2V-3p-DUh" firstAttribute="leading" secondItem="TfA-6E-CQc" secondAttribute="leading" constant="8" id="ZsU-Ec-9Bc"/>
<constraint firstAttribute="trailing" secondItem="Q2V-3p-DUh" secondAttribute="trailing" constant="8" id="bmi-oa-9ss"/>
<constraint firstItem="tqM-QH-LJ3" firstAttribute="leading" secondItem="TfA-6E-CQc" secondAttribute="leading" id="gUO-ka-XvB"/>
<constraint firstAttribute="bottom" secondItem="3Ga-UF-Cr7" secondAttribute="bottom" constant="8" id="gWA-6h-HmJ"/>
<constraint firstItem="DyB-fs-sPo" firstAttribute="trailing" secondItem="M7i-e5-N6v" secondAttribute="trailing" id="jD7-QV-p8s"/>
<constraint firstItem="GIh-sK-KX1" firstAttribute="top" secondItem="Jwx-kf-che" secondAttribute="bottom" constant="8" id="nJj-g4-TSs"/>
<constraint firstItem="Xb4-4c-oEd" firstAttribute="top" secondItem="DyB-fs-sPo" secondAttribute="bottom" constant="8" symbolic="YES" id="pct-jg-eJW"/>
<constraint firstItem="3Ga-UF-Cr7" firstAttribute="top" secondItem="GIh-sK-KX1" secondAttribute="bottom" constant="8" id="qaQ-zK-ael"/>
<constraint firstItem="M7i-e5-N6v" firstAttribute="leading" secondItem="TfA-6E-CQc" secondAttribute="leading" constant="8" id="rsV-dp-eqa"/>
<constraint firstItem="M7i-e5-N6v" firstAttribute="top" secondItem="TfA-6E-CQc" secondAttribute="top" constant="8" id="seX-2q-JVM"/>
<constraint firstItem="Jwx-kf-che" firstAttribute="leading" secondItem="Q2V-3p-DUh" secondAttribute="leading" id="tND-n7-uEb"/>
<constraint firstItem="GIh-sK-KX1" firstAttribute="leading" secondItem="TfA-6E-CQc" secondAttribute="leading" constant="8" id="tsI-iu-M9g"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="TfA-6E-CQc" firstAttribute="top" secondItem="aEH-vE-u7m" secondAttribute="top" constant="8" id="9GR-hr-g5x"/>
<constraint firstAttribute="trailing" secondItem="TfA-6E-CQc" secondAttribute="trailing" constant="8" id="FWZ-RC-8Ed"/>
<constraint firstAttribute="bottom" secondItem="TfA-6E-CQc" secondAttribute="bottom" constant="8" id="fld-qW-XMS"/>
<constraint firstItem="TfA-6E-CQc" firstAttribute="leading" secondItem="aEH-vE-u7m" secondAttribute="leading" constant="8" id="r0r-m9-EiO"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<outlet property="closeButton" destination="3Ga-UF-Cr7" id="yNt-rU-bZX"/>
<outlet property="containerView" destination="TfA-6E-CQc" id="twS-Jx-IAd"/>
<outlet property="descriptionLabel" destination="GIh-sK-KX1" id="L4X-lK-CVb"/>
<outlet property="mapView" destination="tqM-QH-LJ3" id="Gp4-gu-q8r"/>
<outlet property="notificationDescriptionLabel" destination="DyB-fs-sPo" id="aLr-34-WND"/>
<outlet property="notificationIntensityLabel" destination="Xb4-4c-oEd" id="QFh-Jd-pLP"/>
<outlet property="notificationTitleLabel" destination="M7i-e5-N6v" id="RqD-wo-sXl"/>
<outlet property="rateAppButton" destination="n9y-jx-2xG" id="mvX-2K-I6i"/>
<outlet property="shareButton" destination="V2G-UH-Ibe" id="JT4-jR-d45"/>
<outlet property="viewOnTwitterButton" destination="Jwx-kf-che" id="xNf-ps-fWL"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="syj-UE-OWc" id="Vah-TU-YfT"/>
<outlet property="delegate" destination="syj-UE-OWc" id="Iqp-Mp-8lG"/>
@@ -792,9 +629,6 @@ Sisma rilevato da 10 smartphone</string>
<image name="tabbar-icon-networks" width="25" height="25"/>
<image name="tabbar-icon-reports" width="25" height="25"/>
<image name="tabbar-icon-settings" width="25" height="25"/>
<namedColor name="Gray (dark)">
<color red="0.10999999940395355" green="0.13300000131130219" blue="0.14900000393390656" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<systemColor name="groupTableViewBackgroundColor">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
@@ -21,7 +21,15 @@ class AppTheme: NSObject {
static let lightGray = UIColor(named: "Gray (light)")!
static let cardBackgroundRed = UIColor(named: "Red (card background)")!
static let cardBackgroundOrange = UIColor(named: "Orange (card background)")!
static let cardBackgroundGreen = UIColor(named: "Green (card background)")!
static let cardBackgroundYellow = UIColor(named: "Yellow (card background)")!
static let cardBackgroundGray = UIColor(named: "Gray (card background)")!
static let pureBlue = UIColor(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0)
static let pureRed = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
static let navBar = UIColor(red: 155.0/255.0, green: 225.0/255.0, blue: 255.0/255.0, alpha: 1.0)
}
static let shared = AppTheme()
@@ -28,14 +28,6 @@ class EQNBaseContainerTableViewCell: UITableViewCell {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
view.layer.cornerRadius = AppTheme.shared.cardCornerRadius
view.layer.masksToBounds = false
// add shadow
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.5
view.layer.shadowOffset = CGSize(width: 0, height: 2)
view.layer.shadowRadius = 2
return view
}()
@@ -80,6 +72,15 @@ class EQNBaseContainerTableViewCell: UITableViewCell {
/// Text to display inside the header
var headerText: String { "" }
override var backgroundColor: UIColor? {
set {
internalContainerView.backgroundColor = newValue
}
get {
internalContainerView.backgroundColor
}
}
// MARK: - Init
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
@@ -93,12 +94,20 @@ class EQNBaseContainerTableViewCell: UITableViewCell {
setupUI()
updateUI()
}
// MARK: - View Lifecycle
override func layoutSubviews() {
super.layoutSubviews()
containerView.eqn_applyRoundedCorners()
internalContainerView.eqn_applyShadowAndRoundedCorners()
}
// MARK: - Internal
func setupUI() {
selectionStyle = .default
backgroundColor = .clear
super.backgroundColor = .clear
contentView.addSubview(internalContainerView)
@@ -1,26 +0,0 @@
//
// EQNBaseTableViewCell.swift
// Earthquake Network
//
// Created by Busi Andrea on 07/10/2020.
// Copyright © 2020 Earthquake Network. All rights reserved.
//
import Foundation
class EQNBaseTableViewCell: UITableViewCell {
@IBOutlet weak var containerView: UIView!
// MARK: - View Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
clipsToBounds = true
// rounded corners and shadow
containerView.eqn_applyShadowAndRoundedCorners()
}
}
@@ -5,7 +5,7 @@
"Rilevato sisma debole a" = "رصد زلزال خفيف في ميلانو %@";
"Rilevato sisma forte a" = "رصد زلزال قوي في ميلانو %@";
"Rilevato sisma a" = "رصد زلزال في ميلانو %@";
"Sisma segnalato da utente a" = "أبلغ المستخدم عن الزلزال في %@";
"Sisma segnalato da utente a" = "تم الإبلاغ عن الزلزال من قبل مستخدمي التطبيق في %@";
"Sisma lieve segnalato da utente a" = "Mild quake reported by user at %@"; // replaced by alert_intensity_mild
"Sisma forte segnalato da utente a" = "Strong quake reported by user at %@"; // replaced by alert_intensity_moderate
"Sisma molto forte segnalato da utente a" = "Very strong quake reported by user at %@"; // replaced by alert_intensity_strong
@@ -26,7 +26,7 @@
"drawer_privacy" = "الخصوصيات";
"tab_network" = "تنبيهات";
"tab_manual" = "تقارير";
"tab_official" = "الشبكات الزلزالية";
"tab_official" = "قائمة الزلزال";
"inapp_available_10k" = "\U200FTop 10K %lu اشتراكات لا تزال متوفرة ليتم تنبيهها في أقل من ثانية واحدة منذ اكتشاف الزلزال";
"inapp_available_100k" = "\U200FTop 100K %lu اشتراكات لا تزال متوفرة ليتم تنبيهها في أقل من 5 ثوان منذ اكتشاف الزلزال";
"filter_filter" = "اختر الزلازل التي تريد عرضها";
@@ -44,6 +44,7 @@
"filter_empty_area" = "لا توجد زلازل خلال الـ 24 ساعة الماضية وفقًا للمرشحات";
"filter_empty_relevant" = "لم تكن هناك زلازل ذات صلة بموقعك خلال الـ 24 ساعة الماضية";
"filter_nolocation" = "هذا الخيار غير متاح لأن موقعك غير معروف";
"official_filter_changed" = "تم تغيير مرشحات القائمة لإظهار الزلزال الذي تم الإبلاغ عنه";
"official_provider" = "المصدر: %@";
"share_hashtag" = "#زلزال أرضي";
"share_notified" = "قررت من خلال التطبيق منبه الزلازل. قم بتنزيل التطبيق من https://sismo.app/download/ لاستلام تنبيهات في الوقت الفعلي حول #earthquake @SismoDetector";
@@ -84,7 +85,7 @@
"options_official_maxdist" = "المسافة القصو";
"options_notification_manual" = "إشعارات تقرير المستخدم";
"options_notification_enable_manual" = "استلم الإخطارات للزلازل التي أبلغ عنها يدويا من قبل المستخدمين";
"main_areacheck_message" = "في الوقت الحالي ، يوجد في منطقتك %s هواتف ذكية تراقب الزلازل في الوقت الفعلي. قدرة شبكة الهاتف الذكي على اكتشاف الزلازل في الوقت الفعلي هي%@. لتحسين اكتشاف الزلازل في منطقتك ، شارك التطبيق مع عائلتك وأصدقائك ، شكرًا!";
"main_areacheck_message" = "في الوقت الحالي ، يوجد في منطقتك %@ هواتف ذكية تراقب الزلازل في الوقت الفعلي. لتحسين اكتشاف الزلازل في منطقتك ، شارك التطبيق مع عائلتك وأصدقائك ، شكرًا!";
"main_version" = "نموذج";
"app_name" = "منبه الزلازل";
"official_depth" = "العمق:";
@@ -215,7 +216,7 @@
"attention" = "انتباه";
"official_no_country_selected" = "لم تقم بتحديد أي بلد";
"report" = "التقارير";
"purchase_pro_restore" = "يعيد";
"purchase_pro_restore" = "استعادة الاشتراكات";
"purchase_pro_restore_alert_title" = "اكتملت الاستعادة";
"purchase_pro_restore_alert_message" = "لقد استعدت المنتج الذي اشتريته";
"purchase_pro_no_subscriptions_alert_message" = "لم يتم العثور على شراء للاستعادة. تأكد من تسجيل الدخول إلى الحساب الذي تم الشراء به.";
@@ -5,9 +5,10 @@
"Rilevato sisma debole a" = "Ήπιο σεισμό που ανιχνεύεται στο %@";
"Rilevato sisma forte a" = "Ισχυρός σεισμός που ανιχνεύεται στο %@";
"Rilevato sisma a" = "Ο σεισμός ανιχνεύθηκε στο %@";
"Sisma lieve segnalato da utente a" = "Ήπιο σεισμό που αναφέρθηκε από έναν χρήστη στο %@";
"Sisma forte segnalato da utente a" = "Ισχυρός σεισμός που αναφέρθηκε από έναν χρήστη στο %@";
"Sisma molto forte segnalato da utente a" = "Πολύ ισχυρός σεισμός που αναφέρθηκε από έναν χρήστη στο %@";
"Sisma segnalato da utente a" = "Σεισμός που αναφέρθηκε από χρήστες της εφαρμογής στο %@";
"Sisma lieve segnalato da utente a" = "Ήπιο σεισμό που αναφέρθηκε από έναν χρήστη στο %@"; // not used, to be removed
"Sisma forte segnalato da utente a" = "Ισχυρός σεισμός που αναφέρθηκε από έναν χρήστη στο %@"; // not used, to be removed
"Sisma molto forte segnalato da utente a" = "Πολύ ισχυρός σεισμός που αναφέρθηκε από έναν χρήστη στο %@"; // not used, to be removed
"Sisma rilevato a" = "Ο σεισμός ανιχνεύθηκε στο %@";
"alert_intensity_no_shaking" = "Δεν γίνεται αισθητό στην τοποθεσία σας";
"alert_intensity_mild" = "Να περιμένετε ήπιο ή καθόλου κούνημα";
@@ -25,7 +26,7 @@
"drawer_privacy" = "Ιδιωτικό απόρρητο";
"tab_network" = "ΕΙΔΟΠΟΙΗΣΕΙΣ";
"tab_manual" = "ΑΝΑΦΟΡΕΣ";
"tab_official" = "ΣΕΙΣΜΙΚΑ ΔΙΚΤΥΑ";
"tab_official" = "Λιστα σεισμων";
"inapp_available_10k" = "Top 10K: %lu εγγραφές είναι ακόμη διαθέσιμες για ειδοποίηση σε λιγότερο από 1 δευτερόλεπτο από την ανίχνευση του σεισμού";
"inapp_available_100k" = "Top 100K: %lu εγγραφή είναι ακόμη διαθέσιμη για ειδοποίηση σε λιγότερο από 5 δευτερόλεπτα από την ανίχνευση του σεισμού";
"filter_filter" = "Επιλέξτε ποιους σεισμούς θέλετε να δείτε";
@@ -43,6 +44,7 @@
"filter_empty_area" = "Δεν υπάρχουν σεισμοί τις τελευταίες 24 ώρες σύμφωνα με τα φίλτρα";
"filter_empty_relevant" = "Δεν υπάρχουν σχετικοί σεισμοί τις τελευταίες 24 ώρες σε σχέση με την τοποθεσία σας";
"filter_nolocation" = "Αυτή η επιλογή δεν είναι διαθέσιμη επειδή η τοποθεσία σας είναι άγνωστη";
"official_filter_changed" = "Τα φίλτρα της λίστας έχουν αλλάξει για να εμφανιστεί ο ειδοποιημένος σεισμός";
"official_provider" = "Πηγή: %@";
"share_hashtag" = "#σεισμός";
"share_notified" = "Έχει αναφερθεί μέσω της εφαρμογής Ανιχνευτής Σεισμών. Κατέβασε την εφαρμογή από το https://sismo.app/download/ για να λαμβάνεις σε πραγματικό χρόνο ειδοποιήσεις #σεισμού @SismoDetector";
@@ -214,7 +216,7 @@
"attention" = "Προσοχή";
"official_no_country_selected" = "Δεν έχετε επιλέξει καμία χώρα";
"report" = "Αναφορά";
"purchase_pro_restore" = "Επαναφέρω";
"purchase_pro_restore" = "Επαναφορά συνδρομών";
"purchase_pro_restore_alert_title" = "Επαναφέρω ολοκληρώθηκε";
"purchase_pro_restore_alert_message" = "Έχετε αποκαταστήσει το προϊόν που αγοράσατε";
"purchase_pro_no_subscriptions_alert_message" = "Δεν βρέθηκε αγορά αγοράς. Βεβαιωθείτε ότι έχετε συνδεθεί στο λογαριασμό, η αγορά έγινε με.";
@@ -5,9 +5,10 @@
"Rilevato sisma debole a" = "Mild quake detected at %@";
"Rilevato sisma forte a" = "Strong quake detected at %@";
"Rilevato sisma a" = "Quake detected at %@";
"Sisma lieve segnalato da utente a" = "Mild quake reported by user at %@";
"Sisma forte segnalato da utente a" = "Strong quake reported by user at %@";
"Sisma molto forte segnalato da utente a" = "Very strong quake reported by user at %@";
"Sisma segnalato da utente a" = "Earthquake reported by the app users at %@";
"Sisma lieve segnalato da utente a" = "Mild quake reported by user at %@"; // not used, to be removed
"Sisma forte segnalato da utente a" = "Strong quake reported by user at %@"; // not used, to be removed
"Sisma molto forte segnalato da utente a" = "Very strong quake reported by user at %@"; // not used, to be removed
"Sisma rilevato a" = "Quake detected at %@";
"alert_intensity_no_shaking" = "Not felt at your location";
"alert_intensity_mild" = "Expect mild or no shaking";
@@ -25,7 +26,7 @@
"drawer_privacy" = "Privacy";
"tab_network" = "ALERTS";
"tab_manual" = "REPORTS";
"tab_official" = "SEISMIC NETWORKS";
"tab_official" = "Quake list";
"inapp_available_10k" = "Top 10K: %lu subscriptions still available to be alerted in less than 1 second since the detection of the quake";
"inapp_available_100k" = "Top 100K: %lu subscriptions still available to be alerted in less than 5 seconds since the detection of the quake";
"filter_filter" = "Choose which earthquakes you want to view";
@@ -43,10 +44,11 @@
"filter_empty_area" = "Nessun sisma nelle ultime 24 ore in base ai filtri impostati";
"filter_empty_relevant" = "No relevant earthquakes in the last 24 hours with respect to your location";
"filter_nolocation" = "This option is not available because your location is unknown";
"official_filter_changed" = "List filters have been changed in order to show the notified earthquake";
"official_provider" = "Source: %@";
"share_hashtag" = "#earthquake";
"share_notified" = "Reported through the app Earthquake Network. Download the app from https://sismo.app/download/ to receive real time alerts of #earthquake @SismoDetector";
"manual_sure" = "Do you really want to notify an earthquake?";
"manual_sure" = "Do you really want to report an earthquake?";
"manual_yes" = "Yes";
"filter_area" = "Quakes shown: in the radius";
"filter_relevant" = "Quakes shown: relevant";
@@ -214,7 +216,7 @@
"attention" = "Attention";
"official_no_country_selected" = "You have not selected any country";
"report" = "Report";
"purchase_pro_restore" = "Restore";
"purchase_pro_restore" = "Restore subscriptions";
"purchase_pro_restore_alert_title" = "Restore completed";
"purchase_pro_restore_alert_message" = "You have restored the product you purchased";
"purchase_pro_no_subscriptions_alert_message" = "No purchase was found to restore. Make sure you are logged into the account the purchase was made with.";
@@ -5,9 +5,10 @@
"Rilevato sisma debole a" = "Leve sismo detectado en %@";
"Rilevato sisma forte a" = "Fuerte sismo detectado en %@";
"Rilevato sisma a" = "Sismo detectado e %@";
"Sisma lieve segnalato da utente a" = "Sismo leve informado por un usuario en %@";
"Sisma forte segnalato da utente a" = "Fuerte sismo reportado por un usuario en %@";
"Sisma molto forte segnalato da utente a" = "Sismo muy fuerte reportado por un usuario en %@";
"Sisma segnalato da utente a" = "Sismo reportado por los usuarios de la aplicación en %@";
"Sisma lieve segnalato da utente a" = "Sismo leve informado por un usuario en %@"; // not used, to be removed
"Sisma forte segnalato da utente a" = "Fuerte sismo reportado por un usuario en %@"; // not used, to be removed
"Sisma molto forte segnalato da utente a" = "Sismo muy fuerte reportado por un usuario en %@"; // not used, to be removed
"Sisma rilevato a" = "Sismo detectado en %@";
"alert_intensity_no_shaking" = "No se siente en tu ubicación";
"alert_intensity_mild" = "Espera movimiento leve o nulo";
@@ -25,7 +26,7 @@
"drawer_privacy" = "Privacy";
"tab_network" = "ALERTAS";
"tab_manual" = "REPORTES";
"tab_official" = "REDES SÍSMICAS";
"tab_official" = "Lista sismos";
"inapp_available_10k" = "Top 10K: %lu suscripciones aún disponibles para recibir la alerta en menos de 1 segundo a partir de la detección del sismo";
"inapp_available_100k" = "Top 100K: %lu suscripciones aún disponibles para recibir la alerta en menos de 5 segundos a partir de la detección del sismo";
"filter_filter" = "Elige qué sismos quieres ver";
@@ -43,6 +44,7 @@
"filter_empty_area" = "No hay sismos en las últimas 24 horas según los filtros";
"filter_empty_relevant" = "No hay sismos relevantes en las últimas 24 horas con respecto a tu ubicación";
"filter_nolocation" = "Esta opción no está disponible porque tu ubicación es desconocida";
"official_filter_changed" = "Los filtros de lista se han cambiado para mostrar el sismo notificado";
"official_provider" = "Fuente: %@";
"share_hashtag" = "#sismo";
"share_notified" = "Reportado a través de la app Sismo Detector. Descarga la app desde https://sismo.app/download/ para recibir alertas de #sismo en tiempo real @SismoDetector";
@@ -66,7 +68,7 @@
"globe_simulation_message1" = "Con este epicentro, deberías recibir la alerta %.0f segundos antes. Sin embargo, %.0f personas serán alertadas antes que tú. El tiempo de aviso será de %.0f segundos. Al suscribirse hoy al servicio de prioridad TOP 10K, solo %.0f personas recibirán la alerta antes que usted (en orden de distancia del epicentro)";
"globe_simulation_message2" = "Con este epicentro, deberías recibir la alerta %.0f segundos antes. Sin embargo, %.0f personas serán alertadas antes que tú. Recibirá la alerta %.0f segundos después de las ondas sísmicas. Al suscribirse hoy al servicio de prioridad TOP 10K, solo %.0f personas recibirán la alerta antes que usted (en orden de distancia del epicentro)";
"globe_simulation_message3" = "Con este epicentro, deberías recibir la alerta %.0f segundos antes. Sin embargo, %.0f personas serán alertadas antes que tú. Al suscribirse hoy al servicio de prioridad TOP 10K, solo %.0f personas recibirán la alerta antes que usted (en orden de distancia del epicentro)";
"globe_simulation_message4" = "Con este epicentro, gracias al servicio de prioridad %@, deberías recibir la alerta %.0f segundos antes. Solo %@ personas serán alertadas antes que tú";
"globe_simulation_message4" = "Con este epicentro, gracias al servicio de prioridad %@, deberías recibir la alerta %.0f segundos antes. Solo %.0f personas serán alertadas antes que tú";
"globe_simulation_message5" = "Con este epicentro, gracias al servicio de prioridad %@, deberías recibir la alerta %.0f segundos antes. %.0f personas serán alertadas antes que tú. Para aumentar el tiempo de advertencia, puede suscribirse al servicio de prioridad %@";
"globe_simulation_message6" = "Con este epicentro, gracias al servicio de prioridad %@, deberías recibir la alerta %.0f segundos antes. ¡Serás la primera persona en ser alertada!";
"globe_simulation_priority" = "Servicio prioritario";
@@ -214,7 +216,7 @@
"attention" = "Atención";
"official_no_country_selected" = "No has seleccionado ningún país";
"report" = "Informe";
"purchase_pro_restore" = "Restaurar";
"purchase_pro_restore" = "Restablecer suscripciones";
"purchase_pro_restore_alert_title" = "Restauración completada";
"purchase_pro_restore_alert_message" = "Has restaurado el producto que compraste.";
"purchase_pro_no_subscriptions_alert_message" = "No se encontró ninguna compra para restaurar. Asegúrese de haber iniciado sesión en la cuenta con la que se realizó la compra.";
@@ -5,9 +5,10 @@
"Rilevato sisma debole a" = "Séisme léger détecté à %@";
"Rilevato sisma forte a" = "Fort séisme détecté à %@";
"Rilevato sisma a" = "Séisme détecté à %@";
"Sisma lieve segnalato da utente a" = "Séisme léger signalé par un utilisateur à %@";
"Sisma forte segnalato da utente a" = "Fort séisme signalé par un utilisateur à %@";
"Sisma molto forte segnalato da utente a" = "Très fort séisme signalé par un utilisateur à %@";
"Sisma segnalato da utente a" = "Séisme signalé par les utilisateurs de l'application à %@";
"Sisma lieve segnalato da utente a" = "Séisme léger signalé par un utilisateur à %@"; // not used, to be removed
"Sisma forte segnalato da utente a" = "Fort séisme signalé par un utilisateur à %@"; // not used, to be removed
"Sisma molto forte segnalato da utente a" = "Très fort séisme signalé par un utilisateur à %@"; // not used, to be removed
"Sisma rilevato a" = "Séisme détecté à %@";
"alert_intensity_no_shaking" = "Pas ressenti à votre emplacement";
"alert_intensity_mild" = "Attendez-vous à des secousses légères ou nulles";
@@ -25,7 +26,7 @@
"drawer_privacy" = "Confidentialité";
"tab_network" = "ALERTES";
"tab_manual" = "SIGNALEMENTS";
"tab_official" = "RÉSEAUX SISMIQUES";
"tab_official" = "Liste des séisme";
"inapp_available_10k" = "Top 10K : %lu abonnements encore disponibles pour être alerté en moins de 1 seconde à partir de la détection du séisme";
"inapp_available_100k" = "Top 100K : %lu abonnements encore disponibles pour être alerté en moins de 5 secondes à partir de la détection du séisme";
"filter_filter" = "Choisissez les tremblements de terre que vous souhaitez visualiser";
@@ -43,6 +44,7 @@
"filter_empty_area" = "Aucun tremblement de terre au cours des dernières 24 heures selon les filtres";
"filter_empty_relevant" = "Aucun tremblement de terre pertinent au cours des dernières 24 heures par rapport à votre emplacement";
"filter_nolocation" = "EsCette option n'est pas disponible car votre emplacement est inconnu";
"official_filter_changed" = "Les filtres de liste ont été modifiés afin d\'afficher le séisme signalé";
"official_provider" = "Source : %@";
"share_hashtag" = "#séisme";
"share_notified" = "Signalé via l'app Détecteur de Séisme. Téléchargez l'app depuis https://sismo.app/download/ pour recevoir des alertes de #séisme en temps réel @SismoDetector";
@@ -214,7 +216,7 @@
"attention" = "Attention";
"official_no_country_selected" = "Vous n'avez sélectionné aucun pays";
"report" = "Signaler";
"purchase_pro_restore" = "Restaurer";
"purchase_pro_restore" = "Restaurer les abonnements";
"purchase_pro_restore_alert_title" = "Restauration terminée";
"purchase_pro_restore_alert_message" = "Vous avez restauré le produit que vous avez acheté";
"purchase_pro_no_subscriptions_alert_message" = "Aucun achat à restaurer n'a été trouvé. Assurez-vous que vous êtes connecté au compte avec lequel l'achat a été effectué.";
@@ -5,9 +5,10 @@
"Rilevato sisma debole a" = "Blagi potres otkriven u %@";
"Rilevato sisma forte a" = "Snažan potres otkriven u %@";
"Rilevato sisma a" = "Potres otkriven u %@";
"Sisma lieve segnalato da utente a" = "Blagi potres prijavio korisnik u %@";
"Sisma forte segnalato da utente a" = "Snažan potres prijavio korisnik u %@";
"Sisma molto forte segnalato da utente a" = "Vrlo jak potres prijavio korisnik u %@";
"Sisma segnalato da utente a" = "Korisnici aplikacije prijavili potres u %@";
"Sisma lieve segnalato da utente a" = "Blagi potres prijavio korisnik u %@"; // not used, to be removed
"Sisma forte segnalato da utente a" = "Snažan potres prijavio korisnik u %@"; // not used, to be removed
"Sisma molto forte segnalato da utente a" = "Vrlo jak potres prijavio korisnik u %@"; // not used, to be removed
"Sisma rilevato a" = "Potres otkriven u %@";
"alert_intensity_no_shaking" = "Ne osjeća se na vašoj lokaciji";
"alert_intensity_mild" = "Očekujte blago podrhtavanje ili ga nema";
@@ -25,7 +26,7 @@
"drawer_privacy" = "Privatnost";
"tab_network" = "UPOZORENJA";
"tab_manual" = "PRIJAVE";
"tab_official" = "SEIZMOLOŠKE MREŽE";
"tab_official" = "Popis potresa";
"inapp_available_10k" = "Top 10K: Dostupan je sljedeći broj pretplata za primanje upozorenja za manje od 1 sekunde od otkrivanja potresa: %lu";
"inapp_available_100k" = "Top 100K: Dostupan je sljedeći broj pretplata za primanje upozorenja za manje od 1 sekunde od otkrivanja potresa: %lu";
"filter_filter" = "Odaberite koje potrese želite vidjeti";
@@ -43,10 +44,11 @@
"filter_empty_area" = "Nema potresa u posljednja 24 sata prema filtrima";
"filter_empty_relevant" = "Nema relevantnih potresa u posljednja 24 sata u odnosu na vašu lokaciju";
"filter_nolocation" = "Ova opcija nije dostupna jer je vaša lokacija nepoznata";
"official_filter_changed" = "Filtri popisa su promijenjeni kako bi se prikazao prijavljeni potres";
"official_provider" = "Izvor: %@";
"share_hashtag" = "#potres";
"share_notified" = "Prijavljen putem aplikacije Detektor Potresa. Preuzmite aplikaciju na https://sismo.app/download/ da biste u stvarnom vremenu primali upozorenja kada se dogodi #potres @DetektorPotresa";
"manual_sure" = "Želite li zaista poslati obavijest o potresu?";
"manual_sure" = "Želite li stvarno poslati izvješće o potresu?";
"manual_yes" = "Da";
"filter_area" = "Prikazani potresi: u polumjeru";
"filter_relevant" = "Prikazani potresi: relevantni";
@@ -214,7 +216,7 @@
"attention" = "Pažnja";
"official_no_country_selected" = "Niste odabrali nijednu zemlju";
"report" = "Izvješće";
"purchase_pro_restore" = "Vratiti";
"purchase_pro_restore" = "Obnovi pretplate";
"purchase_pro_restore_alert_title" = "Vraćanje dovršeno";
"purchase_pro_restore_alert_message" = "Obnovili ste proizvod koji ste kupili";
"purchase_pro_no_subscriptions_alert_message" = "Nije pronađena nijedna kupnja za vraćanje. Obavezno se prijavite na račun s kojim je obavljena kupnja.";
@@ -5,9 +5,10 @@
"Rilevato sisma debole a" = "Gempa ringan terdeteksi di %@";
"Rilevato sisma forte a" = "Gempa kuat terdeteksi di %@";
"Rilevato sisma a" = "Gempa terdeteksi di %@";
"Sisma lieve segnalato da utente a" = "Gempa ringan dilaporkan oleh pengguna di %@";
"Sisma forte segnalato da utente a" = "Gempa kuat dilaporkan oleh pengguna di %@";
"Sisma molto forte segnalato da utente a" = "Gempa sangat kuat dilaporkan oleh pengguna di %@";
"Sisma segnalato da utente a" = "Gempa bumi yang dilaporkan oleh pengguna aplikasi di %@";
"Sisma lieve segnalato da utente a" = "Gempa ringan dilaporkan oleh pengguna di %@"; // not used, to be removed
"Sisma forte segnalato da utente a" = "Gempa kuat dilaporkan oleh pengguna di %@"; // not used, to be removed
"Sisma molto forte segnalato da utente a" = "Gempa sangat kuat dilaporkan oleh pengguna di %@"; // not used, to be removed
"Sisma rilevato a" = "Gempa terdeteksi di %@";
"alert_intensity_no_shaking" = "Tidak terasa di lokasi Anda";
"alert_intensity_mild" = "Harapkan ringan atau tidak ada guncangan";
@@ -25,7 +26,7 @@
"drawer_privacy" = "Privasi";
"tab_network" = "PERINGATAN";
"tab_manual" = "LAPORAN";
"tab_official" = "JARINGAN SEISMIK";
"tab_official" = "Daftar gempa";
"inapp_available_10k" = "Top 10K: %lu langganan masih tersedia untuk mendapat peringatan dalam waktu kurang dari 1 detik sejak deteksi gempa";
"inapp_available_100k" = "Top 100K: %lu langganan masih tersedia untuk mendapat peringatan dalam waktu kurang dari 5 detik sejak deteksi gempa";
"filter_filter" = "Pilih gempa mana yang ingin Anda lihat";
@@ -43,6 +44,7 @@
"filter_empty_area" = "Tidak ada gempa bumi dalam 24 jam terakhir menurut filter";
"filter_empty_relevant" = "Tidak ada gempa bumi yang relevan dalam 24 jam terakhir sehubungan dengan lokasi Anda";
"filter_nolocation" = "Opsi ini tidak tersedia karena lokasi Anda tidak diketahui";
"official_filter_changed" = "Filter daftar telah diubah untuk menampilkan pemberitahuan gempa";
"official_provider" = "Sumber: %@";
"share_hashtag" = "#gempa";
"share_notified" = "Dilaporkan melalui aplikasi Detektor Gempa. Unduh aplikasi dari https://sismo.app/download/ untuk menerima peringatan real time #gempa @SismoDetector";
@@ -214,7 +216,7 @@
"attention" = "Perhatian";
"official_no_country_selected" = "Anda belum memilih negara mana pun";
"report" = "Melaporkan";
"purchase_pro_restore" = "Mengembalikan";
"purchase_pro_restore" = "Pulihkan langganan";
"purchase_pro_restore_alert_title" = "Kembalikan selesai";
"purchase_pro_restore_alert_message" = "Anda telah memulihkan produk yang Anda belid";
"purchase_pro_no_subscriptions_alert_message" = "Tidak ada pembelian yang ditemukan untuk dipulihkan. Pastikan Anda masuk ke akun tempat pembelian dilakukan.";
@@ -5,9 +5,10 @@
"Rilevato sisma debole a" = "Sisma leggero rilevato a %@";
"Rilevato sisma forte a" = "Sisma forte rilevato a %@";
"Rilevato sisma a" = "Sisma rilevato a %@";
"Sisma lieve segnalato da utente a" = "Sisma lieve segnalato da un utente a %@";
"Sisma forte segnalato da utente a" = "Sisma forte segnalato da un utente a %@";
"Sisma molto forte segnalato da utente a" = "Sisma molto forte segnalato da un utente at %@";
"Sisma segnalato da utente a" = "Sisma segnalato dagli utenti dell'app a %@";
"Sisma lieve segnalato da utente a" = "Sisma lieve segnalato da un utente a %@"; // not used, to be removed
"Sisma forte segnalato da utente a" = "Sisma forte segnalato da un utente a %@"; // not used, to be removed
"Sisma molto forte segnalato da utente a" = "Sisma molto forte segnalato da un utente at %@"; // not used, to be removed
"Sisma rilevato a" = "Sisma rilevato a %@";
"alert_intensity_no_shaking" = "Non percepito dove ti trovi";
"alert_intensity_mild" = "Previsto uno scuotimento leggero o nullo";
@@ -25,7 +26,7 @@
"drawer_privacy" = "Privacy";
"tab_network" = "ALLERTE";
"tab_manual" = "SEGNALAZIONI";
"tab_official" = "RETI SISMICHE";
"tab_official" = "Lista sismi";
"inapp_available_10k" = "Top 10K: %lu sottoscrizioni ancora disponibili per essere allertato in meno di 1 secondo dal rilevamento del sisma";
"inapp_available_100k" = "Top 100K: %lu sottoscrizioni ancora disponibili per essere allertato in meno di 5 secondi dal rilevamento del sisma";
"filter_filter" = "Scegli quali sismi vuoi visualizzare";
@@ -43,6 +44,7 @@
"filter_empty_area" = "Nessun sisma nelle ultime 24 ore in base ai filtri impostati";
"filter_empty_relevant" = "Nessun sisma rilevante nelle ultime 24 ore rispetto alla tua posizione";
"filter_nolocation" = "Questa opzione non è disponibile perché la tua posizione è sconosciuta";
"official_filter_changed" = "I filtri della lista sono stati modificati per mostrare il sisma notificato";
"official_provider" = "Fonte: %@";
"share_hashtag" = "#terremoto";
"share_notified" = "Segnalato tramite la app Rilevatore Terremoto. Scarica la app da https://sismo.app/download/ per ricevere allerte #terremoto in tempo reale @SismoDetector";
@@ -214,7 +216,7 @@
"attention" = "Attenzione";
"official_no_country_selected" = "Non hai selezionato alcuna nazione";
"report" = "Report";
"purchase_pro_restore" = "Ripristina";
"purchase_pro_restore" = "Ripristina abbonamenti";
"purchase_pro_restore_alert_title" = "Ripristino completato";
"purchase_pro_restore_alert_message" = "Hai ripristinato il prodotto che avevi acquistato";
"purchase_pro_no_subscriptions_alert_message" = "Non è stato trovato alcun prodotto da ripristinare. Assicurati di essere registrato con l'account dal quale avevi fatto l'acquisto.";
@@ -5,9 +5,10 @@
"Rilevato sisma debole a" = "%@'da hafif deprem tespit edildi";
"Rilevato sisma forte a" = "%@'da şiddetli deprem tespit edildi";
"Rilevato sisma a" = "%@'da deprem tespit edildi";
"Sisma lieve segnalato da utente a" = "%@da kullanıcı tarafından bildirilen hafif deprem";
"Sisma forte segnalato da utente a" = "%@'da kullanıcı tarafından bildirilen şiddetli deprem";
"Sisma molto forte segnalato da utente a" = "@'da kullanıcı tarafından bildirilen çok şiddetli deprem";
"Sisma segnalato da utente a" = "Uygulama kullanıcıları tarafından %@'de bildirilen deprem";
"Sisma lieve segnalato da utente a" = "%@da kullanıcı tarafından bildirilen hafif deprem"; // not used, to be removed
"Sisma forte segnalato da utente a" = "%@'da kullanıcı tarafından bildirilen şiddetli deprem"; // not used, to be removed
"Sisma molto forte segnalato da utente a" = "@'da kullanıcı tarafından bildirilen çok şiddetli deprem"; // not used, to be removed
"Sisma rilevato a" = "%@'da deprem tespit edildi";
"alert_intensity_no_shaking" = "Bulunduğunuz yerde hissedilmiyor";
"alert_intensity_mild" = "Hafif veya hiç titreme beklemeyin";
@@ -25,7 +26,7 @@
"drawer_privacy" = "Gizlilik";
"tab_network" = "UYARILAR";
"tab_manual" = "RAPORLAR";
"tab_official" = "SİSMİK AĞLAR";
"tab_official" = "Deprem listesi";
"inapp_available_10k" = "Top 10K: Hala depremin tespitinden itibaren 1 saniyeden daha kısa süre içinde uyarı alacak %lu abonelik mevcut";
"inapp_available_100k" = "Top 100K: Hala depremin tespitinden itibaren 5 saniyeden daha kısa süre içinde uyarı alacak %lu abonelik mevcut";
"filter_filter" = "Görüntülemek istediğiniz depremleri seçin";
@@ -43,6 +44,7 @@
"filter_empty_area" = "Filtrelere göre son 24 saatte deprem yok";
"filter_empty_relevant" = "Son 24 saat içinde konumunuza göre alakalı deprem yok";
"filter_nolocation" = "Konumunuz bilinmediğinden bu seçenek kullanılamıyor";
"official_filter_changed" = "Bildirilen depremin gösterilmesi için liste filtreleri değiştirildi";
"official_provider" = "Kaynak: %@";
"share_hashtag" = "#deprem";
"share_notified" = "Deprem Ağı uygulaması aracılığıyla bildirildi. @SismoDetector gerçek zamanlı #deprem uyarılarını almak için uygulamayı https://sismo.app/download/ adresinden indirin.";
@@ -214,7 +216,7 @@
"attention" = "Dikkat";
"official_no_country_selected" = "Herhangi bir ülke seçmediniz";
"report" = "Bildiri";
"purchase_pro_restore" = "Geri yükle";
"purchase_pro_restore" = "Abonelikleri geri yükle";
"purchase_pro_restore_alert_title" = "Geri yükleme tamamlandı";
"purchase_pro_restore_alert_message" = "Satın aldığınız ürünü geri yüklediniz";
"purchase_pro_no_subscriptions_alert_message" = "Geri yüklenecek satın alma bulunamadı. Satın alma işleminin yapıldığı hesapta oturum açtığınızdan emin olun.";