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
1f4dd173
Commit
1f4dd173
authored
Apr 02, 2021
by
Demid Merzlyakov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Health: show actual data.
parent
0677389b
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
73 additions
and
25 deletions
+73
-25
1Weather/Model/LocationManager.swift
+40
-2
1Weather/Network/Health/BlendHealthSource.swift
+21
-9
1Weather/Network/Health/Model/BlendHealthModels.swift
+1
-3
1Weather/UI/View controllers/Today/Cells/TodayAirQualityCell/TodayAirQualityCell.swift
+4
-4
1Weather/UI/View controllers/Today/Cells/TodayCellFactory.swift
+7
-7
No files found.
1Weather/Model/LocationManager.swift
View file @
1f4dd173
...
...
@@ -20,6 +20,7 @@ public class LocationManager {
private
let
deviceLocationMonitor
:
DeviceLocationMonitor
private
let
weatherUpdateSource
:
WeatherSource
private
let
healthSource
:
HealthSource
private
var
defaultLocation
=
Location
(
deviceLocation
:
false
,
coordinates
:
.
init
(
latitude
:
37.3230
,
longitude
:
-
122.0322
),
// Cupertino
timeZone
:
TimeZone
(
abbreviation
:
"PST"
)
!
)
{
...
...
@@ -124,11 +125,12 @@ public class LocationManager {
}
}
public
static
let
shared
=
LocationManager
(
weatherUpdateSource
:
WdtWeatherSource
())
public
static
let
shared
=
LocationManager
(
weatherUpdateSource
:
WdtWeatherSource
()
,
healthSource
:
BlendHealthSource
()
)
public
let
maxLocationsCount
=
12
public
init
(
weatherUpdateSource
:
WeatherSource
)
{
public
init
(
weatherUpdateSource
:
WeatherSource
,
healthSource
:
HealthSource
)
{
self
.
weatherUpdateSource
=
weatherUpdateSource
self
.
healthSource
=
healthSource
self
.
deviceLocationMonitor
=
DeviceLocationMonitor
()
self
.
deviceLocationMonitor
.
delegate
=
self
}
...
...
@@ -138,6 +140,7 @@ public class LocationManager {
guard
locations
.
count
>
0
else
{
log
.
info
(
"Update all: update default location if needed."
)
updateWeather
(
for
:
defaultLocation
,
updateType
:
.
full
)
updateHealth
(
for
:
defaultLocation
)
return
}
log
.
info
(
"Update all
\(
locations
.
count
)
locations if needed..."
)
...
...
@@ -148,6 +151,41 @@ public class LocationManager {
if
selectedLocation
!=
location
{
updateWeather
(
for
:
location
,
updateType
:
.
preferIncremental
)
}
updateHealth
(
for
:
location
)
}
}
public
func
updateHealth
(
for
location
:
Location
)
{
if
let
lastTimeUpdated
=
location
.
health
?
.
lastUpdateTime
{
guard
Date
()
.
timeIntervalSince
(
lastTimeUpdated
)
>=
healthSource
.
healthUpdateInterval
else
{
log
.
info
(
"Update health (
\(
location
)
): fresh enough (last updated at
\(
lastTimeUpdated
)
), skip update."
)
return
}
}
log
.
info
(
"Update health for:
\(
location
)
"
)
healthSource
.
updateHelath
(
for
:
location
)
{
[
weak
self
]
(
health
,
error
)
in
guard
let
self
=
self
else
{
return
}
guard
let
health
=
health
else
{
if
let
error
=
error
{
self
.
log
.
error
(
"Update health (
\(
location
)
) error:
\(
error
)
"
)
}
else
{
self
.
log
.
error
(
"Update health (
\(
location
)
) error: unknown error"
)
}
return
// TODO: we need to somehow track failed attempts, so that we didn't request again and again in case of an error (e.g. server is down).
}
DispatchQueue
.
main
.
async
{
if
let
indexToUpdate
=
self
.
locations
.
firstIndex
(
where
:
{
$0
==
location
})
{
self
.
locations
[
indexToUpdate
]
.
health
=
health
}
else
if
self
.
defaultLocation
==
location
{
self
.
defaultLocation
.
health
=
health
}
else
{
self
.
log
.
warning
(
"Update health: Failed to find location after update. Maybe it was deleted while the update was performed. Maybe something went wrong. Location:
\(
location
)
"
)
}
}
}
}
...
...
1Weather/Network/Health/BlendHealthSource.swift
View file @
1f4dd173
...
...
@@ -21,7 +21,13 @@ public class BlendHealthSource: HealthSource {
private
let
log
=
Logger
(
componentName
:
"BlendHealthSource"
)
#warning("Not implemented: staging / prod switching!")
//TODO: Not implemented: staging / prod switching!
private
static
let
healthCenterUrl
=
"http://sta-1w-dataaggregator.onelouder.com/1weather/api/v1/weather/current"
private
static
let
healthCenterUrlStaging
=
"http://sta-1w-dataaggregator.onelouder.com/1weather/api/v1/weather/current"
private
static
let
healthCenterUrlProduction
=
"https://pro-1w-dataaggregator.onelouder.com/1weather/api/v1/weather/current"
private
static
var
healthCenterUrl
:
String
{
return
healthCenterUrlProduction
}
private
static
let
blendAPIKeyHeaderName
=
"blend-api-key"
private
static
let
blendAPIKey
=
"0imfnc8mVLWwsAawjYr4Rx-Af50DDqtlx"
public
var
healthUpdateInterval
:
TimeInterval
=
TimeInterval
(
15
*
60
)
// 15 minutes
/// This queue is needed to synchronize access to locationsBeingUpdated. Also, to make logging more clear.
...
...
@@ -60,28 +66,34 @@ public class BlendHealthSource: HealthSource {
var
queryParameters
=
[
String
:
String
]()
if
let
coordinates
=
location
.
coordinates
{
queryParameters
[
"
LAT
"
]
=
String
(
format
:
"%.5f"
,
coordinates
.
latitude
)
queryParameters
[
"
LON
"
]
=
String
(
format
:
"%.5f"
,
coordinates
.
longitude
)
queryParameters
[
"
lat
"
]
=
String
(
format
:
"%.5f"
,
coordinates
.
latitude
)
queryParameters
[
"
lon
"
]
=
String
(
format
:
"%.5f"
,
coordinates
.
longitude
)
}
queryParameters
[
"
ZIP
"
]
=
location
.
zip
queryParameters
[
"
CITY
"
]
=
location
.
cityName
queryParameters
[
"
STATE
"
]
=
location
.
region
queryParameters
[
"
COUNTRY"
]
=
location
.
countryNam
e
queryParameters
[
"
zip
"
]
=
location
.
zip
queryParameters
[
"
city
"
]
=
location
.
cityName
queryParameters
[
"
state
"
]
=
location
.
region
queryParameters
[
"
country"
]
=
location
.
countryCod
e
guard
!
queryParameters
.
isEmpty
else
{
completion
(
nil
,
BlendHealthSourceError
.
insufficientLocationInfo
)
log
.
error
(
"Not enough information about location."
)
return
}
urlComponents
.
queryItems
=
queryParameters
.
map
{
URLQueryItem
(
name
:
$0
,
value
:
$1
)
}
guard
let
url
=
urlComponents
.
url
else
{
completion
(
nil
,
BlendHealthSourceError
.
badUrl
)
return
}
log
.
debug
(
"query params:
\(
queryParameters
)
"
)
var
request
=
URLRequest
(
url
:
url
)
var
headers
=
request
.
allHTTPHeaderFields
??
[
String
:
String
]()
headers
[
BlendHealthSource
.
blendAPIKeyHeaderName
]
=
BlendHealthSource
.
blendAPIKey
request
.
allHTTPHeaderFields
=
headers
let
urlSession
=
URLSession
.
shared
let
dataTask
=
urlSession
.
dataTask
(
with
:
url
)
{
[
weak
self
]
(
data
,
reponse
,
error
)
in
guard
let
self
=
self
else
{
return
}
let
dataTask
=
urlSession
.
dataTask
(
with
:
request
)
{
(
data
,
reponse
,
error
)
in
// TODO: check response HTTP code
guard
let
data
=
data
else
{
completion
(
nil
,
BlendHealthSourceError
.
networkError
(
error
))
return
...
...
1Weather/Network/Health/Model/BlendHealthModels.swift
View file @
1f4dd173
...
...
@@ -10,14 +10,12 @@ import UIKit
// MARK: - HealthCenter
struct
BlendHealthCenter
:
Codable
{
public
let
s2CellID
:
String
public
let
updatedOn
:
Date
public
let
airQuality
:
BlendAirQuality
?
public
let
fire
:
BlendFire
public
let
pollutants
,
pollen
:
[
BlendPoll
]?
enum
CodingKeys
:
String
,
CodingKey
{
case
s2CellID
=
"s2_cell_id"
case
updatedOn
=
"updated_on"
case
airQuality
=
"air_quality"
case
fire
,
pollutants
,
pollen
...
...
@@ -33,7 +31,7 @@ struct BlendHealthCenter: Codable {
return
dict
}
let
result
=
Health
(
lastUpdateTime
:
updatedOn
,
airQuality
:
airQuality
,
pollutants
:
pollutants
??
[:])
let
result
=
Health
(
lastUpdateTime
:
Date
()
,
airQuality
:
airQuality
,
pollutants
:
pollutants
??
[:])
return
result
}
}
...
...
1Weather/UI/View controllers/Today/Cells/TodayAirQualityCell/TodayAirQualityCell.swift
View file @
1f4dd173
...
...
@@ -40,10 +40,10 @@ class TodayAirQualityCell: UITableViewCell {
fatalError
(
"init(coder:) has not been implemented"
)
}
public
func
configure
(
health
:
Health
)
{
airQualityValueLabel
.
text
=
"
\(
Int
(
health
.
airQuality
?
.
index
??
0
)
)
"
public
func
configure
(
health
:
Health
?
)
{
airQualityValueLabel
.
text
=
"
\(
Int
(
health
?
.
airQuality
?
.
index
??
0
)
)
"
let
aqiText
=
"air.quality.is"
.
localized
()
let
aqiConditionText
=
health
.
airQuality
?
.
status
.
localized
??
""
let
aqiConditionText
=
health
?
.
airQuality
?
.
status
.
localized
??
""
let
attrString
=
NSMutableAttributedString
(
string
:
"
\(
aqiText
)\n\(
aqiConditionText
)
"
,
attributes
:
[
.
font
:
AppFont
.
SFPro
.
regular
(
size
:
24
),
.
foregroundColor
:
ThemeManager
.
currentTheme
.
secondaryTextColor
])
...
...
@@ -54,7 +54,7 @@ class TodayAirQualityCell: UITableViewCell {
//Fill pollutions
stackView
.
removeAll
()
health
.
pollutants
.
map
{
$1
}
.
forEach
{
health
?
.
pollutants
.
map
{
$1
}
.
forEach
{
let
pollutionView
=
PollutantView
()
pollutionView
.
configure
(
pollutant
:
$0
)
stackView
.
addArrangedSubview
(
pollutionView
)
...
...
1Weather/UI/View controllers/Today/Cells/TodayCellFactory.swift
View file @
1f4dd173
...
...
@@ -40,12 +40,12 @@ class TodayCellFactory: CellFactoryProtocol {
private
var
todaySection
=
TodaySection
(
rows
:
[
.
alert
,
.
forecast
,
.
ad
,
.
conditions
,
.
forecastPeriod
,
.
precipitation
,
.
airQuality
,
.
dayTime
,
.
sun
,
.
moon
])
private
let
health
=
Health
(
lastUpdateTime
:
Date
(),
airQuality
:
.
init
(
index
:
48
,
advice
:
"some"
),
pollutants
:
[
"pm25"
:
.
init
(
name
:
"PM 2.5"
,
value
:
48
),
"pm10"
:
.
init
(
name
:
"PM 10"
,
value
:
42
),
"no2"
:
.
init
(
name
:
"NO2"
,
value
:
74
),
"so2"
:
.
init
(
name
:
"SO2"
,
value
:
135
)])
//
private let health = Health(lastUpdateTime: Date(),
//
airQuality: .init(index: 48, advice: "some"),
//
pollutants: ["pm25" : .init(name: "PM 2.5", value: 48),
//
"pm10" : .init(name: "PM 10", value: 42),
//
"no2" : .init(name: "NO2", value: 74),
//
"so2" : .init(name: "SO2", value: 135)])
//Public
init
(
viewModel
:
TodayViewModel
)
{
...
...
@@ -112,7 +112,7 @@ class TodayCellFactory: CellFactoryProtocol {
return
cell
case
.
airQuality
:
let
cell
=
dequeueReusableCell
(
type
:
TodayAirQualityCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
cell
.
configure
(
health
:
self
.
health
)
cell
.
configure
(
health
:
loc
.
health
)
return
cell
case
.
dayTime
:
let
cell
=
dequeueReusableCell
(
type
:
TodayDayTimesCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
...
...
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