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
bb0e57d7
Commit
bb0e57d7
authored
Mar 23, 2021
by
Dmitriy Stepanets
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Finished ForecastViewController
parent
a0b2dc91
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
460 additions
and
56 deletions
+460
-56
1Weather.xcodeproj/project.pbxproj
+8
-0
1Weather.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
+1
-1
1Weather.xcworkspace/xcuserdata/dstepanets.xcuserdatad/UserInterfaceState.xcuserstate
+0
-0
1Weather/Extensions/Calendar+TimeZone.swift
+7
-0
1Weather/Model/HelperTypes.swift
+37
-0
1Weather/Resources/Assets.xcassets/wind_direction.imageset/Contents.json
+16
-0
1Weather/Resources/Assets.xcassets/wind_direction.imageset/wind_direction.pdf
+0
-0
1Weather/UI/Helpers/AppFont.swift
+18
-20
1Weather/UI/Helpers/ForecastTimePeriod/ForecastPeriodButton.swift
+7
-2
1Weather/UI/Helpers/ForecastTimePeriod/ForecastTimePeriodView.swift
+49
-12
1Weather/UI/Helpers/ForecastTimePeriod/ForecastWindButton.swift
+163
-0
1Weather/UI/Helpers/ForecastTimePeriod/GraphLine.swift
+8
-7
1Weather/UI/Helpers/ForecastTimePeriod/GraphLineSettings.swift
+1
-0
1Weather/UI/Helpers/ForecastTimePeriod/GraphView.swift
+27
-0
1Weather/UI/View controllers/Forecast/Cells/ForecastCellFactory.swift
+8
-1
1Weather/UI/View controllers/Forecast/Cells/ForecastDailyCell.swift
+1
-1
1Weather/UI/View controllers/Forecast/Cells/ForecastHourlyCell.swift
+1
-1
1Weather/UI/View controllers/Forecast/Cells/ForecastWindSpeedCell.swift
+100
-0
1Weather/UI/View controllers/Today/Cells/CityForecastTimePeriodCell.swift
+2
-1
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipButton.swift
+5
-9
Pods/Pods.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
+1
-1
No files found.
1Weather.xcodeproj/project.pbxproj
View file @
bb0e57d7
...
@@ -77,6 +77,8 @@
...
@@ -77,6 +77,8 @@
CDE18DCD25D1666700C80ED9
/* ForecastCoordinator.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDE18DCC25D1666700C80ED9
/* ForecastCoordinator.swift */
;
};
CDE18DCD25D1666700C80ED9
/* ForecastCoordinator.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDE18DCC25D1666700C80ED9
/* ForecastCoordinator.swift */
;
};
CDE18DD125D166F900C80ED9
/* ForecastViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDE18DD025D166F900C80ED9
/* ForecastViewController.swift */
;
};
CDE18DD125D166F900C80ED9
/* ForecastViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDE18DD025D166F900C80ED9
/* ForecastViewController.swift */
;
};
CDE18DD825D16CB200C80ED9
/* NavigationCityButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDE18DD725D16CB200C80ED9
/* NavigationCityButton.swift */
;
};
CDE18DD825D16CB200C80ED9
/* NavigationCityButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDE18DD725D16CB200C80ED9
/* NavigationCityButton.swift */
;
};
CDE2BF222609D4250085C930
/* ForecastWindSpeedCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDE2BF212609D4250085C930
/* ForecastWindSpeedCell.swift */
;
};
CDE2BF252609D9140085C930
/* ForecastWindButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDE2BF242609D9140085C930
/* ForecastWindButton.swift */
;
};
CDEE8AD725DA882200C289DE
/* ForecastPeriodButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDEE8AD625DA882200C289DE
/* ForecastPeriodButton.swift */
;
};
CDEE8AD725DA882200C289DE
/* ForecastPeriodButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CDEE8AD625DA882200C289DE
/* ForecastPeriodButton.swift */
;
};
CE578FD325F7E89400E8B85D
/* DayTimeWeather.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE578FD225F7E89400E8B85D
/* DayTimeWeather.swift */
;
};
CE578FD325F7E89400E8B85D
/* DayTimeWeather.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE578FD225F7E89400E8B85D
/* DayTimeWeather.swift */
;
};
CE9D181625ECB8370028D9D7
/* MulticastDelegate.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE9D181525ECB8370028D9D7
/* MulticastDelegate.swift */
;
};
CE9D181625ECB8370028D9D7
/* MulticastDelegate.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE9D181525ECB8370028D9D7
/* MulticastDelegate.swift */
;
};
...
@@ -178,6 +180,8 @@
...
@@ -178,6 +180,8 @@
CDE18DCC25D1666700C80ED9
/* ForecastCoordinator.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastCoordinator.swift
;
sourceTree
=
"<group>"
;
};
CDE18DCC25D1666700C80ED9
/* ForecastCoordinator.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastCoordinator.swift
;
sourceTree
=
"<group>"
;
};
CDE18DD025D166F900C80ED9
/* ForecastViewController.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastViewController.swift
;
sourceTree
=
"<group>"
;
};
CDE18DD025D166F900C80ED9
/* ForecastViewController.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastViewController.swift
;
sourceTree
=
"<group>"
;
};
CDE18DD725D16CB200C80ED9
/* NavigationCityButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
NavigationCityButton.swift
;
sourceTree
=
"<group>"
;
};
CDE18DD725D16CB200C80ED9
/* NavigationCityButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
NavigationCityButton.swift
;
sourceTree
=
"<group>"
;
};
CDE2BF212609D4250085C930
/* ForecastWindSpeedCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastWindSpeedCell.swift
;
sourceTree
=
"<group>"
;
};
CDE2BF242609D9140085C930
/* ForecastWindButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastWindButton.swift
;
sourceTree
=
"<group>"
;
};
CDEE8AD625DA882200C289DE
/* ForecastPeriodButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastPeriodButton.swift
;
sourceTree
=
"<group>"
;
};
CDEE8AD625DA882200C289DE
/* ForecastPeriodButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastPeriodButton.swift
;
sourceTree
=
"<group>"
;
};
CE578FD225F7E89400E8B85D
/* DayTimeWeather.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
DayTimeWeather.swift
;
sourceTree
=
"<group>"
;
};
CE578FD225F7E89400E8B85D
/* DayTimeWeather.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
DayTimeWeather.swift
;
sourceTree
=
"<group>"
;
};
CE9D181525ECB8370028D9D7
/* MulticastDelegate.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MulticastDelegate.swift
;
sourceTree
=
"<group>"
;
};
CE9D181525ECB8370028D9D7
/* MulticastDelegate.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MulticastDelegate.swift
;
sourceTree
=
"<group>"
;
};
...
@@ -237,6 +241,7 @@
...
@@ -237,6 +241,7 @@
CD3F6E6825FA59D4002DB99B
/* ForecastDetailPeriodButton.swift */
,
CD3F6E6825FA59D4002DB99B
/* ForecastDetailPeriodButton.swift */
,
CD3F6E6B25FA5A90002DB99B
/* PeriodButtonProtocol.swift */
,
CD3F6E6B25FA5A90002DB99B
/* PeriodButtonProtocol.swift */
,
CD593BC126088A5900C93428
/* TimePeriodOffsetHolder.swift */
,
CD593BC126088A5900C93428
/* TimePeriodOffsetHolder.swift */
,
CDE2BF242609D9140085C930
/* ForecastWindButton.swift */
,
);
);
path
=
ForecastTimePeriod
;
path
=
ForecastTimePeriod
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
@@ -435,6 +440,7 @@
...
@@ -435,6 +440,7 @@
CD593BCB2608A4F200C93428
/* ForecastDailyCell.swift */
,
CD593BCB2608A4F200C93428
/* ForecastDailyCell.swift */
,
CD593BCE2608A50900C93428
/* ForecastHourlyCell.swift */
,
CD593BCE2608A50900C93428
/* ForecastHourlyCell.swift */
,
CD593BD22608BC3F00C93428
/* ForecastDayCell.swift */
,
CD593BD22608BC3F00C93428
/* ForecastDayCell.swift */
,
CDE2BF212609D4250085C930
/* ForecastWindSpeedCell.swift */
,
);
);
path
=
Cells
;
path
=
Cells
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
@@ -721,6 +727,7 @@
...
@@ -721,6 +727,7 @@
CD82300325D69DE400A05501
/* CityConditionsCell.swift in Sources */
,
CD82300325D69DE400A05501
/* CityConditionsCell.swift in Sources */
,
CEC526FD25E795F700DA58A5
/* WdtWeatherSource.swift in Sources */
,
CEC526FD25E795F700DA58A5
/* WdtWeatherSource.swift in Sources */
,
CEAFF09225DFC71D00DF4EBF
/* HelperTypes.swift in Sources */
,
CEAFF09225DFC71D00DF4EBF
/* HelperTypes.swift in Sources */
,
CDE2BF222609D4250085C930
/* ForecastWindSpeedCell.swift in Sources */
,
CDA5543025EFA13F00A2E08C
/* Measurement+String.swift in Sources */
,
CDA5543025EFA13F00A2E08C
/* Measurement+String.swift in Sources */
,
CE9D181925ECB9A70028D9D7
/* Logger.swift in Sources */
,
CE9D181925ECB9A70028D9D7
/* Logger.swift in Sources */
,
CE578FD325F7E89400E8B85D
/* DayTimeWeather.swift in Sources */
,
CE578FD325F7E89400E8B85D
/* DayTimeWeather.swift in Sources */
,
...
@@ -783,6 +790,7 @@
...
@@ -783,6 +790,7 @@
CD15DB4225DA806C00024727
/* CityForecastTimePeriodCell.swift in Sources */
,
CD15DB4225DA806C00024727
/* CityForecastTimePeriodCell.swift in Sources */
,
CEC5276025E92DDA00DA58A5
/* WdtHourlySummary.swift in Sources */
,
CEC5276025E92DDA00DA58A5
/* WdtHourlySummary.swift in Sources */
,
CDE18DCA25D165F100C80ED9
/* UITabBarController+Append.swift in Sources */
,
CDE18DCA25D165F100C80ED9
/* UITabBarController+Append.swift in Sources */
,
CDE2BF252609D9140085C930
/* ForecastWindButton.swift in Sources */
,
CD251ED82603633800ED7A65
/* ForecastPrecipitationCell.swift in Sources */
,
CD251ED82603633800ED7A65
/* ForecastPrecipitationCell.swift in Sources */
,
CD86246125E662BC0097F3FB
/* SunUvLineView.swift in Sources */
,
CD86246125E662BC0097F3FB
/* SunUvLineView.swift in Sources */
,
CEC526FA25E7959A00DA58A5
/* WeatherSource.swift in Sources */
,
CEC526FA25E7959A00DA58A5
/* WeatherSource.swift in Sources */
,
...
...
1Weather.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
bb0e57d7
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
<
k
e
y
>
1Weather.xcscheme_
^#
shared
#^
_
<
/k
e
y
>
<
k
e
y
>
1Weather.xcscheme_
^#
shared
#^
_
<
/k
e
y
>
<
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
orderHint
<
/k
e
y
>
<
k
e
y
>
orderHint
<
/k
e
y
>
<
int
e
g
e
r
>
6
<
/int
e
g
e
r
>
<
int
e
g
e
r
>
5
<
/int
e
g
e
r
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
k
e
y
>
PG
(
Playground
)
1.xcscheme
<
/k
e
y
>
<
k
e
y
>
PG
(
Playground
)
1.xcscheme
<
/k
e
y
>
<
d
i
c
t
>
<
d
i
c
t
>
...
...
1Weather.xcworkspace/xcuserdata/dstepanets.xcuserdatad/UserInterfaceState.xcuserstate
View file @
bb0e57d7
No preview for this file type
1Weather/Extensions/Calendar+TimeZone.swift
View file @
bb0e57d7
...
@@ -13,4 +13,11 @@ extension Calendar {
...
@@ -13,4 +13,11 @@ extension Calendar {
cal
.
timeZone
=
timeZone
cal
.
timeZone
=
timeZone
return
cal
return
cal
}
}
static
func
isNow
(
fromDate
date
:
Date
,
timeZone
:
TimeZone
)
->
Bool
{
guard
let
nowDate
=
Date
.
nowDate
(
timeZone
:
timeZone
)
else
{
return
false
}
return
self
.
timeZoneCalendar
(
timeZone
:
timeZone
)
.
isDate
(
date
,
equalTo
:
nowDate
,
toGranularity
:
.
hour
)
}
}
}
1Weather/Model/HelperTypes.swift
View file @
bb0e57d7
...
@@ -115,6 +115,43 @@ public enum WindDirection: String, Codable, CaseIterable {
...
@@ -115,6 +115,43 @@ public enum WindDirection: String, Codable, CaseIterable {
case
westNorthWest
=
"WNW"
case
westNorthWest
=
"WNW"
case
northWest
=
"NW"
case
northWest
=
"NW"
case
northNorthWest
=
"NNW"
case
northNorthWest
=
"NNW"
var
degrees
:
CGFloat
{
switch
self
{
case
.
north
:
return
0
case
.
northNorthEast
:
return
22.5
case
.
northEast
:
return
45
case
.
eastNorthEast
:
return
67.5
case
.
east
:
return
90
case
.
eastSouthEast
:
return
112.5
case
.
southEast
:
return
135
case
.
southSouthEast
:
return
157.5
case
.
south
:
return
180
case
.
southSouthWest
:
return
202.5
case
.
southWest
:
return
225
case
.
westSouthWest
:
return
247.5
case
.
west
:
return
270
case
.
westNorthWest
:
return
292.5
case
.
northWest
:
return
315
case
.
northNorthWest
:
return
337.5
}
}
}
}
...
...
1Weather/Resources/Assets.xcassets/wind_direction.imageset/Contents.json
0 → 100644
View file @
bb0e57d7
{
"images"
:
[
{
"filename"
:
"wind_direction.pdf"
,
"idiom"
:
"universal"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
},
"properties"
:
{
"preserves-vector-representation"
:
true
,
"template-rendering-intent"
:
"template"
}
}
1Weather/Resources/Assets.xcassets/wind_direction.imageset/wind_direction.pdf
0 → 100644
View file @
bb0e57d7
File added
1Weather/UI/Helpers/AppFont.swift
View file @
bb0e57d7
...
@@ -8,37 +8,35 @@
...
@@ -8,37 +8,35 @@
import
UIKit
import
UIKit
public
struct
AppFont
{
public
struct
AppFont
{
private
static
func
fontDescriptor
(
size
:
CGFloat
,
weight
:
UIFont
.
Weight
)
->
UIFontDescriptor
{
let
traitsDict
=
[
UIFontDescriptor
.
TraitKey
.
weight
:
weight
]
let
descriptor
=
UIFontDescriptor
(
fontAttributes
:
[
UIFontDescriptor
.
AttributeName
.
size
:
size
,
UIFontDescriptor
.
AttributeName
.
family
:
"SF Pro"
,
UIFontDescriptor
.
AttributeName
.
traits
:
traitsDict
])
return
descriptor
}
public
struct
SFPro
{
public
struct
SFPro
{
static
func
regular
(
size
:
CGFloat
)
->
UIFont
{
static
func
regular
(
size
:
CGFloat
)
->
UIFont
{
guard
let
font
=
UIFont
(
name
:
"SFPro-Regualr"
,
size
:
size
)
else
{
let
descriptor
=
AppFont
.
fontDescriptor
(
size
:
size
,
weight
:
.
regular
)
return
UIFont
.
systemFont
(
ofSize
:
size
)
return
UIFont
(
descriptor
:
descriptor
,
size
:
size
)
}
return
font
}
}
static
func
bold
(
size
:
CGFloat
)
->
UIFont
{
static
func
bold
(
size
:
CGFloat
)
->
UIFont
{
guard
let
font
=
UIFont
(
name
:
"SFPro-Bold"
,
size
:
size
)
else
{
let
descriptor
=
AppFont
.
fontDescriptor
(
size
:
size
,
weight
:
.
bold
)
return
UIFont
.
systemFont
(
ofSize
:
size
,
weight
:
.
bold
)
return
UIFont
(
descriptor
:
descriptor
,
size
:
size
)
}
return
font
}
}
static
func
medium
(
size
:
CGFloat
)
->
UIFont
{
static
func
medium
(
size
:
CGFloat
)
->
UIFont
{
guard
let
font
=
UIFont
(
name
:
"SFPro-Medium"
,
size
:
size
)
else
{
let
descriptor
=
AppFont
.
fontDescriptor
(
size
:
size
,
weight
:
.
medium
)
return
UIFont
.
systemFont
(
ofSize
:
size
,
weight
:
.
bold
)
return
UIFont
(
descriptor
:
descriptor
,
size
:
size
)
}
return
font
}
}
static
func
semibold
(
size
:
CGFloat
)
->
UIFont
{
static
func
semibold
(
size
:
CGFloat
)
->
UIFont
{
guard
let
font
=
UIFont
(
name
:
"SFPro-Semibold"
,
size
:
size
)
else
{
let
descriptor
=
AppFont
.
fontDescriptor
(
size
:
size
,
weight
:
.
semibold
)
return
UIFont
.
systemFont
(
ofSize
:
size
,
weight
:
.
semibold
)
return
UIFont
(
descriptor
:
descriptor
,
size
:
size
)
}
return
font
}
}
}
}
}
}
1Weather/UI/Helpers/ForecastTimePeriod/ForecastPeriodButton.swift
View file @
bb0e57d7
...
@@ -102,8 +102,13 @@ class ForecastPeriodButton: UIControl, PeriodButtonProtocol {
...
@@ -102,8 +102,13 @@ class ForecastPeriodButton: UIControl, PeriodButtonProtocol {
self
.
tempLabel
.
text
=
hourlyWeather
.
temp
?
.
shortString
self
.
tempLabel
.
text
=
hourlyWeather
.
temp
?
.
shortString
self
.
minTempLabel
.
text
=
nil
self
.
minTempLabel
.
text
=
nil
self
.
indicatorImageView
.
image
=
nil
self
.
indicatorImageView
.
image
=
nil
ForecastPeriodButton
.
hourlyFormatter
.
timeZone
=
hourlyWeather
.
timeZone
if
Calendar
.
isNow
(
fromDate
:
hourlyWeather
.
date
,
timeZone
:
hourlyWeather
.
timeZone
)
{
self
.
timeLabel
.
text
=
ForecastPeriodButton
.
hourlyFormatter
.
string
(
from
:
hourlyWeather
.
date
)
self
.
timeLabel
.
text
=
"day.now"
.
localized
()
.
uppercased
()
}
else
{
ForecastPeriodButton
.
hourlyFormatter
.
timeZone
=
hourlyWeather
.
timeZone
self
.
timeLabel
.
text
=
ForecastPeriodButton
.
hourlyFormatter
.
string
(
from
:
hourlyWeather
.
date
)
}
}
}
}
}
...
...
1Weather/UI/Helpers/ForecastTimePeriod/ForecastTimePeriodView.swift
View file @
bb0e57d7
...
@@ -16,6 +16,12 @@ private struct HourlyGraphPoints {
...
@@ -16,6 +16,12 @@ private struct HourlyGraphPoints {
let
points
:
[
CGPoint
]
let
points
:
[
CGPoint
]
}
}
public
enum
ForecastType
{
case
daily
case
hourly
case
wind
}
protocol
ForecastTimePeriodViewDelegate
:
class
{
protocol
ForecastTimePeriodViewDelegate
:
class
{
func
forecastTimePeriodView
(
view
:
ForecastTimePeriodView
,
didSelectButtonAt
index
:
Int
)
func
forecastTimePeriodView
(
view
:
ForecastTimePeriodView
,
didSelectButtonAt
index
:
Int
)
func
offsetDidChange
(
offset
:
CGFloat
)
func
offsetDidChange
(
offset
:
CGFloat
)
...
@@ -27,7 +33,7 @@ class ForecastTimePeriodView: UIView {
...
@@ -27,7 +33,7 @@ class ForecastTimePeriodView: UIView {
private
let
stackView
=
UIStackView
()
private
let
stackView
=
UIStackView
()
private
let
graphView
=
GraphView
()
private
let
graphView
=
GraphView
()
private
var
graphRect
:
CGRect
=
.
zero
private
var
graphRect
:
CGRect
=
.
zero
private
var
current
TimePeriod
=
TimePeriod
.
daily
private
var
current
ForecastType
=
ForecastType
.
daily
private
var
dailyGraphPoints
=
DailyGraphPoints
(
maxTempPoints
:
[
CGPoint
](),
minTempPoints
:
[
CGPoint
]())
private
var
dailyGraphPoints
=
DailyGraphPoints
(
maxTempPoints
:
[
CGPoint
](),
minTempPoints
:
[
CGPoint
]())
private
var
hourlyGraphPoints
=
HourlyGraphPoints
(
points
:
[
CGPoint
]())
private
var
hourlyGraphPoints
=
HourlyGraphPoints
(
points
:
[
CGPoint
]())
private
var
daily
=
[
DailyWeather
]()
private
var
daily
=
[
DailyWeather
]()
...
@@ -64,8 +70,8 @@ class ForecastTimePeriodView: UIView {
...
@@ -64,8 +70,8 @@ class ForecastTimePeriodView: UIView {
}
}
}
}
public
func
set
(
timePeriod
:
TimePeriod
,
buttonType
:
PeriodButtonProtocol
.
Type
)
{
public
func
set
(
forecastType
:
ForecastType
,
buttonType
:
PeriodButtonProtocol
.
Type
)
{
self
.
current
TimePeriod
=
timePeriod
self
.
current
ForecastType
=
forecastType
rebuildButtons
(
buttonType
:
buttonType
)
rebuildButtons
(
buttonType
:
buttonType
)
}
}
...
@@ -103,19 +109,19 @@ class ForecastTimePeriodView: UIView {
...
@@ -103,19 +109,19 @@ class ForecastTimePeriodView: UIView {
stackView
.
removeAll
()
stackView
.
removeAll
()
let
numberOfButtons
:
Int
let
numberOfButtons
:
Int
switch
current
TimePeriod
{
switch
current
ForecastType
{
case
.
daily
:
case
.
daily
:
numberOfButtons
=
daily
.
count
numberOfButtons
=
daily
.
count
case
.
hourly
:
case
.
hourly
,
.
wind
:
numberOfButtons
=
hourly
.
count
numberOfButtons
=
hourly
.
count
}
}
for
index
in
0
..<
numberOfButtons
{
for
index
in
0
..<
numberOfButtons
{
let
forecastButton
=
buttonType
.
init
()
let
forecastButton
=
buttonType
.
init
()
switch
current
TimePeriod
{
switch
current
ForecastType
{
case
.
daily
:
case
.
daily
:
forecastButton
.
configure
(
dailyWeather
:
daily
[
index
])
forecastButton
.
configure
(
dailyWeather
:
daily
[
index
])
case
.
hourly
:
case
.
hourly
,
.
wind
:
forecastButton
.
configure
(
hourlyWeather
:
hourly
[
index
])
forecastButton
.
configure
(
hourlyWeather
:
hourly
[
index
])
}
}
forecastButton
.
index
=
index
forecastButton
.
index
=
index
...
@@ -145,11 +151,13 @@ class ForecastTimePeriodView: UIView {
...
@@ -145,11 +151,13 @@ class ForecastTimePeriodView: UIView {
}
}
private
func
updateGraphPoints
()
{
private
func
updateGraphPoints
()
{
switch
current
TimePeriod
{
switch
current
ForecastType
{
case
.
daily
:
case
.
daily
:
updateDailyGraphPoints
()
updateDailyGraphPoints
()
case
.
hourly
:
case
.
hourly
:
updateHourlyGraphPoints
()
updateHourlyGraphPoints
()
case
.
wind
:
updateWindPoints
()
}
}
}
}
...
@@ -196,7 +204,6 @@ class ForecastTimePeriodView: UIView {
...
@@ -196,7 +204,6 @@ class ForecastTimePeriodView: UIView {
let
temps
=
(
hourly
.
map
{
CGFloat
(
$0
.
temp
?
.
localeValue
??
0
)
})
let
temps
=
(
hourly
.
map
{
CGFloat
(
$0
.
temp
?
.
localeValue
??
0
)
})
let
maxTemp
=
temps
.
max
()
??
0
let
maxTemp
=
temps
.
max
()
??
0
var
points
=
[
CGPoint
]()
var
points
=
[
CGPoint
]()
for
index
in
0
..<
hoursCount
{
for
index
in
0
..<
hoursCount
{
guard
let
stackButton
=
stackView
.
arrangedSubviews
[
index
]
as?
PeriodButtonProtocol
else
{
continue
}
guard
let
stackButton
=
stackView
.
arrangedSubviews
[
index
]
as?
PeriodButtonProtocol
else
{
continue
}
...
@@ -218,6 +225,32 @@ class ForecastTimePeriodView: UIView {
...
@@ -218,6 +225,32 @@ class ForecastTimePeriodView: UIView {
hourlyGraphPoints
=
HourlyGraphPoints
(
points
:
points
)
hourlyGraphPoints
=
HourlyGraphPoints
(
points
:
points
)
}
}
private
func
updateWindPoints
()
{
let
hoursCount
=
hourly
.
count
let
speeds
=
(
hourly
.
map
{
CGFloat
(
$0
.
windSpeed
?
.
value
??
0
)
})
let
maxWindSpeed
=
speeds
.
max
()
??
0
var
points
=
[
CGPoint
]()
for
index
in
0
..<
hoursCount
{
guard
let
stackButton
=
stackView
.
arrangedSubviews
[
index
]
as?
PeriodButtonProtocol
else
{
continue
}
let
buttonRightSide
=
stackButton
.
frame
.
origin
.
x
+
stackButton
.
bounds
.
width
let
buttonCenterX
=
(
buttonRightSide
+
stackButton
.
frame
.
origin
.
x
)
/
2
let
levelsCount
=
CGFloat
(
Set
(
speeds
)
.
count
)
let
levelHeight
=
(
graphView
.
frame
.
height
/
CGFloat
(
levelsCount
))
.
rounded
(
.
down
)
let
graphFrame
=
CGRect
(
x
:
0
,
y
:
0
,
width
:
graphView
.
frame
.
width
,
height
:
graphView
.
frame
.
height
-
5
)
var
pointLevel
=
graphFrame
.
origin
.
y
+
((
maxWindSpeed
-
speeds
[
index
])
*
levelHeight
)
pointLevel
=
max
(
pointLevel
,
graphFrame
.
origin
.
y
)
pointLevel
=
min
(
graphFrame
.
height
,
pointLevel
)
points
.
append
(
.
init
(
x
:
buttonCenterX
,
y
:
pointLevel
))
}
hourlyGraphPoints
=
HourlyGraphPoints
(
points
:
points
)
}
private
func
drawGraph
()
{
private
func
drawGraph
()
{
guard
guard
let
periodButtons
=
stackView
.
arrangedSubviews
as?
[
PeriodButtonProtocol
],
let
periodButtons
=
stackView
.
arrangedSubviews
as?
[
PeriodButtonProtocol
],
...
@@ -226,7 +259,7 @@ class ForecastTimePeriodView: UIView {
...
@@ -226,7 +259,7 @@ class ForecastTimePeriodView: UIView {
return
return
}
}
switch
current
TimePeriod
{
switch
current
ForecastType
{
case
.
daily
:
case
.
daily
:
self
.
graphView
.
drawMainGraph
(
with
:
dailyGraphPoints
.
maxTempPoints
)
self
.
graphView
.
drawMainGraph
(
with
:
dailyGraphPoints
.
maxTempPoints
)
self
.
graphView
.
drawAdditionalGraph
(
with
:
dailyGraphPoints
.
minTempPoints
)
self
.
graphView
.
drawAdditionalGraph
(
with
:
dailyGraphPoints
.
minTempPoints
)
...
@@ -235,6 +268,10 @@ class ForecastTimePeriodView: UIView {
...
@@ -235,6 +268,10 @@ class ForecastTimePeriodView: UIView {
self
.
graphView
.
drawMainGraph
(
with
:
hourlyGraphPoints
.
points
)
self
.
graphView
.
drawMainGraph
(
with
:
hourlyGraphPoints
.
points
)
self
.
graphView
.
drawAdditionalGraph
(
with
:
[
CGPoint
]())
self
.
graphView
.
drawAdditionalGraph
(
with
:
[
CGPoint
]())
self
.
tintGraphAt
(
button
:
selectedButton
)
self
.
tintGraphAt
(
button
:
selectedButton
)
case
.
wind
:
self
.
graphView
.
drawWindGraph
(
with
:
hourlyGraphPoints
.
points
)
self
.
graphView
.
drawAdditionalGraph
(
with
:
[
CGPoint
]())
self
.
tintGraphAt
(
button
:
selectedButton
)
}
}
print
(
"[ForecastTimePeriod] Draw graph"
)
print
(
"[ForecastTimePeriod] Draw graph"
)
...
@@ -243,13 +280,13 @@ class ForecastTimePeriodView: UIView {
...
@@ -243,13 +280,13 @@ class ForecastTimePeriodView: UIView {
private
func
tintGraphAt
(
button
:
PeriodButtonProtocol
)
{
private
func
tintGraphAt
(
button
:
PeriodButtonProtocol
)
{
guard
button
.
tinted
else
{
return
}
guard
button
.
tinted
else
{
return
}
switch
current
TimePeriod
{
switch
current
ForecastType
{
case
.
daily
:
case
.
daily
:
self
.
graphView
.
tintGraphFrom
(
startPointX
:
button
.
frame
.
origin
.
x
,
self
.
graphView
.
tintGraphFrom
(
startPointX
:
button
.
frame
.
origin
.
x
,
endPointX
:
button
.
frame
.
origin
.
x
+
button
.
bounds
.
width
)
endPointX
:
button
.
frame
.
origin
.
x
+
button
.
bounds
.
width
)
self
.
graphView
.
tintMainDotAt
(
point
:
dailyGraphPoints
.
maxTempPoints
[
button
.
index
])
self
.
graphView
.
tintMainDotAt
(
point
:
dailyGraphPoints
.
maxTempPoints
[
button
.
index
])
self
.
graphView
.
tintAdditionalDotAt
(
point
:
dailyGraphPoints
.
minTempPoints
[
button
.
index
])
self
.
graphView
.
tintAdditionalDotAt
(
point
:
dailyGraphPoints
.
minTempPoints
[
button
.
index
])
case
.
hourly
:
case
.
hourly
,
.
wind
:
self
.
graphView
.
tintGraphFrom
(
startPointX
:
button
.
frame
.
origin
.
x
,
self
.
graphView
.
tintGraphFrom
(
startPointX
:
button
.
frame
.
origin
.
x
,
endPointX
:
button
.
frame
.
origin
.
x
+
button
.
bounds
.
width
)
endPointX
:
button
.
frame
.
origin
.
x
+
button
.
bounds
.
width
)
self
.
graphView
.
tintMainDotAt
(
point
:
hourlyGraphPoints
.
points
[
button
.
index
])
self
.
graphView
.
tintMainDotAt
(
point
:
hourlyGraphPoints
.
points
[
button
.
index
])
...
...
1Weather/UI/Helpers/ForecastTimePeriod/ForecastWindButton.swift
0 → 100644
View file @
bb0e57d7
//
// ForecastWindButton.swift
// 1Weather
//
// Created by Dmitry Stepanets on 23.03.2021.
//
import
UIKit
class
ForecastWindButton
:
UIControl
,
PeriodButtonProtocol
{
//Private
private
static
var
hourlyFormatter
:
DateFormatter
=
{
let
fmt
=
DateFormatter
()
fmt
.
dateFormat
=
"h a"
return
fmt
}()
private
let
kGraphInset
:
CGFloat
=
10
private
let
windInfoLabel
=
UILabel
()
private
let
directionImageView
=
UIImageView
()
private
let
indicatorImageView
=
UIImageView
()
private
let
timeLabel
=
UILabel
()
//Public
var
index
:
Int
=
-
1
var
tinted
:
Bool
{
return
true
}
var
graphRect
:
CGRect
{
let
topInset
=
self
.
directionImageView
.
frame
.
origin
.
y
+
self
.
directionImageView
.
frame
.
size
.
height
+
kGraphInset
return
.
init
(
x
:
0
,
y
:
topInset
,
width
:
self
.
bounds
.
width
,
height
:
self
.
indicatorImageView
.
frame
.
origin
.
y
-
topInset
-
kGraphInset
)
}
required
init
()
{
super
.
init
(
frame
:
.
zero
)
prepareButton
()
prepareInfoLabel
()
prepareDirectionImageView
()
prepareTimeLabel
()
prepareWindIndicator
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
override
var
isSelected
:
Bool
{
didSet
{
if
isSelected
{
self
.
backgroundColor
=
UIColor
.
white
self
.
windInfoLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
16
)
self
.
timeLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
12
)
self
.
layer
.
shadowColor
=
UIColor
(
hex
:
0xe5e6f4
)
.
cgColor
self
.
layer
.
shadowOffset
=
.
init
(
width
:
5
,
height
:
5
)
self
.
layer
.
shadowRadius
=
18
self
.
layer
.
shadowOpacity
=
0.64
}
else
{
self
.
backgroundColor
=
UIColor
.
white
.
withAlphaComponent
(
0.5
)
self
.
windInfoLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
16
)
self
.
timeLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
12
)
self
.
layer
.
shadowColor
=
UIColor
.
clear
.
cgColor
self
.
layer
.
shadowOffset
=
.
zero
self
.
layer
.
shadowRadius
=
0
self
.
layer
.
shadowOpacity
=
0
}
}
}
func
configure
(
dailyWeather
:
DailyWeather
)
{
assertionFailure
(
"Not implemented"
)
}
func
configure
(
hourlyWeather
:
HourlyWeather
)
{
let
direction
=
hourlyWeather
.
windDirection
?
.
rawValue
??
"--"
let
speed
=
hourlyWeather
.
windSpeed
?
.
string
??
"--"
windInfoLabel
.
text
=
"
\(
direction
.
uppercased
()
)\n\(
speed
.
uppercased
()
)
"
let
degrees
=
hourlyWeather
.
windDirection
?
.
degrees
??
0
directionImageView
.
transform
=
CGAffineTransform
(
rotationAngle
:
degrees
*
.
pi
/
180
)
if
Calendar
.
isNow
(
fromDate
:
hourlyWeather
.
date
,
timeZone
:
hourlyWeather
.
timeZone
)
{
timeLabel
.
text
=
"day.now"
.
localized
()
.
uppercased
()
}
else
{
ForecastWindButton
.
hourlyFormatter
.
timeZone
=
hourlyWeather
.
timeZone
timeLabel
.
text
=
ForecastWindButton
.
hourlyFormatter
.
string
(
from
:
hourlyWeather
.
date
)
}
}
}
//MARK:- Prepare
private
extension
ForecastWindButton
{
func
prepareButton
()
{
clipsToBounds
=
false
backgroundColor
=
UIColor
.
white
layer
.
cornerRadius
=
12
layer
.
borderColor
=
UIColor
(
hex
:
0xeceef6
)
.
cgColor
layer
.
borderWidth
=
1
/
UIScreen
.
main
.
scale
self
.
snp
.
makeConstraints
{
(
make
)
in
make
.
width
.
equalTo
(
70
)
}
}
func
prepareInfoLabel
()
{
windInfoLabel
.
isUserInteractionEnabled
=
false
windInfoLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
16
)
windInfoLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
windInfoLabel
.
textAlignment
=
.
center
windInfoLabel
.
numberOfLines
=
2
windInfoLabel
.
lineBreakMode
=
.
byWordWrapping
addSubview
(
windInfoLabel
)
windInfoLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalToSuperview
()
.
inset
(
16
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
2
)
}
}
func
prepareDirectionImageView
()
{
directionImageView
.
contentMode
=
.
scaleAspectFit
directionImageView
.
image
=
UIImage
(
named
:
"wind_direction"
)
directionImageView
.
tintColor
=
UIColor
(
hex
:
0x8fc2ff
)
addSubview
(
directionImageView
)
directionImageView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalTo
(
windInfoLabel
.
snp
.
bottom
)
.
offset
(
36
)
make
.
width
.
height
.
equalTo
(
18
)
make
.
centerX
.
equalToSuperview
()
}
}
func
prepareWindIndicator
()
{
indicatorImageView
.
isUserInteractionEnabled
=
false
indicatorImageView
.
isHidden
=
true
indicatorImageView
.
contentMode
=
.
scaleAspectFit
indicatorImageView
.
image
=
UIImage
(
named
:
"blowingDust"
)
addSubview
(
indicatorImageView
)
indicatorImageView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
width
.
height
.
equalTo
(
12
)
make
.
centerX
.
equalToSuperview
()
make
.
bottom
.
equalTo
(
timeLabel
.
snp
.
top
)
.
offset
(
-
15
)
}
}
func
prepareTimeLabel
()
{
timeLabel
.
isUserInteractionEnabled
=
false
timeLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
12
)
timeLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
timeLabel
.
text
=
"9 AM"
addSubview
(
timeLabel
)
timeLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
centerX
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
.
inset
(
20
)
}
}
}
1Weather/UI/Helpers/ForecastTimePeriod/GraphLine.swift
View file @
bb0e57d7
...
@@ -15,6 +15,7 @@ struct LineDot {
...
@@ -15,6 +15,7 @@ struct LineDot {
struct
GraphLine
{
struct
GraphLine
{
//Private
//Private
private
let
kInset
:
CGFloat
=
10
private
let
kIntersectAccuracy
:
CGFloat
=
0
private
let
kIntersectAccuracy
:
CGFloat
=
0
private
var
points
=
[
CGPoint
]()
private
var
points
=
[
CGPoint
]()
private
let
settings
:
GraphLineSettings
private
let
settings
:
GraphLineSettings
...
@@ -107,7 +108,7 @@ struct GraphLine {
...
@@ -107,7 +108,7 @@ struct GraphLine {
p1
:
.
init
(
x
:
startPointX
+
kIntersectAccuracy
,
y
:
self
.
onGetGraphRect
()
.
height
))
p1
:
.
init
(
x
:
startPointX
+
kIntersectAccuracy
,
y
:
self
.
onGetGraphRect
()
.
height
))
let
rightLine
=
LineSegment
(
p0
:
.
init
(
x
:
endPointX
-
kIntersectAccuracy
,
y
:
0
),
let
rightLine
=
LineSegment
(
p0
:
.
init
(
x
:
endPointX
-
kIntersectAccuracy
,
y
:
0
),
p1
:
.
init
(
x
:
endPointX
-
kIntersectAccuracy
,
y
:
self
.
onGetGraphRect
()
.
height
))
p1
:
.
init
(
x
:
endPointX
-
kIntersectAccuracy
,
y
:
self
.
onGetGraphRect
()
.
height
))
//Get all sections for the given tint and cut them
//Get all sections for the given tint and cut them
let
tintPath
=
UIBezierPath
()
let
tintPath
=
UIBezierPath
()
for
section
in
sections
{
for
section
in
sections
{
...
@@ -115,10 +116,10 @@ struct GraphLine {
...
@@ -115,10 +116,10 @@ struct GraphLine {
let
maxLeftPointX
=
max
(
section
.
startingPoint
.
x
,
leftLine
.
startingPoint
.
x
)
let
maxLeftPointX
=
max
(
section
.
startingPoint
.
x
,
leftLine
.
startingPoint
.
x
)
let
minRightPointX
=
min
(
section
.
endingPoint
.
x
,
rightLine
.
endingPoint
.
x
)
let
minRightPointX
=
min
(
section
.
endingPoint
.
x
,
rightLine
.
endingPoint
.
x
)
let
leftBoundary
=
LineSegment
(
p0
:
.
init
(
x
:
maxLeftPointX
,
y
:
0
),
let
leftBoundary
=
LineSegment
(
p0
:
.
init
(
x
:
maxLeftPointX
,
y
:
-
kInset
),
p1
:
.
init
(
x
:
maxLeftPointX
,
y
:
self
.
onGetGraphRect
()
.
height
))
p1
:
.
init
(
x
:
maxLeftPointX
,
y
:
self
.
onGetGraphRect
()
.
height
+
kInset
*
2
))
let
rightBoundary
=
LineSegment
(
p0
:
.
init
(
x
:
minRightPointX
,
y
:
0
),
let
rightBoundary
=
LineSegment
(
p0
:
.
init
(
x
:
minRightPointX
,
y
:
-
kInset
),
p1
:
.
init
(
x
:
minRightPointX
,
y
:
self
.
onGetGraphRect
()
.
height
))
p1
:
.
init
(
x
:
minRightPointX
,
y
:
self
.
onGetGraphRect
()
.
height
+
kInset
*
2
))
if
let
subcurve
=
getSubcurvePath
(
baseCurve
:
section
,
if
let
subcurve
=
getSubcurvePath
(
baseCurve
:
section
,
leftBoundary
:
leftBoundary
,
leftBoundary
:
leftBoundary
,
rightBoundary
:
rightBoundary
)
rightBoundary
:
rightBoundary
)
...
@@ -136,7 +137,7 @@ struct GraphLine {
...
@@ -136,7 +137,7 @@ struct GraphLine {
func
tintDotAt
(
point
:
CGPoint
)
{
func
tintDotAt
(
point
:
CGPoint
)
{
lineDots
.
forEach
{
lineDots
.
forEach
{
$0
.
shape
.
strokeColor
=
settings
.
c
olor
.
cgColor
$0
.
shape
.
strokeColor
=
settings
.
dotC
olor
.
cgColor
}
}
guard
let
dotToTint
=
(
lineDots
.
first
{
$0
.
center
==
point
})
else
{
return
}
guard
let
dotToTint
=
(
lineDots
.
first
{
$0
.
center
==
point
})
else
{
return
}
...
@@ -167,7 +168,7 @@ struct GraphLine {
...
@@ -167,7 +168,7 @@ struct GraphLine {
endAngle
:
.
pi
*
2
,
endAngle
:
.
pi
*
2
,
clockwise
:
true
)
.
cgPath
clockwise
:
true
)
.
cgPath
dotShape
.
fillColor
=
UIColor
.
white
.
cgColor
dotShape
.
fillColor
=
UIColor
.
white
.
cgColor
dotShape
.
strokeColor
=
settings
.
c
olor
.
cgColor
dotShape
.
strokeColor
=
settings
.
dotC
olor
.
cgColor
dotShape
.
lineWidth
=
settings
.
dotLineWidth
dotShape
.
lineWidth
=
settings
.
dotLineWidth
lineDots
.
append
(
.
init
(
center
:
$0
,
shape
:
dotShape
))
lineDots
.
append
(
.
init
(
center
:
$0
,
shape
:
dotShape
))
}
}
...
...
1Weather/UI/Helpers/ForecastTimePeriod/GraphLineSettings.swift
View file @
bb0e57d7
...
@@ -17,5 +17,6 @@ struct GraphLineSettings {
...
@@ -17,5 +17,6 @@ struct GraphLineSettings {
//General
//General
let
color
:
UIColor
let
color
:
UIColor
let
dotColor
:
UIColor
let
tintColor
:
UIColor
let
tintColor
:
UIColor
}
}
1Weather/UI/Helpers/ForecastTimePeriod/GraphView.swift
View file @
bb0e57d7
...
@@ -14,12 +14,20 @@ class GraphView: UIView {
...
@@ -14,12 +14,20 @@ class GraphView: UIView {
dotRadius
:
2.5
,
dotRadius
:
2.5
,
dotLineWidth
:
2
,
dotLineWidth
:
2
,
color
:
ThemeManager
.
currentTheme
.
graphColor
,
color
:
ThemeManager
.
currentTheme
.
graphColor
,
dotColor
:
ThemeManager
.
currentTheme
.
graphColor
,
tintColor
:
ThemeManager
.
currentTheme
.
graphTintColor
)
tintColor
:
ThemeManager
.
currentTheme
.
graphTintColor
)
private
let
additionalLineSettings
=
GraphLineSettings
(
lineWidth
:
2
,
private
let
additionalLineSettings
=
GraphLineSettings
(
lineWidth
:
2
,
dotRadius
:
2
,
dotRadius
:
2
,
dotLineWidth
:
1
,
dotLineWidth
:
1
,
color
:
UIColor
(
hex
:
0xa4a4a4
)
.
withAlphaComponent
(
0.7
),
color
:
UIColor
(
hex
:
0xa4a4a4
)
.
withAlphaComponent
(
0.7
),
dotColor
:
UIColor
(
hex
:
0xa4a4a4
)
.
withAlphaComponent
(
0.7
),
tintColor
:
UIColor
(
hex
:
0x434343
)
.
withAlphaComponent
(
0.7
))
tintColor
:
UIColor
(
hex
:
0x434343
)
.
withAlphaComponent
(
0.7
))
private
let
windLineSettings
=
GraphLineSettings
(
lineWidth
:
3
,
dotRadius
:
2.5
,
dotLineWidth
:
2
,
color
:
UIColor
(
hex
:
0x8fc1ff
),
dotColor
:
UIColor
(
hex
:
0x2292fa
),
tintColor
:
UIColor
(
hex
:
0x2292fa
))
private
lazy
var
mainLine
:
GraphLine
=
{
private
lazy
var
mainLine
:
GraphLine
=
{
let
line
=
GraphLine
(
settings
:
mainLineSettings
,
onGetGraphRect
:
{
let
line
=
GraphLine
(
settings
:
mainLineSettings
,
onGetGraphRect
:
{
...
@@ -35,6 +43,13 @@ class GraphView: UIView {
...
@@ -35,6 +43,13 @@ class GraphView: UIView {
return
line
return
line
}()
}()
private
lazy
var
windLine
:
GraphLine
=
{
let
line
=
GraphLine
(
settings
:
windLineSettings
,
onGetGraphRect
:
{
return
self
.
frame
})
return
line
}()
//MARK:- View life cycle
//MARK:- View life cycle
init
()
{
init
()
{
...
@@ -47,6 +62,9 @@ class GraphView: UIView {
...
@@ -47,6 +62,9 @@ class GraphView: UIView {
layer
.
insertSublayer
(
additionalLine
.
lineShape
,
at
:
0
)
layer
.
insertSublayer
(
additionalLine
.
lineShape
,
at
:
0
)
layer
.
insertSublayer
(
additionalLine
.
tintLineShape
,
at
:
0
)
layer
.
insertSublayer
(
additionalLine
.
tintLineShape
,
at
:
0
)
layer
.
insertSublayer
(
windLine
.
lineShape
,
at
:
0
)
layer
.
insertSublayer
(
windLine
.
tintLineShape
,
at
:
1
)
}
}
required
init
?(
coder
:
NSCoder
)
{
required
init
?(
coder
:
NSCoder
)
{
...
@@ -68,13 +86,22 @@ class GraphView: UIView {
...
@@ -68,13 +86,22 @@ class GraphView: UIView {
}
}
}
}
public
func
drawWindGraph
(
with
points
:[
CGPoint
])
{
windLine
.
updateWith
(
points
:
points
)
windLine
.
lineDots
.
forEach
{
layer
.
addSublayer
(
$0
.
shape
)
}
}
public
func
tintGraphFrom
(
startPointX
:
CGFloat
,
endPointX
:
CGFloat
)
{
public
func
tintGraphFrom
(
startPointX
:
CGFloat
,
endPointX
:
CGFloat
)
{
mainLine
.
tintLineFrom
(
startPointX
:
startPointX
,
to
:
endPointX
)
mainLine
.
tintLineFrom
(
startPointX
:
startPointX
,
to
:
endPointX
)
additionalLine
.
tintLineFrom
(
startPointX
:
startPointX
,
to
:
endPointX
)
additionalLine
.
tintLineFrom
(
startPointX
:
startPointX
,
to
:
endPointX
)
windLine
.
tintLineFrom
(
startPointX
:
startPointX
,
to
:
endPointX
)
}
}
public
func
tintMainDotAt
(
point
:
CGPoint
)
{
public
func
tintMainDotAt
(
point
:
CGPoint
)
{
mainLine
.
tintDotAt
(
point
:
point
)
mainLine
.
tintDotAt
(
point
:
point
)
windLine
.
tintDotAt
(
point
:
point
)
}
}
public
func
tintAdditionalDotAt
(
point
:
CGPoint
)
{
public
func
tintAdditionalDotAt
(
point
:
CGPoint
)
{
...
...
1Weather/UI/View controllers/Forecast/Cells/ForecastCellFactory.swift
View file @
bb0e57d7
...
@@ -22,7 +22,7 @@ private enum HourlyForecastCellType: Int, CaseIterable {
...
@@ -22,7 +22,7 @@ private enum HourlyForecastCellType: Int, CaseIterable {
case
day
case
day
case
tempInfo
case
tempInfo
case
precipitation
case
precipitation
//
case wind
case
wind
}
}
class
ForecastCellFactory
{
class
ForecastCellFactory
{
...
@@ -49,6 +49,7 @@ class ForecastCellFactory {
...
@@ -49,6 +49,7 @@ class ForecastCellFactory {
registerCell
(
type
:
ForecastHourlyCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastHourlyCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastInfoCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastInfoCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
PrecipitationCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
PrecipitationCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastWindSpeedCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CitySunCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CitySunCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityMoonCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityMoonCell
.
self
,
tableView
:
tableView
)
}
}
...
@@ -136,6 +137,12 @@ class ForecastCellFactory {
...
@@ -136,6 +137,12 @@ class ForecastCellFactory {
cell
.
configure
(
with
:
hourly
)
cell
.
configure
(
with
:
hourly
)
}
}
return
cell
return
cell
case
.
wind
:
let
cell
=
dequeueReusableCell
(
type
:
ForecastWindSpeedCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
if
let
hourly
=
forecastViewModel
.
location
?
.
hourly
{
cell
.
configure
(
with
:
hourly
)
}
return
cell
}
}
}
}
...
...
1Weather/UI/View controllers/Forecast/Cells/ForecastDailyCell.swift
View file @
bb0e57d7
...
@@ -38,7 +38,7 @@ class ForecastDailyCell: UITableViewCell {
...
@@ -38,7 +38,7 @@ class ForecastDailyCell: UITableViewCell {
public
func
configure
(
daily
:[
DailyWeather
],
offset
:
CGFloat
=
0
,
selectedButtonIndex
:
Int
=
0
)
{
public
func
configure
(
daily
:[
DailyWeather
],
offset
:
CGFloat
=
0
,
selectedButtonIndex
:
Int
=
0
)
{
self
.
forecastTimePeriodView
.
set
(
daily
:
daily
,
hourly
:
nil
)
self
.
forecastTimePeriodView
.
set
(
daily
:
daily
,
hourly
:
nil
)
if
self
.
forecastTimePeriodView
.
isEmpty
{
if
self
.
forecastTimePeriodView
.
isEmpty
{
self
.
forecastTimePeriodView
.
set
(
timePeriod
:
.
daily
,
buttonType
:
ForecastDetailPeriodButton
.
self
)
self
.
forecastTimePeriodView
.
set
(
forecastType
:
.
daily
,
buttonType
:
ForecastDetailPeriodButton
.
self
)
}
}
self
.
forecastTimePeriodView
.
selectButtonAt
(
index
:
selectedButtonIndex
)
self
.
forecastTimePeriodView
.
selectButtonAt
(
index
:
selectedButtonIndex
)
self
.
forecastTimePeriodView
.
update
(
offset
:
offset
)
self
.
forecastTimePeriodView
.
update
(
offset
:
offset
)
...
...
1Weather/UI/View controllers/Forecast/Cells/ForecastHourlyCell.swift
View file @
bb0e57d7
...
@@ -31,7 +31,7 @@ class ForecastHourlyCell: UITableViewCell {
...
@@ -31,7 +31,7 @@ class ForecastHourlyCell: UITableViewCell {
public
func
configure
(
hourly
:[
HourlyWeather
])
{
public
func
configure
(
hourly
:[
HourlyWeather
])
{
self
.
forecastTimePeriodView
.
set
(
daily
:
nil
,
hourly
:
hourly
)
self
.
forecastTimePeriodView
.
set
(
daily
:
nil
,
hourly
:
hourly
)
if
self
.
forecastTimePeriodView
.
isEmpty
{
if
self
.
forecastTimePeriodView
.
isEmpty
{
self
.
forecastTimePeriodView
.
set
(
timePeriod
:
.
hourly
,
buttonType
:
ForecastPeriodButton
.
self
)
self
.
forecastTimePeriodView
.
set
(
forecastType
:
.
hourly
,
buttonType
:
ForecastPeriodButton
.
self
)
}
}
}
}
}
}
...
...
1Weather/UI/View controllers/Forecast/Cells/ForecastWindSpeedCell.swift
0 → 100644
View file @
bb0e57d7
//
// ForecastWindSpeedCell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 23.03.2021.
//
import
UIKit
class
ForecastWindSpeedCell
:
UITableViewCell
{
//Private
private
let
headingLabel
=
UILabel
()
private
let
timePeriodView
=
ForecastTimePeriodView
()
private
let
summaryView
=
UIView
()
private
let
summaryImageView
=
UIImageView
()
private
let
summaryLabel
=
UILabel
()
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
prepareCell
()
prepareHeadingLabel
()
prepareTimePeriodView
()
prepareSummaryView
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
public
func
configure
(
with
hourly
:[
HourlyWeather
])
{
self
.
timePeriodView
.
set
(
daily
:
nil
,
hourly
:
hourly
)
if
self
.
timePeriodView
.
isEmpty
{
self
.
timePeriodView
.
set
(
forecastType
:
.
wind
,
buttonType
:
ForecastWindButton
.
self
)
}
}
}
//MARK:- Prepare
private
extension
ForecastWindSpeedCell
{
func
prepareCell
()
{
selectionStyle
=
.
none
contentView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
}
func
prepareHeadingLabel
()
{
headingLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
18
)
headingLabel
.
textColor
=
ThemeManager
.
currentTheme
.
primaryTextColor
headingLabel
.
text
=
"condition.wind"
.
localized
()
contentView
.
addSubview
(
headingLabel
)
headingLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
top
.
equalToSuperview
()
.
inset
(
18
)
}
}
func
prepareTimePeriodView
()
{
contentView
.
addSubview
(
timePeriodView
)
timePeriodView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
make
.
right
.
equalToSuperview
()
make
.
top
.
equalTo
(
headingLabel
.
snp
.
bottom
)
.
offset
(
18
)
.
priority
(
.
medium
)
make
.
height
.
equalTo
(
267
)
}
}
func
prepareSummaryView
()
{
summaryImageView
.
contentMode
=
.
scaleAspectFit
summaryImageView
.
image
=
UIImage
(
named
:
"blowingDust"
)
summaryView
.
addSubview
(
summaryImageView
)
summaryImageView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
.
inset
(
20
)
make
.
centerY
.
equalToSuperview
()
make
.
width
.
height
.
equalTo
(
12
)
}
summaryLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
13
)
summaryLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
summaryLabel
.
text
=
"Strongest winds between 12 AM - 1 PM"
summaryView
.
addSubview
(
summaryLabel
)
summaryLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalTo
(
summaryImageView
.
snp
.
right
)
.
offset
(
8
)
make
.
right
.
equalToSuperview
()
.
inset
(
8
)
make
.
centerY
.
equalToSuperview
()
}
summaryView
.
backgroundColor
=
UIColor
(
hex
:
0xd9ebfe
)
.
withAlphaComponent
(
0.5
)
summaryView
.
layer
.
cornerRadius
=
12
contentView
.
addSubview
(
summaryView
)
summaryView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
18
)
make
.
height
.
equalTo
(
40
)
make
.
top
.
equalTo
(
timePeriodView
.
snp
.
bottom
)
.
offset
(
20
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
15
)
}
}
}
1Weather/UI/View controllers/Today/Cells/CityForecastTimePeriodCell.swift
View file @
bb0e57d7
...
@@ -46,7 +46,8 @@ class CityForecastTimePeriodCell: UITableViewCell {
...
@@ -46,7 +46,8 @@ class CityForecastTimePeriodCell: UITableViewCell {
return
return
}
}
self
.
forecastTimePeriodView
.
set
(
timePeriod
:
timePeriod
,
buttonType
:
ForecastPeriodButton
.
self
)
let
forecastType
=
timePeriod
==
.
daily
?
ForecastType
.
daily
:
ForecastType
.
hourly
self
.
forecastTimePeriodView
.
set
(
forecastType
:
forecastType
,
buttonType
:
ForecastPeriodButton
.
self
)
}
}
}
}
...
...
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipButton.swift
View file @
bb0e57d7
...
@@ -89,17 +89,13 @@ class PrecipButton: UIControl {
...
@@ -89,17 +89,13 @@ class PrecipButton: UIControl {
self
.
precipView
.
set
(
value
:
CGFloat
(
percent
)
/
100.0
)
self
.
precipView
.
set
(
value
:
CGFloat
(
percent
)
/
100.0
)
self
.
valueLabel
.
text
=
"
\(
Int
(
percent
)
)
%"
self
.
valueLabel
.
text
=
"
\(
Int
(
percent
)
)
%"
if
let
nowDate
=
Date
.
nowDate
(
timeZone
:
hourly
.
timeZone
)
{
if
Calendar
.
timeZoneCalendar
(
timeZone
:
hourly
.
timeZone
)
.
isDate
(
hourly
.
date
,
equalTo
:
nowDate
,
toGranularity
:
.
hour
)
{
if
Calendar
.
isNow
(
fromDate
:
hourly
.
date
,
timeZone
:
hourly
.
timeZone
)
{
self
.
timeLabel
.
text
=
"day.now"
.
localized
()
.
uppercased
()
self
.
timeLabel
.
text
=
"day.now"
.
localized
()
.
uppercased
()
}
else
{
PrecipButton
.
hourlyFormatter
.
timeZone
=
hourly
.
timeZone
self
.
timeLabel
.
text
=
PrecipButton
.
hourlyFormatter
.
string
(
from
:
hourly
.
date
)
}
}
}
else
{
else
{
self
.
timeLabel
.
text
=
"--"
PrecipButton
.
hourlyFormatter
.
timeZone
=
hourly
.
timeZone
self
.
timeLabel
.
text
=
PrecipButton
.
hourlyFormatter
.
string
(
from
:
hourly
.
date
)
}
}
}
}
}
}
...
...
Pods/Pods.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
bb0e57d7
...
@@ -52,7 +52,7 @@
...
@@ -52,7 +52,7 @@
<
k
e
y
>
XMLCoder.xcscheme_
^#
shared
#^
_
<
/k
e
y
>
<
k
e
y
>
XMLCoder.xcscheme_
^#
shared
#^
_
<
/k
e
y
>
<
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
orderHint
<
/k
e
y
>
<
k
e
y
>
orderHint
<
/k
e
y
>
<
int
e
g
e
r
>
5
<
/int
e
g
e
r
>
<
int
e
g
e
r
>
6
<
/int
e
g
e
r
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
k
e
y
>
SuppressBuildableAutocreation
<
/k
e
y
>
<
k
e
y
>
SuppressBuildableAutocreation
<
/k
e
y
>
...
...
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