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
a0b2dc91
Commit
a0b2dc91
authored
Mar 22, 2021
by
Dmitriy Stepanets
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added Forecast hourly cells
parent
92fda9d3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
561 additions
and
153 deletions
+561
-153
1Weather.xcodeproj/project.pbxproj
+0
-0
1Weather.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
+1
-1
1Weather.xcworkspace/xcuserdata/dstepanets.xcuserdatad/UserInterfaceState.xcuserstate
+0
-0
1Weather/Extensions/Date+Now.swift
+21
-0
1Weather/Extensions/UITableView+HeaderSize.swift
+39
-0
1Weather/Resources/OneWeatherColorsAsset.xcassets/primary_text_color.colorset/Contents.json
+3
-3
1Weather/Resources/en.lproj/Localizable.strings
+2
-1
1Weather/UI/Helpers/ForecastTimePeriod/ForecastDetailPeriodButton.swift
+1
-1
1Weather/UI/Helpers/ForecastTimePeriod/ForecastTimePeriodView.swift
+20
-5
1Weather/UI/Helpers/ForecastTimePeriod/GraphLine.swift
+1
-1
1Weather/UI/Helpers/ForecastTimePeriod/TimePeriodOffsetHolder.swift
+23
-0
1Weather/UI/View controllers/Forecast/Cells/ForecastCellFactory.swift
+76
-26
1Weather/UI/View controllers/Forecast/Cells/ForecastDailyCell.swift
+28
-60
1Weather/UI/View controllers/Forecast/Cells/ForecastDayCell.swift
+80
-0
1Weather/UI/View controllers/Forecast/Cells/ForecastHourlyCell.swift
+100
-0
1Weather/UI/View controllers/Forecast/DaysControlView.swift
+15
-0
1Weather/UI/View controllers/Forecast/ForecastViewController.swift
+63
-18
1Weather/UI/View controllers/Today/Cells/CityDayTimesCell/CityDayTimesCell.swift
+1
-1
1Weather/UI/View controllers/Today/Cells/CityDayTimesCell/DayTimeView.swift
+14
-9
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipButton.swift
+33
-3
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipitationCell.swift
+22
-7
1Weather/UI/View controllers/Today/Cells/TodayCellFactory.swift
+2
-2
1Weather/ViewModels/ForecastViewModel.swift
+15
-14
Pods/Pods.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
+1
-1
No files found.
1Weather.xcodeproj/project.pbxproj
View file @
a0b2dc91
This diff is collapsed.
Click to expand it.
1Weather.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
a0b2dc91
...
...
@@ -7,7 +7,7 @@
<
k
e
y
>
1Weather.xcscheme_
^#
shared
#^
_
<
/k
e
y
>
<
d
i
c
t
>
<
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
>
<
k
e
y
>
PG
(
Playground
)
1.xcscheme
<
/k
e
y
>
<
d
i
c
t
>
...
...
1Weather.xcworkspace/xcuserdata/dstepanets.xcuserdatad/UserInterfaceState.xcuserstate
View file @
a0b2dc91
No preview for this file type
1Weather/Extensions/Date+Now.swift
0 → 100644
View file @
a0b2dc91
//
// Date+Now.swift
// 1Weather
//
// Created by Dmitry Stepanets on 22.03.2021.
//
import
UIKit
extension
Date
{
private
static
var
formatter
:
DateFormatter
=
{
let
fmt
=
DateFormatter
()
fmt
.
dateFormat
=
"yyyy-MM-dd HH:mm:ss"
return
fmt
}()
static
func
nowDate
(
timeZone
:
TimeZone
)
->
Self
?
{
formatter
.
timeZone
=
timeZone
let
nowDateString
=
formatter
.
string
(
from
:
Date
())
return
formatter
.
date
(
from
:
nowDateString
)
}
}
1Weather/Extensions/UITableView+HeaderSize.swift
0 → 100644
View file @
a0b2dc91
//
// UITableView+HeaderSize.swift
// 1Weather
//
// Created by Dmitry Stepanets on 22.03.2021.
//
import
UIKit
extension
UITableView
{
//Variable-height UITableView tableHeaderView with autolayout
func
layoutTableHeaderView
()
{
guard
let
headerView
=
self
.
tableHeaderView
else
{
return
}
headerView
.
translatesAutoresizingMaskIntoConstraints
=
false
let
headerWidth
=
headerView
.
bounds
.
size
.
width
;
let
temporaryWidthConstraints
=
NSLayoutConstraint
.
constraints
(
withVisualFormat
:
"[headerView(width)]"
,
options
:
NSLayoutConstraint
.
FormatOptions
(
rawValue
:
UInt
(
0
)),
metrics
:
[
"width"
:
headerWidth
],
views
:
[
"headerView"
:
headerView
])
headerView
.
addConstraints
(
temporaryWidthConstraints
)
headerView
.
setNeedsLayout
()
headerView
.
layoutIfNeeded
()
let
headerSize
=
headerView
.
systemLayoutSizeFitting
(
UITableView
.
layoutFittingCompressedSize
)
let
height
=
headerSize
.
height
var
frame
=
headerView
.
frame
frame
.
size
.
height
=
height
headerView
.
frame
=
frame
self
.
tableHeaderView
=
headerView
headerView
.
removeConstraints
(
temporaryWidthConstraints
)
headerView
.
translatesAutoresizingMaskIntoConstraints
=
true
}
}
1Weather/Resources/OneWeatherColorsAsset.xcassets/primary_text_color.colorset/Contents.json
View file @
a0b2dc91
...
...
@@ -5,9 +5,9 @@
"color-space"
:
"srgb"
,
"components"
:
{
"alpha"
:
"1.000"
,
"blue"
:
"
0x34
"
,
"green"
:
"
0x23
"
,
"red"
:
"
0x21
"
"blue"
:
"
52
"
,
"green"
:
"
35
"
,
"red"
:
"
33
"
}
},
"idiom"
:
"universal"
...
...
1Weather/Resources/en.lproj/Localizable.strings
View file @
a0b2dc91
...
...
@@ -32,6 +32,7 @@
//Day
"day.today" = "Today";
"day.now" = "Now";
//Day time
"dayTime.morning" = "Morning";
...
...
@@ -40,6 +41,7 @@
"dayTime.night" = "Night";
//Condition
"condition.temperature" = "Temperature";
"condition.precipitation" = "Precipitation";
"condition.humidity" = "Humidity";
"condition.uvIndex" = "UV-Index";
...
...
@@ -52,7 +54,6 @@
"forecast.timePeriod.daily" = "Daily";
"forecast.timePeriod.hourly" = "Hourly";
"forecast.timePeriod.minutely" = "Minutely";
"forecast.timePeriod.now" = "now";
//Sun
"sun.title" = "sun";
...
...
1Weather/UI/Helpers/ForecastTimePeriod/ForecastDetailPeriodButton.swift
View file @
a0b2dc91
...
...
@@ -111,7 +111,7 @@ private extension ForecastDetailPeriodButton {
clipsToBounds
=
false
backgroundColor
=
UIColor
.
white
layer
.
cornerRadius
=
12
layer
.
borderColor
=
UIColor
(
hex
:
0x
eceef6
)
.
cgColor
layer
.
borderColor
=
UIColor
(
hex
:
0x
dcdcdc
)
.
cgColor
layer
.
borderWidth
=
1
/
UIScreen
.
main
.
scale
}
...
...
1Weather/UI/Helpers/ForecastTimePeriod/ForecastTimePeriodView.swift
View file @
a0b2dc91
...
...
@@ -18,6 +18,7 @@ private struct HourlyGraphPoints {
protocol
ForecastTimePeriodViewDelegate
:
class
{
func
forecastTimePeriodView
(
view
:
ForecastTimePeriodView
,
didSelectButtonAt
index
:
Int
)
func
offsetDidChange
(
offset
:
CGFloat
)
}
class
ForecastTimePeriodView
:
UIView
{
...
...
@@ -34,6 +35,9 @@ class ForecastTimePeriodView: UIView {
//Public
weak
var
delegate
:
ForecastTimePeriodViewDelegate
?
var
isEmpty
:
Bool
{
return
dailyGraphPoints
.
maxTempPoints
.
isEmpty
&&
hourlyGraphPoints
.
points
.
isEmpty
}
//MARK:- View life cycle
init
()
{
...
...
@@ -72,10 +76,12 @@ class ForecastTimePeriodView: UIView {
buttons
.
enumerated
()
.
forEach
{
$1
.
isSelected
=
$0
==
index
if
$1
.
isSelected
{
self
.
scrollView
.
scrollRectToVisible
(
$1
.
frame
,
animated
:
true
)
}
}
}
public
func
update
(
offset
:
CGFloat
)
{
if
self
.
scrollView
.
contentOffset
.
x
!=
offset
{
self
.
scrollView
.
setContentOffset
(
.
init
(
x
:
offset
,
y
:
0
),
animated
:
false
)
}
}
...
...
@@ -251,12 +257,14 @@ class ForecastTimePeriodView: UIView {
}
}
//MARK:- Prepare
private
extension
ForecastTimePeriodView
{
func
preapreView
()
{
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColo
r
backgroundColor
=
.
clea
r
}
func
prepareScrollView
()
{
scrollView
.
delegate
=
self
scrollView
.
showsVerticalScrollIndicator
=
false
scrollView
.
showsHorizontalScrollIndicator
=
false
scrollView
.
clipsToBounds
=
false
...
...
@@ -289,3 +297,10 @@ private extension ForecastTimePeriodView {
scrollView
.
addSubview
(
graphView
)
}
}
//MARK:- UIScrollView Delegate
extension
ForecastTimePeriodView
:
UIScrollViewDelegate
{
func
scrollViewDidScroll
(
_
scrollView
:
UIScrollView
)
{
self
.
delegate
?
.
offsetDidChange
(
offset
:
scrollView
.
contentOffset
.
x
)
}
}
1Weather/UI/Helpers/ForecastTimePeriod/GraphLine.swift
View file @
a0b2dc91
...
...
@@ -15,7 +15,7 @@ struct LineDot {
struct
GraphLine
{
//Private
private
let
kIntersectAccuracy
:
CGFloat
=
2
private
let
kIntersectAccuracy
:
CGFloat
=
0
private
var
points
=
[
CGPoint
]()
private
let
settings
:
GraphLineSettings
private
let
onGetGraphRect
:
GraphRectClosure
...
...
1Weather/UI/Helpers/ForecastTimePeriod/TimePeriodOffsetHolder.swift
0 → 100644
View file @
a0b2dc91
//
// TimePeriodOffsetHolder.swift
// 1Weather
//
// Created by Dmitry Stepanets on 22.03.2021.
//
import
UIKit
protocol
TimePeriodOffsetDelegate
:
class
{
func
offsetDidChange
(
newOffset
:
CGFloat
)
}
class
TimePeriodOffsetHolder
{
//Public
private(set)
var
currentOffset
:
CGFloat
=
0
weak
var
delegate
:
TimePeriodOffsetDelegate
?
public
func
update
(
offset
:
CGFloat
)
{
self
.
currentOffset
=
offset
self
.
delegate
?
.
offsetDidChange
(
newOffset
:
offset
)
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastCellFactory.swift
View file @
a0b2dc91
...
...
@@ -7,8 +7,8 @@
import
UIKit
private
enum
ForecastCellType
:
Int
,
CaseIterable
{
case
forecast
Period
=
0
private
enum
Daily
ForecastCellType
:
Int
,
CaseIterable
{
case
forecast
=
0
case
forecastInfo
// case forecast
// case conditions
...
...
@@ -18,40 +18,76 @@ private enum ForecastCellType:Int, CaseIterable {
case
moon
}
private
enum
HourlyForecastCellType
:
Int
,
CaseIterable
{
case
day
case
tempInfo
case
precipitation
// case wind
}
class
ForecastCellFactory
{
//Private
private
let
forecastViewModel
:
ForecastViewModel
private
var
currentTimePeriod
=
TimePeriod
.
daily
//Public
public
var
numberOfRows
:
Int
{
return
ForecastCellType
.
allCases
.
count
return
currentTimePeriod
==
.
daily
?
DailyForecastCellType
.
allCases
.
count
:
Hourly
ForecastCellType
.
allCases
.
count
}
public
init
(
viewModel
:
ForecastViewModel
)
{
self
.
forecastViewModel
=
viewModel
}
public
func
setTimePeriod
(
timePeriod
:
TimePeriod
)
{
self
.
currentTimePeriod
=
timePeriod
}
public
func
registerCells
(
on
tableView
:
UITableView
)
{
registerCell
(
type
:
ForecastTimePeriodCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastDailyCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastDayCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastHourlyCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastInfoCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
PrecipitationCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CitySunCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityMoonCell
.
self
,
tableView
:
tableView
)
}
public
func
cellFromTableView
(
tableView
:
UITableView
,
indexPath
:
IndexPath
)
->
UITableViewCell
{
guard
let
cellType
=
ForecastCellType
(
rawValue
:
indexPath
.
row
)
else
{
switch
currentTimePeriod
{
case
.
daily
:
return
dailyCellFor
(
tableView
:
tableView
,
indexPath
:
indexPath
)
case
.
hourly
:
return
hourlyCellFor
(
tableView
:
tableView
,
indexPath
:
indexPath
)
}
}
public
func
willDisplay
(
cell
:
UITableViewCell
)
{
switch
cell
{
case
let
sunCell
as
CitySunCell
:
sunCell
.
updateSunPosition
()
case
let
moonCell
as
CityMoonCell
:
moonCell
.
updateMoonPosition
()
default
:
break
}
}
//Private
private
func
dailyCellFor
(
tableView
:
UITableView
,
indexPath
:
IndexPath
)
->
UITableViewCell
{
guard
let
cellType
=
DailyForecastCellType
(
rawValue
:
indexPath
.
row
)
else
{
return
UITableViewCell
()
}
switch
cellType
{
case
.
forecast
Period
:
let
cell
=
dequeueReusableCell
(
type
:
Forecast
TimePeriod
Cell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
case
.
forecast
:
let
cell
=
dequeueReusableCell
(
type
:
Forecast
Daily
Cell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
cell
.
delegate
=
self
cell
.
selectDayButtonAt
(
index
:
forecastViewModel
.
selectedDailyWeatherIndex
)
if
let
daily
=
forecastViewModel
.
location
?
.
daily
,
let
hourly
=
forecastViewModel
.
location
?
.
hourly
{
cell
.
configure
(
daily
:
daily
,
hourly
:
hourly
)
if
let
daily
=
forecastViewModel
.
location
?
.
daily
{
cell
.
configure
(
daily
:
daily
,
offset
:
forecastViewModel
.
offsetHolder
.
currentOffset
,
selectedButtonIndex
:
forecastViewModel
.
selectedDailyWeatherIndex
)
}
return
cell
case
.
forecastInfo
:
...
...
@@ -76,18 +112,33 @@ class ForecastCellFactory {
}
}
public
func
willDisplay
(
cell
:
UITableViewCell
)
{
switch
cell
{
case
let
sunCell
as
CitySunCell
:
sunCell
.
updateSunPosition
()
case
let
moonCell
as
CityMoonCell
:
moonCell
.
updateMoonPosition
()
default
:
break
private
func
hourlyCellFor
(
tableView
:
UITableView
,
indexPath
:
IndexPath
)
->
UITableViewCell
{
guard
let
cellType
=
HourlyForecastCellType
(
rawValue
:
indexPath
.
row
)
else
{
return
UITableViewCell
()
}
switch
cellType
{
case
.
day
:
let
cell
=
dequeueReusableCell
(
type
:
ForecastDayCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
if
let
today
=
forecastViewModel
.
location
?
.
today
{
cell
.
configure
(
today
:
today
)
}
return
cell
case
.
tempInfo
:
let
cell
=
dequeueReusableCell
(
type
:
ForecastHourlyCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
if
let
hourly
=
forecastViewModel
.
location
?
.
hourly
{
cell
.
configure
(
hourly
:
hourly
)
}
return
cell
case
.
precipitation
:
let
cell
=
dequeueReusableCell
(
type
:
PrecipitationCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
if
let
hourly
=
forecastViewModel
.
location
?
.
hourly
{
cell
.
configure
(
with
:
hourly
)
}
return
cell
}
}
//Private
private
func
registerCell
<
T
:
ReusableCellProtocol
>
(
type
:
T
.
Type
,
tableView
:
UITableView
)
{
tableView
.
register
(
type
,
forCellReuseIdentifier
:
T
.
kIdentifier
)
}
...
...
@@ -99,13 +150,12 @@ class ForecastCellFactory {
}
//MARK:- ForecastTimePeriodCell Delegate
extension
ForecastCellFactory
:
ForecastTimePeriodCellDelegate
{
func
timePeriodCell
(
cell
:
ForecastTimePeriodCell
,
didSelectButtonAt
index
:
Int
)
{
guard
forecastViewModel
.
currentTimePeriod
==
.
daily
else
{
return
}
forecastViewModel
.
selectDailyWeather
(
at
:
index
)
extension
ForecastCellFactory
:
ForecastDailyCellDelegate
{
func
timePeriodCell
(
cell
:
ForecastDailyCell
,
didSelectButtonAt
index
:
Int
)
{
forecastViewModel
.
selectDailyWeatherAt
(
index
:
index
)
}
func
timePeriodCell
(
cell
:
Forecast
TimePeriodCell
,
didSelectTimePeriod
timePeriod
:
TimePeriod
)
{
forecastViewModel
.
setTimePeriod
(
timePeriod
:
timePeriod
)
func
timePeriodCell
(
cell
:
Forecast
DailyCell
,
offsetDidChage
offset
:
CGFloat
)
{
forecastViewModel
.
offsetHolder
.
update
(
offset
:
offset
)
}
}
1Weather/UI/View controllers/Forecast/Cells/Forecast
TimePeriod
Cell.swift
→
1Weather/UI/View controllers/Forecast/Cells/Forecast
Daily
Cell.swift
View file @
a0b2dc91
//
// Forecast
TimePeriod
Cell.swift
// Forecast
Daily
Cell.swift
// 1Weather
//
// Created by Dmitry Stepanets on
10
.03.2021.
// Created by Dmitry Stepanets on
22
.03.2021.
//
import
UIKit
protocol
Forecast
TimePeriod
CellDelegate
:
class
{
func
timePeriodCell
(
cell
:
Forecast
TimePeriod
Cell
,
didSelectButtonAt
index
:
Int
)
func
timePeriodCell
(
cell
:
Forecast
TimePeriodCell
,
didSelectTimePeriod
timePeriod
:
TimePeriod
)
protocol
Forecast
Daily
CellDelegate
:
class
{
func
timePeriodCell
(
cell
:
Forecast
Daily
Cell
,
didSelectButtonAt
index
:
Int
)
func
timePeriodCell
(
cell
:
Forecast
DailyCell
,
offsetDidChage
offset
:
CGFloat
)
}
class
Forecast
TimePeriod
Cell
:
UITableViewCell
{
class
Forecast
Daily
Cell
:
UITableViewCell
{
//Private
private
let
periodSegmentedControl
=
ForecastTimePeriodControl
(
items
:
[
"forecast.timePeriod.daily"
.
localized
(),
"forecast.timePeriod.hourly"
.
localized
()])
private
let
forecastTimePeriodView
=
ForecastTimePeriodView
()
private
let
gradientView
=
GradientView
(
startColor
:
UIColor
(
hex
:
0xffffff
)
.
withAlphaComponent
(
0
),
endColor
:
UIColor
(
hex
:
0xdaddec
),
...
...
@@ -24,93 +21,64 @@ class ForecastTimePeriodCell: UITableViewCell {
private
var
graphIsDrawn
=
false
//Public
weak
var
delegate
:
Forecast
TimePeriod
CellDelegate
?
weak
var
delegate
:
Forecast
Daily
CellDelegate
?
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
prepareCell
()
prepareSegmentedControl
()
prepareGradient
()
prepare
Forecast
TimePeriodView
()
prepareTimePeriodView
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
//Public
public
func
configure
(
daily
:[
DailyWeather
],
hourly
:[
HourlyWeather
])
{
self
.
forecastTimePeriodView
.
set
(
daily
:
daily
,
hourly
:
hourly
)
if
graphIsDrawn
==
false
{
self
.
handleSegmentDidChange
()
self
.
graphIsDrawn
=
true
}
}
public
func
selectDayButtonAt
(
index
:
Int
)
{
self
.
forecastTimePeriodView
.
selectButtonAt
(
index
:
index
)
}
@objc
private
func
handleSegmentDidChange
()
{
guard
let
timePeriod
=
TimePeriod
(
rawValue
:
self
.
periodSegmentedControl
.
selectedSegmentIndex
)
else
{
return
}
switch
timePeriod
{
case
.
daily
:
self
.
forecastTimePeriodView
.
set
(
timePeriod
:
timePeriod
,
buttonType
:
ForecastDetailPeriodButton
.
self
)
case
.
hourly
:
self
.
forecastTimePeriodView
.
set
(
timePeriod
:
timePeriod
,
buttonType
:
ForecastPeriodButton
.
self
)
public
func
configure
(
daily
:[
DailyWeather
],
offset
:
CGFloat
=
0
,
selectedButtonIndex
:
Int
=
0
)
{
self
.
forecastTimePeriodView
.
set
(
daily
:
daily
,
hourly
:
nil
)
if
self
.
forecastTimePeriodView
.
isEmpty
{
self
.
forecastTimePeriodView
.
set
(
timePeriod
:
.
daily
,
buttonType
:
ForecastDetailPeriodButton
.
self
)
}
delegate
?
.
timePeriodCell
(
cell
:
self
,
didSelectTimePeriod
:
timePeriod
)
self
.
forecastTimePeriodView
.
selectButtonAt
(
index
:
selectedButtonIndex
)
self
.
forecastTimePeriodView
.
update
(
offset
:
offset
)
}
}
private
extension
Forecast
TimePeriod
Cell
{
private
extension
Forecast
Daily
Cell
{
func
prepareCell
()
{
selectionStyle
=
.
none
contentView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
}
func
prepareSegmentedControl
()
{
periodSegmentedControl
.
selectedSegmentIndex
=
0
periodSegmentedControl
.
addTarget
(
self
,
action
:
#selector(
handleSegmentDidChange
)
,
for
:
.
valueChanged
)
contentView
.
addSubview
(
periodSegmentedControl
)
periodSegmentedControl
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalToSuperview
()
.
inset
(
15
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
16
)
make
.
height
.
equalTo
(
40
)
func
prepareGradient
()
{
contentView
.
addSubview
(
gradientView
)
gradientView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
bottom
.
equalToSuperview
()
make
.
height
.
equalTo
(
172
)
}
}
func
prepare
Forecast
TimePeriodView
()
{
func
prepareTimePeriodView
()
{
forecastTimePeriodView
.
delegate
=
self
contentView
.
addSubview
(
forecastTimePeriodView
)
forecastTimePeriodView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
make
.
right
.
equalToSuperview
()
make
.
top
.
equalTo
(
periodSegmentedControl
.
snp
.
bottom
)
.
off
set
(
20
)
.
priority
(
.
medium
)
make
.
top
.
equalTo
Superview
()
.
in
set
(
20
)
.
priority
(
.
medium
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
30
)
make
.
height
.
equalTo
(
267
)
}
}
func
prepareGradient
()
{
contentView
.
addSubview
(
gradientView
)
gradientView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
bottom
.
equalToSuperview
()
make
.
height
.
equalTo
(
172
)
}
}
}
//MARK:- ForecastTimePeriodView Delegate
extension
Forecast
TimePeriod
Cell
:
ForecastTimePeriodViewDelegate
{
extension
Forecast
Daily
Cell
:
ForecastTimePeriodViewDelegate
{
func
forecastTimePeriodView
(
view
:
ForecastTimePeriodView
,
didSelectButtonAt
index
:
Int
)
{
self
.
delegate
?
.
timePeriodCell
(
cell
:
self
,
didSelectButtonAt
:
index
)
}
func
offsetDidChange
(
offset
:
CGFloat
)
{
self
.
delegate
?
.
timePeriodCell
(
cell
:
self
,
offsetDidChage
:
offset
)
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastDayCell.swift
0 → 100644
View file @
a0b2dc91
//
// ForecastDayCell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 22.03.2021.
//
import
UIKit
class
ForecastDayCell
:
UITableViewCell
{
//Private
private
let
dateLabel
=
UILabel
()
private
let
forecastLabel
=
UILabel
()
private
let
gradientView
=
GradientView
(
startColor
:
UIColor
(
hex
:
0xffffff
)
.
withAlphaComponent
(
0
),
endColor
:
UIColor
(
hex
:
0xdaddec
),
opacity
:
0.5
)
private
static
var
formatter
:
DateFormatter
=
{
let
fmt
=
DateFormatter
()
fmt
.
dateFormat
=
"d, E"
return
fmt
}()
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
prepareCell
()
prepareGradient
()
prepareLabels
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
public
func
configure
(
today
:
CurrentWeather
)
{
ForecastDayCell
.
formatter
.
timeZone
=
today
.
timeZone
dateLabel
.
text
=
ForecastDayCell
.
formatter
.
string
(
from
:
today
.
date
)
let
maxTemp
=
today
.
maxTemp
?
.
shortString
??
"--"
let
minTemp
=
today
.
minTemp
?
.
shortString
??
"--"
forecastLabel
.
text
=
"
\(
today
.
type
.
localized
(
isDay
:
today
.
isDay
)
)
|
\(
maxTemp
)
/
\(
minTemp
)
"
}
}
//MARK:- Prepare
private
extension
ForecastDayCell
{
func
prepareCell
()
{
selectionStyle
=
.
none
contentView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
}
func
prepareGradient
()
{
contentView
.
addSubview
(
gradientView
)
gradientView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
bottom
.
equalToSuperview
()
make
.
height
.
equalTo
(
41
)
}
}
func
prepareLabels
()
{
dateLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
34
)
dateLabel
.
textColor
=
ThemeManager
.
currentTheme
.
primaryTextColor
dateLabel
.
setContentHuggingPriority
(
.
fittingSizeLevel
,
for
:
.
vertical
)
contentView
.
addSubview
(
dateLabel
)
dateLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
top
.
equalToSuperview
()
.
inset
(
18
)
}
forecastLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
16
)
forecastLabel
.
textColor
=
ThemeManager
.
currentTheme
.
primaryTextColor
contentView
.
addSubview
(
forecastLabel
)
forecastLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
.
inset
(
18
)
make
.
top
.
equalTo
(
dateLabel
.
snp
.
bottom
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
18
)
}
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastHourlyCell.swift
0 → 100644
View file @
a0b2dc91
//
// ForecastHourlyCell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 22.03.2021.
//
import
UIKit
class
ForecastHourlyCell
:
UITableViewCell
{
//Private
private
let
tempLabel
=
UILabel
()
private
let
forecastTimePeriodView
=
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
()
prepareTempLabel
()
prepareTimePeriodView
()
prepareSummaryView
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
public
func
configure
(
hourly
:[
HourlyWeather
])
{
self
.
forecastTimePeriodView
.
set
(
daily
:
nil
,
hourly
:
hourly
)
if
self
.
forecastTimePeriodView
.
isEmpty
{
self
.
forecastTimePeriodView
.
set
(
timePeriod
:
.
hourly
,
buttonType
:
ForecastPeriodButton
.
self
)
}
}
}
//MARK:- Prepare
private
extension
ForecastHourlyCell
{
func
prepareCell
()
{
selectionStyle
=
.
none
contentView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
}
func
prepareTempLabel
()
{
tempLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
18
)
tempLabel
.
textColor
=
ThemeManager
.
currentTheme
.
primaryTextColor
tempLabel
.
text
=
"condition.temperature"
.
localized
()
contentView
.
addSubview
(
tempLabel
)
tempLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
top
.
equalToSuperview
()
.
inset
(
18
)
}
}
func
prepareTimePeriodView
()
{
contentView
.
addSubview
(
forecastTimePeriodView
)
forecastTimePeriodView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
make
.
right
.
equalToSuperview
()
make
.
top
.
equalTo
(
tempLabel
.
snp
.
bottom
)
.
offset
(
18
)
.
priority
(
.
medium
)
make
.
height
.
equalTo
(
267
)
}
}
func
prepareSummaryView
()
{
summaryImageView
.
contentMode
=
.
scaleAspectFit
summaryImageView
.
image
=
UIImage
(
named
:
"hot_indicator"
)
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
=
"Hottest part of the day 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
:
0xfaedda
)
.
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
(
forecastTimePeriodView
.
snp
.
bottom
)
.
offset
(
20
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
15
)
}
}
}
1Weather/UI/View controllers/Forecast/DaysControlView.swift
View file @
a0b2dc91
...
...
@@ -9,6 +9,7 @@ import UIKit
protocol
DaysControlViewDelegate
:
class
{
func
didSelectButtonAt
(
index
:
Int
)
func
offsetDidChange
(
offset
:
CGFloat
)
}
class
DaysControlView
:
UIView
{
...
...
@@ -73,6 +74,12 @@ class DaysControlView: UIView {
}
}
public
func
update
(
offset
:
CGFloat
)
{
if
self
.
scrollView
.
contentOffset
.
x
!=
offset
{
self
.
scrollView
.
setContentOffset
(
.
init
(
x
:
offset
,
y
:
0
),
animated
:
false
)
}
}
@objc
private
func
handleDayButton
(
button
:
DayControlButton
)
{
guard
let
buttons
=
stackView
.
arrangedSubviews
as?
[
DayControlButton
]
else
{
return
}
...
...
@@ -100,6 +107,7 @@ private extension DaysControlView {
func
prepareScrollView
()
{
scrollView
.
showsVerticalScrollIndicator
=
false
scrollView
.
showsHorizontalScrollIndicator
=
false
scrollView
.
delegate
=
self
addSubview
(
scrollView
)
scrollView
.
snp
.
makeConstraints
{
(
make
)
in
...
...
@@ -126,6 +134,13 @@ private extension DaysControlView {
}
}
//MARK:- UIScrollView Delegate
extension
DaysControlView
:
UIScrollViewDelegate
{
func
scrollViewDidScroll
(
_
scrollView
:
UIScrollView
)
{
delegate
?
.
offsetDidChange
(
offset
:
scrollView
.
contentOffset
.
x
)
}
}
//MARK:- Button
private
class
DayControlButton
:
UIControl
{
//Private
...
...
1Weather/UI/View controllers/Forecast/ForecastViewController.swift
View file @
a0b2dc91
...
...
@@ -12,10 +12,15 @@ class ForecastViewController: UIViewController {
private
let
forecastCellFactory
:
ForecastCellFactory
private
let
cityButton
=
NavigationCityButton
()
private
let
daysControlView
=
DaysControlView
()
private
let
timePeriodControl
=
ForecastTimePeriodControl
(
items
:
[
"forecast.timePeriod.daily"
.
localized
(),
"forecast.timePeriod.hourly"
.
localized
()])
private
let
tableView
=
UITableView
()
private
let
viewModel
:
ForecastViewModel
private
var
timePeriodCellFrame
=
CGRect
.
zero
private
var
localizationObserver
:
Any
?
private
var
timePeriod
:
TimePeriod
{
return
TimePeriod
(
rawValue
:
timePeriodControl
.
selectedSegmentIndex
)
??
.
daily
}
init
(
viewModel
:
ForecastViewModel
)
{
self
.
viewModel
=
viewModel
...
...
@@ -31,16 +36,23 @@ class ForecastViewController: UIViewController {
super
.
viewDidLoad
()
viewModel
.
delegate
=
self
viewModel
.
offsetHolder
.
delegate
=
self
prepareViewController
()
prepareNavigationBar
()
prepareTableView
()
prepareTimePeriodControl
()
prepareDayControlsView
()
refreshCityButton
()
refreshDayButtons
()
}
override
func
viewDidLayoutSubviews
()
{
super
.
viewDidLayoutSubviews
()
self
.
tableView
.
layoutTableHeaderView
()
}
private
func
refreshCityButton
()
{
cityButton
.
configure
(
with
:
viewModel
.
location
)
cityButton
.
isHidden
=
false
...
...
@@ -55,6 +67,15 @@ class ForecastViewController: UIViewController {
}
}
@objc
private
func
handleSegmentDidChange
()
{
guard
let
timePeriod
=
TimePeriod
(
rawValue
:
self
.
timePeriodControl
.
selectedSegmentIndex
)
else
{
return
}
forecastCellFactory
.
setTimePeriod
(
timePeriod
:
timePeriod
)
self
.
tableView
.
reloadData
()
}
@objc
private
func
handleCityButton
()
{
print
(
"Handle city button"
)
}
...
...
@@ -121,6 +142,22 @@ private extension ForecastViewController {
make
.
edges
.
equalToSuperview
()
}
}
func
prepareTimePeriodControl
()
{
let
container
=
UIView
()
container
.
addSubview
(
self
.
timePeriodControl
)
timePeriodControl
.
selectedSegmentIndex
=
0
timePeriodControl
.
addTarget
(
self
,
action
:
#selector(
handleSegmentDidChange
)
,
for
:
.
valueChanged
)
self
.
timePeriodControl
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
18
)
.
priority
(
.
init
(
999
))
make
.
top
.
equalToSuperview
()
.
inset
(
30
)
make
.
bottom
.
equalToSuperview
()
.
priority
(
.
init
(
999
))
make
.
height
.
equalTo
(
40
)
.
priority
(
.
init
(
999
))
}
tableView
.
tableHeaderView
=
container
}
}
//MARK:- UITableView Delegate
...
...
@@ -129,7 +166,7 @@ extension ForecastViewController: UITableViewDelegate {
guard
let
navVC
=
self
.
navigationController
,
viewModel
.
location
?
.
daily
.
isEmpty
==
false
,
viewModel
.
currentT
imePeriod
==
.
daily
self
.
t
imePeriod
==
.
daily
else
{
return
}
...
...
@@ -143,6 +180,7 @@ extension ForecastViewController: UITableViewDelegate {
if
scrollView
.
contentOffset
.
y
>=
startPointY
{
if
!
navVC
.
isNavigationBarHidden
{
navVC
.
setNavigationBarHidden
(
true
,
animated
:
true
)
self
.
daysControlView
.
update
(
offset
:
self
.
viewModel
.
offsetHolder
.
currentOffset
)
UIView
.
animate
(
withDuration
:
0.35
)
{
self
.
daysControlView
.
alpha
=
1
}
...
...
@@ -183,30 +221,37 @@ extension ForecastViewController: ForecastViewModelDelegate {
refreshDayButtons
()
}
func
selectedDailyWeatherDidChange
()
{
var
indexPathToReload
=
[
IndexPath
]()
for
index
in
0
..<
forecastCellFactory
.
numberOfRows
{
if
index
==
0
{
continue
}
func
selectedWeatherDidChange
()
{
switch
timePeriod
{
case
.
daily
:
var
indexPathToReload
=
[
IndexPath
]()
for
index
in
0
..<
forecastCellFactory
.
numberOfRows
{
if
index
==
0
{
continue
}
indexPathToReload
.
append
([
0
,
index
])
}
indexPathToReload
.
append
([
0
,
index
])
}
tableView
.
reloadRows
(
at
:
indexPathToReload
,
with
:
.
none
)
daysControlView
.
selectDayAt
(
index
:
viewModel
.
selectedDailyWeatherIndex
)
}
func
selectedTimePeriodDidChange
()
{
guard
let
timePeriodCell
=
tableView
.
cellForRow
(
at
:
[
0
,
0
])
as?
ForecastTimePeriodCell
else
{
return
tableView
.
reloadRows
(
at
:
indexPathToReload
,
with
:
.
none
)
daysControlView
.
selectDayAt
(
index
:
viewModel
.
selectedDailyWeatherIndex
)
case
.
hourly
:
tableView
.
reloadData
()
}
timePeriodCell
.
selectDayButtonAt
(
index
:
viewModel
.
selectedDailyWeatherIndex
)
}
}
//MARK:- DaysControlView Delegate
extension
ForecastViewController
:
DaysControlViewDelegate
{
func
didSelectButtonAt
(
index
:
Int
)
{
viewModel
.
selectDailyWeather
(
at
:
index
)
viewModel
.
selectDailyWeatherAt
(
index
:
index
)
}
func
offsetDidChange
(
offset
:
CGFloat
)
{
viewModel
.
offsetHolder
.
update
(
offset
:
offset
)
}
}
//MARK:- TimePeriodOffset Delegate
extension
ForecastViewController
:
TimePeriodOffsetDelegate
{
func
offsetDidChange
(
newOffset
:
CGFloat
)
{
}
}
1Weather/UI/View controllers/Today/Cells/CityDayTimesCell/CityDayTimesCell.swift
View file @
a0b2dc91
...
...
@@ -84,7 +84,7 @@ private extension CityDayTimesCell {
func
prepareStackView
()
{
stackView
.
axis
=
.
horizontal
stackView
.
distribution
=
.
fillProportionally
stackView
.
distribution
=
.
equalCentering
stackView
.
alignment
=
.
center
stackView
.
spacing
=
0
stackView
.
clipsToBounds
=
false
...
...
1Weather/UI/View controllers/Today/Cells/CityDayTimesCell/DayTimeView.swift
View file @
a0b2dc91
...
...
@@ -45,7 +45,7 @@ private extension DayTimeView {
addSubview
(
dayTimeLabel
)
forecastImageView
.
contentMode
=
.
scaleAspectFit
forecastImageView
.
image
=
nil
//TODO: we need a placeholder here?
forecastImageView
.
image
=
WeatherType
.
unknown
.
image
(
isDay
:
true
)
addSubview
(
forecastImageView
)
tempLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
18
)
...
...
@@ -53,7 +53,7 @@ private extension DayTimeView {
tempLabel
.
text
=
"--"
addSubview
(
tempLabel
)
dayTimeConditionLabel
.
numberOfLines
=
2
dayTimeConditionLabel
.
numberOfLines
=
3
dayTimeConditionLabel
.
lineBreakMode
=
.
byWordWrapping
dayTimeConditionLabel
.
textAlignment
=
.
center
dayTimeConditionLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
14
)
...
...
@@ -70,19 +70,24 @@ private extension DayTimeView {
forecastImageView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
width
.
height
.
equalTo
(
28
)
make
.
centerX
.
equalToSuperview
()
make
.
top
.
equalTo
(
dayTimeLabel
.
snp
.
bottom
)
.
offset
(
33
)
make
.
top
.
equalTo
(
dayTimeLabel
.
snp
.
bottom
)
.
offset
(
18
)
}
tempLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
centerX
.
equalToSuperview
()
make
.
top
.
equalTo
(
forecastImageView
.
snp
.
bottom
)
.
offset
(
30
)
make
.
top
.
equalTo
(
forecastImageView
.
snp
.
bottom
)
.
offset
(
18
)
}
dayTimeConditionLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
2
)
make
.
top
.
equalTo
(
tempLabel
.
snp
.
bottom
)
.
offset
(
14
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
24
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
8
)
make
.
top
.
equalTo
(
tempLabel
.
snp
.
bottom
)
.
offset
(
14
)
.
priority
(
.
low
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
18
)
make
.
height
.
equalTo
(
52
)
}
self
.
snp
.
makeConstraints
{
(
make
)
in
make
.
height
.
equalTo
(
210
)
make
.
width
.
equalTo
(
90
)
}
}
...
...
@@ -94,7 +99,7 @@ private extension DayTimeView {
separatorView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalTo
(
dayTimeLabel
)
make
.
bottom
.
equalTo
(
dayTimeConditionLabel
)
make
.
bottom
.
equalTo
Superview
()
.
inset
(
18
)
make
.
right
.
equalToSuperview
()
make
.
width
.
equalTo
(
1
)
}
...
...
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipButton.swift
View file @
a0b2dc91
...
...
@@ -9,10 +9,14 @@ import UIKit
class
PrecipButton
:
UIControl
{
//Private
private
static
let
f
ormatter
:
DateFormatter
=
{
private
static
var
dailyF
ormatter
:
DateFormatter
=
{
let
fmt
=
DateFormatter
()
fmt
.
dateFormat
=
"d, E"
return
fmt
}()
private
static
var
hourlyFormatter
:
DateFormatter
=
{
let
fmt
=
DateFormatter
()
fmt
.
dateFormat
=
"h a"
return
fmt
}()
private
let
valueLabel
=
UILabel
()
...
...
@@ -65,11 +69,37 @@ class PrecipButton: UIControl {
self
.
precipView
.
set
(
value
:
CGFloat
(
percent
)
/
100.0
)
self
.
valueLabel
.
text
=
"
\(
Int
(
percent
)
)
%"
if
Calendar
.
timeZoneCalendar
(
timeZone
:
daily
.
timeZone
)
.
isDateInToday
(
daily
.
date
)
{
self
.
timeLabel
.
text
=
"day.today"
.
localized
()
}
else
{
self
.
timeLabel
.
text
=
PrecipButton
.
formatter
.
string
(
from
:
daily
.
date
)
PrecipButton
.
dailyFormatter
.
timeZone
=
daily
.
timeZone
self
.
timeLabel
.
text
=
PrecipButton
.
dailyFormatter
.
string
(
from
:
daily
.
date
)
}
}
public
func
configure
(
with
hourly
:
HourlyWeather
)
{
guard
let
percent
=
hourly
.
precipitationProbability
else
{
self
.
precipView
.
set
(
value
:
0
)
self
.
valueLabel
.
text
=
"0%"
self
.
timeLabel
.
text
=
nil
return
}
self
.
precipView
.
set
(
value
:
CGFloat
(
percent
)
/
100.0
)
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
)
{
self
.
timeLabel
.
text
=
"day.now"
.
localized
()
.
uppercased
()
}
else
{
PrecipButton
.
hourlyFormatter
.
timeZone
=
hourly
.
timeZone
self
.
timeLabel
.
text
=
PrecipButton
.
hourlyFormatter
.
string
(
from
:
hourly
.
date
)
}
}
else
{
self
.
timeLabel
.
text
=
"--"
}
}
}
...
...
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/
CityPrecip
Cell.swift
→
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/
Precipitation
Cell.swift
View file @
a0b2dc91
//
//
CityPrecip
Cell.swift
//
Precipitation
Cell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 24.02.2021.
...
...
@@ -7,7 +7,7 @@
import
UIKit
class
CityPrecip
Cell
:
UITableViewCell
{
class
Precipitation
Cell
:
UITableViewCell
{
//Private
private
let
headingLabel
=
UILabel
()
private
let
headingButton
=
ArrowButton
()
...
...
@@ -32,11 +32,9 @@ class CityPrecipCell: UITableViewCell {
}
public
func
configure
(
with
dayily
:[
DailyWeather
])
{
stackView
.
arrangedSubviews
.
forEach
{
stackView
.
removeArrangedSubview
(
$0
)
$0
.
removeFromSuperview
()
}
guard
stackView
.
arrangedSubviews
.
isEmpty
else
{
return
}
self
.
headingButton
.
isHidden
=
false
for
index
in
0
..<
dayily
.
count
{
let
precipButton
=
PrecipButton
()
precipButton
.
isSelected
=
index
==
1
...
...
@@ -47,6 +45,23 @@ class CityPrecipCell: UITableViewCell {
stackView
.
layoutIfNeeded
()
}
public
func
configure
(
with
hourly
:[
HourlyWeather
])
{
guard
stackView
.
arrangedSubviews
.
isEmpty
else
{
return
}
self
.
headingLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
18
)
self
.
headingButton
.
isHidden
=
true
self
.
headingLabel
.
text
=
"precipitation.title"
.
localized
()
.
capitalized
self
.
headingLabel
.
textColor
=
ThemeManager
.
currentTheme
.
primaryTextColor
for
index
in
0
..<
hourly
.
count
{
let
precipButton
=
PrecipButton
()
precipButton
.
isSelected
=
index
==
0
precipButton
.
configure
(
with
:
hourly
[
index
])
precipButton
.
addTarget
(
self
,
action
:
#selector(
handlePrecipButton(button:)
)
,
for
:
.
touchUpInside
)
stackView
.
addArrangedSubview
(
precipButton
)
}
stackView
.
layoutIfNeeded
()
}
//Private
@objc
private
func
handleArrowButton
()
{
...
...
@@ -62,7 +77,7 @@ class CityPrecipCell: UITableViewCell {
}
//MARK:- Prepare
private
extension
CityPrecip
Cell
{
private
extension
Precipitation
Cell
{
func
prepareCell
()
{
selectionStyle
=
.
none
contentView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
...
...
1Weather/UI/View controllers/Today/Cells/TodayCellFactory.swift
View file @
a0b2dc91
...
...
@@ -29,7 +29,7 @@ class TodayCellFactory {
registerCell
(
type
:
TodayAdCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityConditionsCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityForecastTimePeriodCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityPrecip
Cell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
Precipitation
Cell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityDayTimesCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityAirQualityCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CitySunCell
.
self
,
tableView
:
tableView
)
...
...
@@ -62,7 +62,7 @@ class TodayCellFactory {
cell
.
configure
(
with
:
loc
)
return
cell
case
.
precipitation
:
let
cell
=
dequeueReusableCell
(
type
:
CityPrecip
Cell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
let
cell
=
dequeueReusableCell
(
type
:
Precipitation
Cell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
cell
.
configure
(
with
:
loc
.
daily
)
return
cell
case
.
dayTime
:
...
...
1Weather/ViewModels/ForecastViewModel.swift
View file @
a0b2dc91
...
...
@@ -8,16 +8,16 @@
import
UIKit
protocol
ForecastViewModelDelegate
:
ViewModelDelegate
{
func
selectedDailyWeatherDidChange
()
func
selectedTimePeriodDidChange
()
func
selectedWeatherDidChange
()
}
class
ForecastViewModel
:
ViewModelProtocol
{
//Public
public
let
offsetHolder
=
TimePeriodOffsetHolder
()
public
weak
var
delegate
:
ForecastViewModelDelegate
?
public
private(set)
var
location
:
Location
?
public
private(set)
var
selectedDailyWeather
:
DailyWeather
?
public
private(set)
var
currentTimePeriod
=
TimePeriod
.
daily
public
private(set)
var
selectedHourlyWeather
:
HourlyWeather
?
public
var
selectedDailyWeatherIndex
:
Int
{
guard
let
loc
=
self
.
location
else
{
return
-
1
}
...
...
@@ -46,24 +46,24 @@ class ForecastViewModel: ViewModelProtocol {
locationManager
.
updateWeather
()
}
public
func
select
(
dailyWeather
:
DailyWeather
)
{
self
.
selectedDailyWeather
=
dailyWeather
self
.
delegate
?
.
selectedDailyWeatherDidChange
()
}
public
func
selectDailyWeather
(
at
index
:
Int
)
{
public
func
selectDailyWeatherAt
(
index
:
Int
)
{
guard
let
daily
=
location
?
.
daily
else
{
return
}
daily
.
enumerated
()
.
forEach
{
if
$0
==
index
{
self
.
selectedDailyWeather
=
$1
}
}
self
.
delegate
?
.
selected
Daily
WeatherDidChange
()
self
.
delegate
?
.
selectedWeatherDidChange
()
}
public
func
setTimePeriod
(
timePeriod
:
TimePeriod
)
{
self
.
currentTimePeriod
=
timePeriod
self
.
delegate
?
.
selectedTimePeriodDidChange
()
public
func
selectHourlyWeatherAt
(
index
:
Int
)
{
guard
let
hourly
=
location
?
.
hourly
else
{
return
}
hourly
.
enumerated
()
.
forEach
{
if
$0
==
index
{
self
.
selectedHourlyWeather
=
$1
}
}
self
.
delegate
?
.
selectedWeatherDidChange
()
}
}
...
...
@@ -73,7 +73,8 @@ extension ForecastViewModel: LocationManagerDelegate {
DispatchQueue
.
main
.
async
{
print
(
"TVM-Forecast"
)
self
.
location
=
newLocation
self
.
selectDailyWeather
(
at
:
0
)
self
.
selectDailyWeatherAt
(
index
:
0
)
self
.
selectHourlyWeatherAt
(
index
:
0
)
self
.
delegate
?
.
viewModelDidChange
(
model
:
self
)
}
}
...
...
Pods/Pods.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
a0b2dc91
...
...
@@ -52,7 +52,7 @@
<
k
e
y
>
XMLCoder.xcscheme_
^#
shared
#^
_
<
/k
e
y
>
<
d
i
c
t
>
<
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
>
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