Commit 606f1463 by Demid Merzlyakov

NWSAlerts storage.

parent 70f2f2d4
......@@ -169,6 +169,10 @@
CE28475226159A32006C8DC5 /* BlendHealthModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE28475126159A32006C8DC5 /* BlendHealthModels.swift */; };
CE28475D2615A5B3006C8DC5 /* Health.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE28475C2615A5B3006C8DC5 /* Health.swift */; };
CE2847602615A8AD006C8DC5 /* BlendHealthSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE28475F2615A8AD006C8DC5 /* BlendHealthSource.swift */; };
CE308B262637EA88001ECD8A /* CoreNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE308B242637EA87001ECD8A /* CoreNotifications.swift */; };
CE308B272637EA88001ECD8A /* CoreNWSAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE308B252637EA87001ECD8A /* CoreNWSAlert.swift */; };
CE308B2A2637EA8E001ECD8A /* _CoreNWSAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE308B282637EA8E001ECD8A /* _CoreNWSAlert.swift */; };
CE308B2B2637EA8E001ECD8A /* _CoreNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE308B292637EA8E001ECD8A /* _CoreNotifications.swift */; };
CE376C98261EE484000B1159 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE376C97261EE484000B1159 /* LaunchScreen.storyboard */; };
CE578FD325F7E89400E8B85D /* DayTimeWeather.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE578FD225F7E89400E8B85D /* DayTimeWeather.swift */; };
CE578FE525FB415F00E8B85D /* CityCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE578FE225FB415F00E8B85D /* CityCell.swift */; };
......@@ -417,6 +421,10 @@
CE28475126159A32006C8DC5 /* BlendHealthModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlendHealthModels.swift; sourceTree = "<group>"; };
CE28475C2615A5B3006C8DC5 /* Health.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Health.swift; sourceTree = "<group>"; };
CE28475F2615A8AD006C8DC5 /* BlendHealthSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlendHealthSource.swift; sourceTree = "<group>"; };
CE308B242637EA87001ECD8A /* CoreNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreNotifications.swift; sourceTree = "<group>"; };
CE308B252637EA87001ECD8A /* CoreNWSAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreNWSAlert.swift; sourceTree = "<group>"; };
CE308B282637EA8E001ECD8A /* _CoreNWSAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _CoreNWSAlert.swift; sourceTree = "<group>"; };
CE308B292637EA8E001ECD8A /* _CoreNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _CoreNotifications.swift; sourceTree = "<group>"; };
CE376C97261EE484000B1159 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
CE578FD225F7E89400E8B85D /* DayTimeWeather.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayTimeWeather.swift; sourceTree = "<group>"; };
CE578FE225FB415F00E8B85D /* CityCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CityCell.swift; sourceTree = "<group>"; };
......@@ -1177,6 +1185,8 @@
CE89629626175DF500CA274A /* _CoreLocation.swift */,
CE89629726175DF500CA274A /* _CoreCurrentWeather.swift */,
CE89629826175DF500CA274A /* _CoreDailyWeather.swift */,
CE308B292637EA8E001ECD8A /* _CoreNotifications.swift */,
CE308B282637EA8E001ECD8A /* _CoreNWSAlert.swift */,
);
path = Machine;
sourceTree = "<group>";
......@@ -1192,6 +1202,8 @@
CE89629E26175DF500CA274A /* CoreLocation.swift */,
CE89629F26175DF500CA274A /* CoreDailyWeather.swift */,
CE8962A126175DF500CA274A /* CoreHourlyWeather.swift */,
CE308B242637EA87001ECD8A /* CoreNotifications.swift */,
CE308B252637EA87001ECD8A /* CoreNWSAlert.swift */,
);
path = Human;
sourceTree = "<group>";
......@@ -1574,6 +1586,7 @@
CE13B814262480B3007CBD4D /* BRNativeBannerView.swift in Sources */,
CE13B7E126247BF9007CBD4D /* UserDefaultsOptionalValue.swift in Sources */,
CE8962A626175DF500CA274A /* _CoreHealth.swift in Sources */,
CE308B2B2637EA8E001ECD8A /* _CoreNotifications.swift in Sources */,
CE28475226159A32006C8DC5 /* BlendHealthModels.swift in Sources */,
CE13B80D262480B3007CBD4D /* AdConfig.swift in Sources */,
CE8962A926175DF500CA274A /* _CoreDailyWeather.swift in Sources */,
......@@ -1593,6 +1606,7 @@
CDD0F1EE25725BCF00CF5017 /* ThemeManager.swift in Sources */,
87D815852636CFFE0015A6D1 /* NWSAlertViewController.swift in Sources */,
CD1237F4255D889F00C98139 /* GradientView.swift in Sources */,
CE308B262637EA88001ECD8A /* CoreNotifications.swift in Sources */,
CD37D3EF260DF4E6002669D6 /* SettingsViewController.swift in Sources */,
CE6BE4942634170800626822 /* USStateCode.swift in Sources */,
CD593BC926089FC100C93428 /* UITableView+HeaderSize.swift in Sources */,
......@@ -1695,6 +1709,7 @@
87D815B32636F2040015A6D1 /* NWSAlertInfoBlockTableViewCell.swift in Sources */,
CD32CE0B260C744A00235081 /* MenuCoordinator.swift in Sources */,
CD55E0BB2615EE2400CC4DC7 /* PollutantView.swift in Sources */,
CE308B2A2637EA8E001ECD8A /* _CoreNWSAlert.swift in Sources */,
CE13B81C262480B3007CBD4D /* Interstitial.swift in Sources */,
CEC526FA25E7959A00DA58A5 /* WeatherSource.swift in Sources */,
CDF4808F261727E00076E9F5 /* CLAuthorizationStatus+Localized.swift in Sources */,
......@@ -1727,6 +1742,7 @@
CE13B80C262480B3007CBD4D /* AdConfigManager.swift in Sources */,
CE13B81F262480B3007CBD4D /* UserDefaultsWrapper.swift in Sources */,
CD17C5F625D15B4400EE884E /* TodayViewController.swift in Sources */,
CE308B272637EA88001ECD8A /* CoreNWSAlert.swift in Sources */,
CD86245E25E646350097F3FB /* SunUvView.swift in Sources */,
CEAFF08325DFC67F00DF4EBF /* Location.swift in Sources */,
CEFB857226174F7A00C5CDD2 /* Storage.swift in Sources */,
......
......@@ -179,6 +179,7 @@ public class LocationManager {
assertionFailure("Either error or locations have to be nil, not both")
return
}
self.nwsAlertsManager.loadAlerts(from: locations)
self.set(locations: locations, selectedIndex: selectedIndex)
}
}
......
......@@ -61,6 +61,20 @@ public class NWSAlertsManager {
public var alerts = [NWSAlert]()
public func loadAlerts(from locations: [Location]) {
internalQueue.addOperation { [weak self] in
var allAlerts = [NWSAlert]()
for location in locations {
if let locationAlerts = location.notifications?.nwsAlerts {
allAlerts = allAlerts + locationAlerts
}
}
if allAlerts.count > 0 {
self?.merge(alerts: allAlerts)
}
}
}
public func fetchActiveAlerts(for location: Location, completion: @escaping NWSAlertsManager.Completion) {
internalQueue.addOperation { [weak self] in
let extendedCompletion: NWSAlertsManager.Completion = { [weak self] (updatedLocation, error) in
......
......@@ -95,21 +95,42 @@
<relationship name="daily" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreDailyWeather" inverseName="location" inverseEntity="CoreDailyWeather"/>
<relationship name="health" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreHealth" inverseName="location" inverseEntity="CoreHealth"/>
<relationship name="hourly" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreHourlyWeather" inverseName="location" inverseEntity="CoreHourlyWeather"/>
<relationship name="notifications" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreNotifications" inverseName="location" inverseEntity="CoreNotifications"/>
<relationship name="today" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreCurrentWeather" inverseName="location" inverseEntity="CoreCurrentWeather"/>
</entity>
<entity name="CoreNotifications" representedClassName="CoreNotifications" syncable="YES">
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="location" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreLocation" inverseName="notifications" inverseEntity="CoreLocation"/>
<relationship name="nwsAlerts" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreNWSAlert" inverseName="notifications" inverseEntity="CoreNWSAlert"/>
</entity>
<entity name="CoreNWSAlert" representedClassName="CoreNWSAlert" syncable="YES">
<attribute name="city" attributeType="String"/>
<attribute name="descriptionText" attributeType="String"/>
<attribute name="expires" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="messageID" attributeType="String"/>
<attribute name="messageURL" attributeType="String"/>
<attribute name="read" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="severityLevel" attributeType="String"/>
<attribute name="timeZone" attributeType="String"/>
<attribute name="weatherID" attributeType="String"/>
<attribute name="weatherMessage" optional="YES" attributeType="String"/>
<relationship name="notifications" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreNotifications" inverseName="nwsAlerts" inverseEntity="CoreNotifications"/>
</entity>
<entity name="CorePollutant" representedClassName="CorePollutant" syncable="YES">
<attribute name="name" attributeType="String"/>
<attribute name="value" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<relationship name="health" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreHealth" inverseName="pollutants" inverseEntity="CoreHealth"/>
</entity>
<elements>
<element name="CoreAppData" positionX="114.79296875" positionY="-494.5078125" width="128" height="73"/>
<element name="CoreAirQuality" positionX="438.48828125" positionY="-201.96875" width="128" height="88"/>
<element name="CoreAppData" positionX="114.79296875" positionY="-494.5078125" width="128" height="73"/>
<element name="CoreCurrentWeather" positionX="-105.953125" positionY="-203.82421875" width="128" height="418"/>
<element name="CoreDailyWeather" positionX="270.5546875" positionY="-505.83203125" width="128" height="313"/>
<element name="CoreHealth" positionX="277.1640625" positionY="-156.77734375" width="128" height="103"/>
<element name="CoreHourlyWeather" positionX="279.15234375" positionY="-29.234375" width="128" height="238"/>
<element name="CoreLocation" positionX="113.6640625" positionY="-337.08984375" width="128" height="313"/>
<element name="CoreLocation" positionX="113.6640625" positionY="-337.08984375" width="128" height="328"/>
<element name="CorePollutant" positionX="438.171875" positionY="-103.41015625" width="128" height="88"/>
<element name="CoreNotifications" positionX="-153.28125" positionY="-336.6484375" width="128" height="88"/>
<element name="CoreNWSAlert" positionX="-315.77734375" positionY="-337.84375" width="128" height="208"/>
</elements>
</model>
\ No newline at end of file
......@@ -33,6 +33,7 @@ open class CoreLocation: _CoreLocation, CoreDataAppModelConvertable {
}
location.health = try self.health?.toAppModel()
location.notifications = try self.notifications?.toAppModel()
return location
}
......@@ -76,7 +77,12 @@ open class CoreLocation: _CoreLocation, CoreDataAppModelConvertable {
try CoreHourlyWeather(context: context, appModel: elem)
}
})
self.health = skipIfError(attribute: "health", action: { try CoreHealth(context: context, appModel: appModel.health) })
self.health = skipIfError(attribute: "health", action: {
try CoreHealth(context: context, appModel: appModel.health)
})
self.notifications = skipIfError(attribute: "notifications", action: {
try CoreNotifications(context: context, appModel: appModel.notifications)
})
}
private func skipIfError<T>(attribute: String, action: () throws -> T?) -> T? {
......
import Foundation
import CoreData
@objc(CoreNWSAlert)
open class CoreNWSAlert: _CoreNWSAlert, CoreDataAppModelConvertable {
func toAppModel() throws -> NWSAlert {
let severityLevel: NWSSeverityLevel = try CoreDataUtils.appValue(name: "severityLevel", value: self.severityLevel, in: self)
let timeZone = try CoreDataUtils.timeZone(from: self.timeZone, in: self, attributeName: "timeZone")
let result = NWSAlert(weatherID: weatherID,
messageID: messageID,
messageURL: messageURL,
severityLevel: severityLevel,
description: descriptionText,
expires: expires,
weatherMessage: weatherMessage,
city: city,
timeZone: timeZone,
read: read,
extendedInfo: nil) // not saving extendedInfo, since it can be regenerated.
return result
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: NWSAlert?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.weatherID = appModel.weatherID
self.messageID = appModel.messageID
self.messageURL = appModel.messageURL
self.severityLevel = appModel.severityLevel.rawValue
self.descriptionText = appModel.description
self.expires = appModel.expires
self.weatherMessage = appModel.weatherMessage
self.city = appModel.city
self.timeZone = try CoreDataUtils.timeZoneToString(appModel.timeZone, in: self, attributeName: "timeZone")
self.read = appModel.read
// not saving extendedInfo, since it can be regenerated.
}
typealias AppModel = NWSAlert
}
import Foundation
import CoreData
@objc(CoreNotifications)
open class CoreNotifications: _CoreNotifications, CoreDataAppModelConvertable {
func toAppModel() throws -> Notifications {
var notifications = Notifications(updatedAt: updatedAt, nwsAlerts: [NWSAlert]())
try CoreDataUtils.foreach(in: self.nwsAlerts, of: self, attributeName: "nwsAlerts", do: { (coreNwsAlert: CoreNWSAlert) in
notifications.nwsAlerts.append(try coreNwsAlert.toAppModel())
})
return notifications
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: Notifications?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.updatedAt = appModel.updatedAt
self.nwsAlerts = NSOrderedSet(array: appModel.nwsAlerts.compactMap { elem in
skipIfError(attribute: "nwsAlerts") {
try CoreNWSAlert(context: context, appModel: elem)
}
})
}
typealias AppModel = Notifications
private func skipIfError<T>(attribute: String, action: () throws -> T?) -> T? {
do {
let result = try action()
return result
}
catch {
Logger(componentName: "CoreLocation").error("Couldn't parse \(attribute) in CoreLocation due to error: \(error)")
return nil
}
}
}
......@@ -25,6 +25,7 @@ public enum CoreLocationRelationships: String {
case daily = "daily"
case health = "health"
case hourly = "hourly"
case notifications = "notifications"
case today = "today"
}
......@@ -120,6 +121,9 @@ open class _CoreLocation: NSManagedObject {
}
@NSManaged open
var notifications: CoreNotifications?
@NSManaged open
var today: CoreCurrentWeather?
}
......
// DO NOT EDIT. This file is machine-generated and constantly overwritten.
// Make changes to CoreNWSAlert.swift instead.
import Foundation
import CoreData
public enum CoreNWSAlertAttributes: String {
case city = "city"
case descriptionText = "descriptionText"
case expires = "expires"
case messageID = "messageID"
case messageURL = "messageURL"
case read = "read"
case severityLevel = "severityLevel"
case timeZone = "timeZone"
case weatherID = "weatherID"
case weatherMessage = "weatherMessage"
}
public enum CoreNWSAlertRelationships: String {
case notifications = "notifications"
}
open class _CoreNWSAlert: NSManagedObject {
// MARK: - Class methods
open class func entityName () -> String {
return "CoreNWSAlert"
}
open class func entity(managedObjectContext: NSManagedObjectContext) -> NSEntityDescription? {
return NSEntityDescription.entity(forEntityName: self.entityName(), in: managedObjectContext)
}
@nonobjc
open class func fetchRequest() -> NSFetchRequest<CoreNWSAlert> {
return NSFetchRequest(entityName: self.entityName())
}
// MARK: - Life cycle methods
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
public convenience init?(managedObjectContext: NSManagedObjectContext) {
guard let entity = _CoreNWSAlert.entity(managedObjectContext: managedObjectContext) else { return nil }
self.init(entity: entity, insertInto: managedObjectContext)
}
// MARK: - Properties
@NSManaged open
var city: String!
@NSManaged open
var descriptionText: String!
@NSManaged open
var expires: Date!
@NSManaged open
var messageID: String!
@NSManaged open
var messageURL: String!
@NSManaged open
var read: Bool
@NSManaged open
var severityLevel: String!
@NSManaged open
var timeZone: String!
@NSManaged open
var weatherID: String!
@NSManaged open
var weatherMessage: String?
// MARK: - Relationships
@NSManaged open
var notifications: CoreNotifications?
}
// DO NOT EDIT. This file is machine-generated and constantly overwritten.
// Make changes to CoreNotifications.swift instead.
import Foundation
import CoreData
public enum CoreNotificationsAttributes: String {
case updatedAt = "updatedAt"
}
public enum CoreNotificationsRelationships: String {
case location = "location"
case nwsAlerts = "nwsAlerts"
}
open class _CoreNotifications: NSManagedObject {
// MARK: - Class methods
open class func entityName () -> String {
return "CoreNotifications"
}
open class func entity(managedObjectContext: NSManagedObjectContext) -> NSEntityDescription? {
return NSEntityDescription.entity(forEntityName: self.entityName(), in: managedObjectContext)
}
@nonobjc
open class func fetchRequest() -> NSFetchRequest<CoreNotifications> {
return NSFetchRequest(entityName: self.entityName())
}
// MARK: - Life cycle methods
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
public convenience init?(managedObjectContext: NSManagedObjectContext) {
guard let entity = _CoreNotifications.entity(managedObjectContext: managedObjectContext) else { return nil }
self.init(entity: entity, insertInto: managedObjectContext)
}
// MARK: - Properties
@NSManaged open
var updatedAt: Date!
// MARK: - Relationships
@NSManaged open
var location: CoreLocation?
@NSManaged open
var nwsAlerts: NSOrderedSet
open func nwsAlertsSet() -> NSMutableOrderedSet {
return self.nwsAlerts.mutableCopy() as! NSMutableOrderedSet
}
}
extension _CoreNotifications {
open func addNwsAlerts(_ objects: NSOrderedSet) {
let mutable = self.nwsAlerts.mutableCopy() as! NSMutableOrderedSet
mutable.union(objects)
self.nwsAlerts = mutable.copy() as! NSOrderedSet
}
open func removeNwsAlerts(_ objects: NSOrderedSet) {
let mutable = self.nwsAlerts.mutableCopy() as! NSMutableOrderedSet
mutable.minus(objects)
self.nwsAlerts = mutable.copy() as! NSOrderedSet
}
open func addNwsAlertsObject(_ value: CoreNWSAlert) {
let mutable = self.nwsAlerts.mutableCopy() as! NSMutableOrderedSet
mutable.add(value)
self.nwsAlerts = mutable.copy() as! NSOrderedSet
}
open func removeNwsAlertsObject(_ value: CoreNWSAlert) {
let mutable = self.nwsAlerts.mutableCopy() as! NSMutableOrderedSet
mutable.remove(value)
self.nwsAlerts = mutable.copy() as! NSOrderedSet
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment