Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
1
1weather
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dmitriy Stepanets
1weather
Commits
e45681f9
Commit
e45681f9
authored
Apr 22, 2021
by
Demid Merzlyakov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added alert info parser.
parent
9b149a6a
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
286 additions
and
89 deletions
+286
-89
1Weather.xcodeproj/project.pbxproj
+17
-9
1Weather.xcodeproj/xcshareddata/xcschemes/1Weather.xcscheme
+1
-1
1Weather/Model/ModelObjects/Notifications/AppNotification.swift
+0
-27
1Weather/Model/ModelObjects/Notifications/WeatherAlert.swift
+0
-23
1Weather/Network/Notifications/Model/NWSAlert.swift
+2
-26
1Weather/Network/Notifications/Model/NWSAlertExtendedInfo.swift
+16
-0
1Weather/Network/Notifications/Model/NWSAlertInfoBlock.swift
+13
-0
1Weather/Network/Notifications/Model/NWSSeverityLevel.swift
+34
-0
1Weather/Network/Notifications/NWSAlertInfoParser.swift
+203
-0
1Weather/StuffThatIsPresentInTheMainProject.swift
+0
-3
No files found.
1Weather.xcodeproj/project.pbxproj
View file @
e45681f9
...
...
@@ -154,8 +154,6 @@
CE13B88F26248A77007CBD4D
/* GoogleService-Info-Staging.plist in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE13B88D26248A77007CBD4D
/* GoogleService-Info-Staging.plist */
;
};
CE13B97B2626FB11007CBD4D
/* PSMLocationSDK.xcframework in Frameworks */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE13B7DC262478E7007CBD4D
/* PSMLocationSDK.xcframework */
;
};
CE13B97C2626FB11007CBD4D
/* PSMLocationSDK.xcframework in Embed Frameworks */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE13B7DC262478E7007CBD4D
/* PSMLocationSDK.xcframework */
;
settings
=
{
ATTRIBUTES
=
(
CodeSignOnCopy
,
RemoveHeadersOnCopy
,
);
};
};
CE13B98226272A1F007CBD4D
/* AppNotification.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE13B98126272A1F007CBD4D
/* AppNotification.swift */
;
};
CE13B98526272E18007CBD4D
/* WeatherAlert.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE13B98426272E18007CBD4D
/* WeatherAlert.swift */
;
};
CE13B98726273236007CBD4D
/* NWSAlert.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE13B98626273236007CBD4D
/* NWSAlert.swift */
;
};
CE28474F26159857006C8DC5
/* HealthSource.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE28474E26159857006C8DC5
/* HealthSource.swift */
;
};
CE28475226159A32006C8DC5
/* BlendHealthModels.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE28475126159A32006C8DC5
/* BlendHealthModels.swift */
;
};
...
...
@@ -210,6 +208,10 @@
CEDE4F0B25EFA3A7007457E9
/* UpdatableModelObject.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEDE4F0A25EFA3A7007457E9
/* UpdatableModelObject.swift */
;
};
CEDE4F0F25EFA3B4007457E9
/* UpdatableModelObjectInTime.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEDE4F0E25EFA3B4007457E9
/* UpdatableModelObjectInTime.swift */
;
};
CEE0A179262FA9650044C257
/* DelayedSaveStorage.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEE0A178262FA9650044C257
/* DelayedSaveStorage.swift */
;
};
CEE0A17B263179E60044C257
/* NWSAlertInfoBlock.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEE0A17A263179E50044C257
/* NWSAlertInfoBlock.swift */
;
};
CEE0A1A026317A1E0044C257
/* NWSAlertExtendedInfo.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEE0A19F26317A1E0044C257
/* NWSAlertExtendedInfo.swift */
;
};
CEE0A1A226317A3F0044C257
/* NWSSeverityLevel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEE0A1A126317A3F0044C257
/* NWSSeverityLevel.swift */
;
};
CEE0A1A426317A8F0044C257
/* NWSAlertInfoParser.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEE0A1A326317A8F0044C257
/* NWSAlertInfoParser.swift */
;
};
CEF959652600C2F900975FAA
/* AnalyticsService.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEF959642600C2F900975FAA
/* AnalyticsService.swift */
;
};
CEF959692600C30500975FAA
/* Global.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEF959682600C30500975FAA
/* Global.swift */
;
};
CEF9596C2600C32E00975FAA
/* AnalyticsEvent.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEF9596B2600C32E00975FAA
/* AnalyticsEvent.swift */
;
};
...
...
@@ -389,8 +391,6 @@
CE13B809262480B3007CBD4D
/* Scheduler.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Scheduler.swift
;
sourceTree
=
"<group>"
;
};
CE13B88C26248A77007CBD4D
/* GoogleService-Info-Production.plist */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text.plist.xml
;
path
=
"GoogleService-Info-Production.plist"
;
sourceTree
=
"<group>"
;
};
CE13B88D26248A77007CBD4D
/* GoogleService-Info-Staging.plist */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text.plist.xml
;
path
=
"GoogleService-Info-Staging.plist"
;
sourceTree
=
"<group>"
;
};
CE13B98126272A1F007CBD4D
/* AppNotification.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
AppNotification.swift
;
sourceTree
=
"<group>"
;
};
CE13B98426272E18007CBD4D
/* WeatherAlert.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WeatherAlert.swift
;
sourceTree
=
"<group>"
;
};
CE13B98626273236007CBD4D
/* NWSAlert.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
NWSAlert.swift
;
sourceTree
=
"<group>"
;
};
CE28474E26159857006C8DC5
/* HealthSource.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
HealthSource.swift
;
sourceTree
=
"<group>"
;
};
CE28475126159A32006C8DC5
/* BlendHealthModels.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
BlendHealthModels.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -445,6 +445,10 @@
CEDE4F0A25EFA3A7007457E9
/* UpdatableModelObject.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
UpdatableModelObject.swift
;
sourceTree
=
"<group>"
;
};
CEDE4F0E25EFA3B4007457E9
/* UpdatableModelObjectInTime.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
UpdatableModelObjectInTime.swift
;
sourceTree
=
"<group>"
;
};
CEE0A178262FA9650044C257
/* DelayedSaveStorage.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
DelayedSaveStorage.swift
;
sourceTree
=
"<group>"
;
};
CEE0A17A263179E50044C257
/* NWSAlertInfoBlock.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
NWSAlertInfoBlock.swift
;
sourceTree
=
"<group>"
;
};
CEE0A19F26317A1E0044C257
/* NWSAlertExtendedInfo.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
NWSAlertExtendedInfo.swift
;
sourceTree
=
"<group>"
;
};
CEE0A1A126317A3F0044C257
/* NWSSeverityLevel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
NWSSeverityLevel.swift
;
sourceTree
=
"<group>"
;
};
CEE0A1A326317A8F0044C257
/* NWSAlertInfoParser.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
NWSAlertInfoParser.swift
;
sourceTree
=
"<group>"
;
};
CEF959642600C2F900975FAA
/* AnalyticsService.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
AnalyticsService.swift
;
sourceTree
=
"<group>"
;
};
CEF959682600C30500975FAA
/* Global.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Global.swift
;
sourceTree
=
"<group>"
;
};
CEF9596B2600C32E00975FAA
/* AnalyticsEvent.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
AnalyticsEvent.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -1004,6 +1008,7 @@
children
=
(
CE13B98026272A13007CBD4D
/* Model */
,
CE0456232629C04C003D252B
/* NWSAlertsManager.swift */
,
CEE0A1A326317A8F0044C257
/* NWSAlertInfoParser.swift */
,
);
path
=
Notifications
;
sourceTree
=
"<group>"
;
...
...
@@ -1011,8 +1016,11 @@
CE13B98026272A13007CBD4D
/* Model */
=
{
isa
=
PBXGroup
;
children
=
(
CE13B98626273236007CBD4D
/* NWSAlert.swift */
,
CE04561E26282325003D252B
/* NWSCurrentEventsReponse.swift */
,
CE13B98626273236007CBD4D
/* NWSAlert.swift */
,
CEE0A1A126317A3F0044C257
/* NWSSeverityLevel.swift */
,
CEE0A19F26317A1E0044C257
/* NWSAlertExtendedInfo.swift */
,
CEE0A17A263179E50044C257
/* NWSAlertInfoBlock.swift */
,
);
path
=
Model
;
sourceTree
=
"<group>"
;
...
...
@@ -1020,8 +1028,6 @@
CE13B98326272A59007CBD4D
/* Notifications */
=
{
isa
=
PBXGroup
;
children
=
(
CE13B98126272A1F007CBD4D
/* AppNotification.swift */
,
CE13B98426272E18007CBD4D
/* WeatherAlert.swift */
,
87D81581262EFC9A0015A6D1
/* Notifications.swift */
,
);
path
=
Notifications
;
...
...
@@ -1509,6 +1515,7 @@
CDD0F1E82572429E00CF5017
/* AppFont.swift in Sources */
,
CE8962AA26175DF500CA274A
/* CoreAirQuality.swift in Sources */
,
CE28475D2615A5B3006C8DC5
/* Health.swift in Sources */
,
CEE0A1A026317A1E0044C257
/* NWSAlertExtendedInfo.swift in Sources */
,
CDC6124F25E7964700188DA7
/* TodayDayTimesCell.swift in Sources */
,
CD593BC226088A5900C93428
/* TimePeriodOffsetHolder.swift in Sources */
,
CE8962A226175DF500CA274A
/* _CoreAirQuality.swift in Sources */
,
...
...
@@ -1553,6 +1560,7 @@
CDC6125725E7AB1A00188DA7
/* TodayAirQualityCell.swift in Sources */
,
CD593BCF2608A50900C93428
/* ForecastHourlyCell.swift in Sources */
,
CD6B3036257262C2004B34B3
/* UIColor+Highlight.swift in Sources */
,
CEE0A17B263179E60044C257
/* NWSAlertInfoBlock.swift in Sources */
,
CD1DDD332602305200AC62B2
/* ForecastInfoCell.swift in Sources */
,
CEDE4E8425EEFD56007457E9
/* WdtDailySummariesArray.swift in Sources */
,
CDEE8AD725DA882200C289DE
/* ForecastPeriodButton.swift in Sources */
,
...
...
@@ -1627,9 +1635,11 @@
CE13B98726273236007CBD4D
/* NWSAlert.swift in Sources */
,
CE13B819262480B3007CBD4D
/* A9Cache.swift in Sources */
,
CE578FE625FB415F00E8B85D
/* LocationViewController.swift in Sources */
,
CEE0A1A226317A3F0044C257
/* NWSSeverityLevel.swift in Sources */
,
CD86246525E66E8A0097F3FB
/* PrecipitationCell.swift in Sources */
,
CD80917B2578E4A8003541A4
/* UIViewController+Alert.swift in Sources */
,
CEF959932600C63500975FAA
/* Analytics.swift in Sources */
,
CEE0A1A426317A8F0044C257
/* NWSAlertInfoParser.swift in Sources */
,
CE13B821262480B3007CBD4D
/* Scheduler.swift in Sources */
,
CEDE4F0F25EFA3B4007457E9
/* UpdatableModelObjectInTime.swift in Sources */
,
CE13B81E262480B3007CBD4D
/* AdCacheManager.swift in Sources */
,
...
...
@@ -1658,11 +1668,9 @@
CEAFF0A325E0FF0800DF4EBF
/* LocationManager.swift in Sources */
,
CE13B7E226247BF9007CBD4D
/* UserDefaultsValue.swift in Sources */
,
CEAD00A12577B2D5003596AD
/* StuffThatIsPresentInTheMainProject.swift in Sources */
,
CE13B98226272A1F007CBD4D
/* AppNotification.swift in Sources */
,
CEDE4E8925EEFFEF007457E9
/* WdtDayNight.swift in Sources */
,
CE13B820262480B3007CBD4D
/* AdLogger.swift in Sources */
,
CDF48092261729680076E9F5
/* UIApplication+Settings.swift in Sources */
,
CE13B98526272E18007CBD4D
/* WeatherAlert.swift in Sources */
,
);
runOnlyForDeploymentPostprocessing
=
0
;
};
...
...
1Weather.xcodeproj/xcshareddata/xcschemes/1Weather.xcscheme
View file @
e45681f9
...
...
@@ -72,7 +72,7 @@
buildConfiguration =
"Debug"
>
</AnalyzeAction>
<ArchiveAction
buildConfiguration =
"
Release
"
buildConfiguration =
"
Debug
"
revealArchiveInOrganizer =
"YES"
>
</ArchiveAction>
</Scheme>
1Weather/Model/ModelObjects/Notifications/AppNotification.swift
deleted
100644 → 0
View file @
9b149a6a
//
// Notification.swift
// 1Weather
//
// Created by Demid Merzlyakov on 14.04.2021.
//
import
Foundation
protocol
AppNotification
{
var
date
:
Date
{
get
}
var
title
:
String
{
get
}
var
text
:
String
?
{
get
}
var
location
:
Location
?
{
get
}
var
expires
:
Date
?
{
get
}
var
expired
:
Bool
{
get
}
}
extension
AppNotification
{
var
expired
:
Bool
{
guard
let
expires
=
expires
else
{
return
false
}
return
Date
()
<
expires
}
}
1Weather/Model/ModelObjects/Notifications/WeatherAlert.swift
deleted
100644 → 0
View file @
9b149a6a
//
// NWSAlert.swift
// 1Weather
//
// Created by Demid Merzlyakov on 14.04.2021.
//
import
Foundation
struct
WeatherAlert
:
AppNotification
{
var
date
:
Date
var
title
:
String
var
text
:
String
?
var
location
:
Location
?
var
expires
:
Date
?
var
whatText
:
String
?
var
whereText
:
String
?
var
whenText
:
String
?
var
impactText
:
String
?
var
instructionsText
:
String
?
var
targetAreaText
:
String
?
}
1Weather/Network/Notifications/Model/NWSAlert.swift
View file @
e45681f9
...
...
@@ -7,32 +7,6 @@
import
Foundation
public
enum
NWSSeverityLevel
:
String
,
Codable
,
Comparable
{
case
warning
=
"1"
case
watch
=
"2"
case
advisory
=
"3"
public
static
func
<
(
lhs
:
Self
,
rhs
:
Self
)
->
Bool
{
lhs
!=
rhs
&&
(
(
lhs
==
.
warning
)
||
(
lhs
==
.
watch
&&
rhs
==
.
advisory
)
)
}
public
static
func
<=
(
lhs
:
Self
,
rhs
:
Self
)
->
Bool
{
lhs
==
rhs
||
lhs
<
rhs
}
public
static
func
>=
(
lhs
:
Self
,
rhs
:
Self
)
->
Bool
{
lhs
==
rhs
||
lhs
>
rhs
}
public
static
func
>
(
lhs
:
Self
,
rhs
:
Self
)
->
Bool
{
lhs
!=
rhs
&&
!
(
lhs
<
rhs
)
}
}
public
struct
NWSAlert
:
Codable
,
Equatable
,
Hashable
{
public
var
issueDate
:
Date
?
public
let
weatherID
:
String
...
...
@@ -47,6 +21,8 @@ public struct NWSAlert: Codable, Equatable, Hashable {
/// This property is set by NWSAlertManager after decoding the response.
public
var
city
:
String
=
""
public
var
extendedInfo
:
NWSAlertExtendedInfo
?
// Used to encode/decode a JSON object to send/recieve data with the server
private
enum
CodingKeys
:
String
,
CodingKey
{
case
weatherID
...
...
1Weather/Network/Notifications/Model/NWSAlertExtendedInfo.swift
0 → 100644
View file @
e45681f9
//
// NWSAlertExtendedInfo.swift
// 1Weather
//
// Created by Demid Merzlyakov on 22.04.2021.
//
import
Foundation
public
struct
NWSAlertExtendedInfo
:
Codable
{
public
var
title
:
String
?
public
var
issueDate
:
Date
?
public
var
expiryDate
:
Date
?
public
var
issuer
:
String
?
public
var
infoBlocks
:
[
NWSAlertInfoBlock
]
=
[
NWSAlertInfoBlock
]()
}
1Weather/Network/Notifications/Model/NWSAlertInfoBlock.swift
0 → 100644
View file @
e45681f9
//
// NWSAlertInfoBlock.swift
// 1Weather
//
// Created by Demid Merzlyakov on 22.04.2021.
//
import
Foundation
public
struct
NWSAlertInfoBlock
:
Codable
{
let
title
:
String
?
let
text
:
String
?
}
1Weather/Network/Notifications/Model/NWSSeverityLevel.swift
0 → 100644
View file @
e45681f9
//
// NWSSeverityLevel.swift
// 1Weather
//
// Created by Demid Merzlyakov on 22.04.2021.
//
import
Foundation
public
enum
NWSSeverityLevel
:
String
,
Codable
,
Comparable
{
case
warning
=
"1"
case
watch
=
"2"
case
advisory
=
"3"
public
static
func
<
(
lhs
:
Self
,
rhs
:
Self
)
->
Bool
{
lhs
!=
rhs
&&
(
(
lhs
==
.
warning
)
||
(
lhs
==
.
watch
&&
rhs
==
.
advisory
)
)
}
public
static
func
<=
(
lhs
:
Self
,
rhs
:
Self
)
->
Bool
{
lhs
==
rhs
||
lhs
<
rhs
}
public
static
func
>=
(
lhs
:
Self
,
rhs
:
Self
)
->
Bool
{
lhs
==
rhs
||
lhs
>
rhs
}
public
static
func
>
(
lhs
:
Self
,
rhs
:
Self
)
->
Bool
{
lhs
!=
rhs
&&
!
(
lhs
<
rhs
)
}
}
1Weather/Network/Notifications/NWSAlertInfoParser.swift
0 → 100644
View file @
e45681f9
//
// NWSAlertInfoParser.swift
// 1Weather
//
// Created by Demid Merzlyakov on 22.04.2021.
//
import
Foundation
class
NWSAlertInfoParser
{
public
func
fetchExtendedInfo
(
for
alert
:
NWSAlert
,
completion
:
@escaping
(
NWSAlertExtendedInfo
?)
->
())
{
let
log
=
Logger
(
componentName
:
"NWSAlertInfoParser (alert
\(
alert
.
messageID
)
)"
)
log
.
info
(
"URL:
\(
alert
.
messageURL
)
"
)
guard
let
url
=
URL
(
string
:
alert
.
messageURL
)
else
{
log
.
error
(
"Bad URL"
)
completion
(
nil
)
return
}
let
urlSession
=
URLSession
.
shared
urlSession
.
dataTask
(
with
:
url
)
{
[
weak
self
]
(
data
,
response
,
error
)
in
guard
let
self
=
self
else
{
return
}
if
let
httpResponse
=
response
as?
HTTPURLResponse
{
guard
httpResponse
.
statusCode
>=
200
&&
httpResponse
.
statusCode
<
400
else
{
log
.
error
(
"HTTP error
\(
httpResponse
.
statusCode
)
"
)
completion
(
nil
)
return
}
}
guard
let
data
=
data
,
let
responseString
=
String
(
data
:
data
,
encoding
:
.
utf8
)
else
{
log
.
error
(
"Empty response"
)
completion
(
nil
)
return
}
let
extendedInfo
:
NWSAlertExtendedInfo
=
self
.
parseExtendedInfo
(
from
:
responseString
)
completion
(
extendedInfo
)
}
}
// MARK: - Private methods
private
static
var
dateFormatter
:
DateFormatter
=
{
let
dateFormatter
=
DateFormatter
()
// Date examples:
// April 15 at 4:24AM MDT
// April 14 at 9:32PM CDT
// April 15 at 9:33AM EDT
dateFormatter
.
dateFormat
=
"yyyy MMMM d 'at' h:mma zzz"
dateFormatter
.
locale
=
Locale
(
identifier
:
"en-US"
)
return
dateFormatter
}()
private
func
parse
(
dateString
:
String
,
shouldBeInThePast
:
Bool
)
->
Date
?
{
// There's no year here, so we've got to guess.
let
currentDate
=
Date
()
let
calendar
=
Calendar
(
identifier
:
.
gregorian
)
guard
let
currentYear
=
calendar
.
dateComponents
([
.
year
],
from
:
currentDate
)
.
year
else
{
return
nil
}
let
dateStringWithCurrentYear
=
"
\(
currentYear
)
\(
dateString
)
"
if
shouldBeInThePast
{
guard
let
dateWithCurrentYear
=
NWSAlertInfoParser
.
dateFormatter
.
date
(
from
:
dateStringWithCurrentYear
)
else
{
return
nil
}
if
dateWithCurrentYear
>
currentDate
{
let
dateStringWithPreviousYear
=
"
\(
currentYear
-
1
)
\(
dateString
)
"
return
NWSAlertInfoParser
.
dateFormatter
.
date
(
from
:
dateStringWithPreviousYear
)
}
else
{
return
dateWithCurrentYear
}
}
else
{
return
NWSAlertInfoParser
.
dateFormatter
.
date
(
from
:
dateStringWithCurrentYear
)
}
}
private
func
parse
(
firstLine
:
String
)
->
NWSAlertExtendedInfo
{
// A few first line examples:
// Winter Weather Advisory issued April 15 at 4:24AM MDT until April 16 at 9:00AM MDT by NWS RapidCity
// Flood Warning issued April 14 at 9:32PM CDT until April 19 at 7:00AM CDT by NWS New Orleans
// Rip Current Statement issued April 15 at 9:33AM EDT until April 17 at 8:00AM EDT by NWS Mobile
// Flood Warning issued April 14 at 8:10PM CDT until April 16 at 9:00PM CDT by NWS Saint Louis
// So, the structure is:
// <TITLE> issued <ISSUE_DATE_TIME> until <EXPIRE_DATE_TIME> by <ISSUER>
var
result
=
NWSAlertExtendedInfo
()
// Using try!, since it's a hardcoded regexp, which has to be correct. If it's not, I want it to fail here and now, while I'm debugging this.
let
titlePattern
=
"(?<title>.+?)"
let
issuedDatePattern
=
"(?<issuedDate>[a-z0-9: ]*?)"
let
expiryDatePattern
=
"(?<expiryDate>[a-z0-9: ]*?)"
let
issuerPattern
=
"(?<issuer>.+)"
let
fullPattern
=
"
\(
titlePattern
)
issued
\(
issuedDatePattern
)
(?: until
\(
expiryDatePattern
)
)? by
\(
issuerPattern
)
"
let
regex
=
try
?
NSRegularExpression
(
pattern
:
fullPattern
,
options
:
.
caseInsensitive
)
guard
let
firstMatch
=
regex
?
.
matches
(
in
:
firstLine
,
range
:
NSRange
(
firstLine
.
startIndex
...
,
in
:
firstLine
))
.
first
else
{
return
result
}
result
.
title
=
(
firstLine
as
NSString
)
.
substring
(
with
:
firstMatch
.
range
(
withName
:
"title"
))
let
issuedDateString
=
(
firstLine
as
NSString
)
.
substring
(
with
:
firstMatch
.
range
(
withName
:
"issuedDate"
))
result
.
issueDate
=
parse
(
dateString
:
issuedDateString
,
shouldBeInThePast
:
true
)
let
expiryDateRange
=
firstMatch
.
range
(
withName
:
"expiryDate"
)
if
expiryDateRange
.
location
!=
NSNotFound
{
let
expiryDateString
=
(
firstLine
as
NSString
)
.
substring
(
with
:
expiryDateRange
)
result
.
expiryDate
=
parse
(
dateString
:
expiryDateString
,
shouldBeInThePast
:
false
)
}
result
.
issuer
=
(
firstLine
as
NSString
)
.
substring
(
with
:
firstMatch
.
range
(
withName
:
"issuer"
))
return
result
}
private
func
parseBlock
(
paragraph
:
String
)
->
NWSAlertInfoBlock
?
{
let
firstLineAndTheRest
=
paragraph
.
split
(
separator
:
"
\n
"
,
maxSplits
:
1
,
omittingEmptySubsequences
:
true
)
guard
let
firstLine
=
firstLineAndTheRest
.
first
else
{
return
nil
}
var
remainingLines
:
String
?
=
nil
if
firstLineAndTheRest
.
count
>
1
{
remainingLines
=
String
(
firstLineAndTheRest
[
1
])
}
var
title
:
String
?
var
paragraphText
:
String
?
if
firstLine
.
contains
(
"..."
)
{
let
firstLineBreakdown
=
firstLine
.
components
(
separatedBy
:
"..."
)
title
=
firstLineBreakdown
[
0
]
paragraphText
=
firstLineBreakdown
[
1
]
+
(
remainingLines
??
""
)
}
else
{
paragraphText
=
firstLine
+
(
remainingLines
??
""
)
}
title
=
title
?
.
trimmingCharacters
(
in
:
CharacterSet
.
whitespacesAndNewlines
)
paragraphText
=
paragraphText
?
.
trimmingCharacters
(
in
:
CharacterSet
.
whitespacesAndNewlines
)
if
title
?
.
isEmpty
==
true
{
title
=
nil
}
if
paragraphText
?
.
isEmpty
==
true
{
paragraphText
=
nil
}
guard
title
!=
nil
||
paragraphText
!=
nil
else
{
return
nil
}
return
NWSAlertInfoBlock
(
title
:
title
,
text
:
paragraphText
)
}
private
func
parseBlocks
(
from
text
:
String
)
->
[
NWSAlertInfoBlock
]
{
var
result
=
[
NWSAlertInfoBlock
]()
/*
The format of alerts is not strict, but there's some form of structure and similarities.
We're going to try our best to parse the text into meaningful blocks.
The overall structure is:
FIRST_LINE (see parse(firstLine:) )
REST_OF_TEXT (that's what we're here for)
In REST_OF_TEXT there may be just plain text, paragraphs without titlees, paragraphs with titles.
Some common elements include
• Paragraph with title:
* TITLE...PARAGRAPH_TEXT
or
...TITLE...
PARAGRAPH_TEXT
Note: sometimes in case of ...TITLE... there's just title, without the text.
• Paragraph without title:
* PARAGRAPH TEXT
• Plain text is just plain text.
*/
let
partialParagraphs
=
text
.
components
(
separatedBy
:
"
\n
* "
)
for
partialParagraph
in
partialParagraphs
{
for
paragraph
in
partialParagraph
.
components
(
separatedBy
:
"
\n
..."
)
{
let
trimmed
=
paragraph
.
trimmingCharacters
(
in
:
CharacterSet
.
whitespacesAndNewlines
)
if
let
block
=
parseBlock
(
paragraph
:
trimmed
)
{
result
.
append
(
block
)
}
}
}
return
result
}
private
func
parseExtendedInfo
(
from
response
:
String
)
->
NWSAlertExtendedInfo
{
guard
let
firstLineBreakIndex
=
response
.
firstIndex
(
of
:
"
\n
"
)
else
{
return
NWSAlertExtendedInfo
()
}
let
firstLine
=
response
.
prefix
(
upTo
:
firstLineBreakIndex
)
let
remainingText
=
response
.
suffix
(
from
:
firstLine
.
endIndex
)
var
extendedInfo
:
NWSAlertExtendedInfo
=
parse
(
firstLine
:
String
(
firstLine
))
extendedInfo
.
infoBlocks
=
parseBlocks
(
from
:
String
(
remainingText
))
return
extendedInfo
}
}
1Weather/StuffThatIsPresentInTheMainProject.swift
View file @
e45681f9
...
...
@@ -51,9 +51,6 @@ extension String {
return
self
.
trimmingCharacters
(
in
:
CharacterSet
.
whitespaces
)
}
func
trimSpaceNewlines
()
->
String
{
return
self
.
trimmingCharacters
(
in
:
CharacterSet
.
whitespacesAndNewlines
)
}
func
trim
(
_
characters
:
String
)
->
String
{
return
self
.
trimmingCharacters
(
in
:
CharacterSet
(
charactersIn
:
characters
))
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment