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
445be99f
Commit
445be99f
authored
Mar 17, 2021
by
Dmitriy Stepanets
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Changed DaysControlView presentation logic
parent
94c6f356
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
385 additions
and
195 deletions
+385
-195
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/Coordinators/TodayCoordinator.swift
+1
-1
1Weather/Model/ModelObjects/DailyWeather.swift
+9
-0
1Weather/UI/Helpers/DayControlsNavigationBar.swift
+0
-59
1Weather/UI/Helpers/DayControlsNavigatoinController.swift
+0
-52
1Weather/UI/Helpers/ForecastTimePeriod/ForecastTimePeriodView.swift
+8
-3
1Weather/UI/View controllers/Forecast/Cells/ForecastCellFactory.swift
+17
-7
1Weather/UI/View controllers/Forecast/Cells/ForecastInfoCell.swift
+111
-0
1Weather/UI/View controllers/Forecast/Cells/ForecastTimePeriodCell.swift
+2
-2
1Weather/UI/View controllers/Forecast/DaysControlView.swift
+178
-0
1Weather/UI/View controllers/Forecast/ForecastViewController.swift
+47
-13
1Weather/UI/View controllers/Today/Cells/CityDayTimesCell/CityDayTimesCell.swift
+3
-1
1Weather/UI/View controllers/Today/Cells/CityDayTimesCell/DayTimeView.swift
+4
-1
1Weather/UI/View controllers/Today/Cells/CityForecastTimePeriodCell.swift
+1
-1
1Weather/UI/View controllers/Today/Cells/TodayCellFactory.swift
+0
-5
1Weather/UI/View controllers/Today/TodayViewController.swift
+0
-41
1Weather/ViewModels/ForecastViewModel.swift
+0
-5
Pods/Pods.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
+3
-3
No files found.
1Weather.xcodeproj/project.pbxproj
View file @
445be99f
This diff is collapsed.
Click to expand it.
1Weather.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
445be99f
...
@@ -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
>
3
<
/int
e
g
e
r
>
<
int
e
g
e
r
>
6
<
/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 @
445be99f
No preview for this file type
1Weather/Coordinators/TodayCoordinator.swift
View file @
445be99f
...
@@ -10,7 +10,7 @@ import UIKit
...
@@ -10,7 +10,7 @@ import UIKit
class
TodayCoordinator
:
Coordinator
{
class
TodayCoordinator
:
Coordinator
{
//Private
//Private
private
let
todayViewModel
=
TodayViewModel
(
locationManager
:
LocationManager
.
shared
)
// TODO: get rid of singleton maybe?
private
let
todayViewModel
=
TodayViewModel
(
locationManager
:
LocationManager
.
shared
)
// TODO: get rid of singleton maybe?
private
let
navigationController
=
DayControlsNavigatoinController
(
)
private
let
navigationController
=
UINavigationController
(
nibName
:
nil
,
bundle
:
nil
)
private
var
tabBarController
:
UITabBarController
?
private
var
tabBarController
:
UITabBarController
?
//Public
//Public
...
...
1Weather/Model/ModelObjects/DailyWeather.swift
View file @
445be99f
...
@@ -8,11 +8,19 @@
...
@@ -8,11 +8,19 @@
import
Foundation
import
Foundation
public
struct
DailyWeather
:
Equatable
,
Hashable
{
public
struct
DailyWeather
:
Equatable
,
Hashable
{
private
static
var
timeZoneCaledar
:
Calendar
=
{
let
cal
=
Calendar
(
identifier
:
Calendar
.
current
.
identifier
)
return
cal
}()
public
var
lastTimeUpdated
:
Date
public
var
lastTimeUpdated
:
Date
public
var
date
:
Date
public
var
date
:
Date
public
var
timeZone
:
TimeZone
public
var
timeZone
:
TimeZone
public
var
weekDay
:
WeekDay
public
var
weekDay
:
WeekDay
public
var
type
:
WeatherType
=
.
unknown
public
var
type
:
WeatherType
=
.
unknown
public
var
isToday
:
Bool
{
DailyWeather
.
timeZoneCaledar
.
timeZone
=
timeZone
return
DailyWeather
.
timeZoneCaledar
.
isDateInToday
(
date
)
}
public
var
minTemp
:
Temperature
?
public
var
minTemp
:
Temperature
?
public
var
maxTemp
:
Temperature
?
public
var
maxTemp
:
Temperature
?
...
@@ -27,6 +35,7 @@ public struct DailyWeather: Equatable, Hashable {
...
@@ -27,6 +35,7 @@ public struct DailyWeather: Equatable, Hashable {
public
var
moonset
:
Date
?
public
var
moonset
:
Date
?
public
var
moonState
:
CelestialState
?
=
.
normal
public
var
moonState
:
CelestialState
?
=
.
normal
public
var
moonPhase
:
MoonPhase
?
=
.
unknown
public
var
moonPhase
:
MoonPhase
?
=
.
unknown
}
}
extension
DailyWeather
:
UpdatableModelObjectInTime
{
extension
DailyWeather
:
UpdatableModelObjectInTime
{
...
...
1Weather/UI/Helpers/DayControlsNavigationBar.swift
deleted
100644 → 0
View file @
94c6f356
//
// DayControlsNavigatoinBar.swift
// 1Weather
//
// Created by Dmitry Stepanets on 12.03.2021.
//
import
UIKit
class
DayControlsNavigationBar
:
UINavigationBar
{
private
var
currentProgress
:
CGFloat
=
0
private
var
savedProgress
:
CGFloat
=
0
private
var
defaultYOffset
:
CGFloat
=
0
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
isTranslucent
=
true
}
override
func
layoutSubviews
()
{
super
.
layoutSubviews
()
if
frame
.
origin
.
y
!=
0
&&
defaultYOffset
==
0
{
self
.
defaultYOffset
=
frame
.
origin
.
y
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
//Public
public
func
showControls
(
progressValue
:
CGFloat
)
{
var
progress
=
max
(
progressValue
,
0
)
progress
=
min
(
progress
,
1
)
self
.
currentProgress
=
progress
self
.
frame
.
origin
.
y
=
defaultYOffset
-
self
.
frame
.
height
*
progressValue
self
.
alpha
=
1
-
progressValue
}
public
func
saveProgress
()
{
savedProgress
=
currentProgress
}
public
func
restoreProgress
()
{
let
diff
=
(
savedProgress
-
currentProgress
)
*
100
let
numerOfSteps
=
Int
((
diff
/
60
*
0.35
*
100
)
.
rounded
(
.
up
))
for
step
in
0
..<
numerOfSteps
{
showControls
(
progressValue
:
CGFloat
(
step
)
/
CGFloat
(
numerOfSteps
))
}
// currentProgress = savedProgress
// showControls(progressValue: currentProgress)
// savedProgress = 0
}
}
1Weather/UI/Helpers/DayControlsNavigatoinController.swift
deleted
100644 → 0
View file @
94c6f356
//
// DayControlsNavigatoinController.swift
// 1Weather
//
// Created by Dmitry Stepanets on 15.03.2021.
//
import
UIKit
class
DayControlsNavigatoinController
:
UINavigationController
{
private
var
dayControllsNavBar
:
DayControlsNavigationBar
?
{
return
self
.
navigationBar
as?
DayControlsNavigationBar
}
init
()
{
super
.
init
(
navigationBarClass
:
DayControlsNavigationBar
.
self
,
toolbarClass
:
nil
)
delegate
=
self
}
required
init
?(
coder
aDecoder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
}
override
func
popViewController
(
animated
:
Bool
)
->
UIViewController
?
{
let
popViewController
=
super
.
popViewController
(
animated
:
animated
)
dayControllsNavBar
?
.
restoreProgress
()
return
popViewController
}
}
extension
DayControlsNavigatoinController
:
UINavigationControllerDelegate
{
func
navigationController
(
_
navigationController
:
UINavigationController
,
didShow
viewController
:
UIViewController
,
animated
:
Bool
)
{
// if viewController === viewControllers.first {
// self.dayControllsNavBar?.restoreProgress()
// }
}
func
navigationController
(
_
navigationController
:
UINavigationController
,
willShow
viewController
:
UIViewController
,
animated
:
Bool
)
{
if
viewController
!=
self
.
viewControllers
.
first
{
self
.
dayControllsNavBar
?
.
saveProgress
()
self
.
dayControllsNavBar
?
.
showControls
(
progressValue
:
0
)
}
}
}
1Weather/UI/Helpers/ForecastTimePeriod/ForecastTimePeriodView.swift
View file @
445be99f
...
@@ -43,9 +43,14 @@ class ForecastTimePeriodView: UIView {
...
@@ -43,9 +43,14 @@ class ForecastTimePeriodView: UIView {
}
}
//Public
//Public
public
func
set
(
location
:
Location
)
{
public
func
set
(
daily
:[
DailyWeather
]?
=
nil
,
hourly
:[
HourlyWeather
]?
=
nil
)
{
self
.
daily
=
location
.
daily
if
let
inputDaily
=
daily
{
self
.
hourly
=
location
.
hourly
self
.
daily
=
inputDaily
}
if
let
inputHourly
=
hourly
{
self
.
hourly
=
inputHourly
}
}
}
public
func
set
(
timePeriod
:
TimePeriod
,
buttonType
:
PeriodButtonProtocol
.
Type
)
{
public
func
set
(
timePeriod
:
TimePeriod
,
buttonType
:
PeriodButtonProtocol
.
Type
)
{
...
...
1Weather/UI/View controllers/Forecast/Cells/ForecastCellFactory.swift
View file @
445be99f
...
@@ -9,6 +9,7 @@ import UIKit
...
@@ -9,6 +9,7 @@ import UIKit
private
enum
ForecastCellType
:
Int
,
CaseIterable
{
private
enum
ForecastCellType
:
Int
,
CaseIterable
{
case
forecastPeriod
=
0
case
forecastPeriod
=
0
case
forecastInfo
// case forecast
// case forecast
// case conditions
// case conditions
// case precipitation
// case precipitation
...
@@ -18,28 +19,37 @@ private enum ForecastCellType:Int, CaseIterable {
...
@@ -18,28 +19,37 @@ private enum ForecastCellType:Int, CaseIterable {
}
}
class
ForecastCellFactory
{
class
ForecastCellFactory
{
public
var
onGetLocation
:(()
->
Location
?)?
public
var
forecastPeriodCellFrame
:
CGRect
=
.
zero
public
var
numberOfRows
:
Int
{
public
var
numberOfRows
:
Int
{
return
ForecastCellType
.
allCases
.
count
return
ForecastCellType
.
allCases
.
count
}
}
public
func
registerCells
(
on
tableView
:
UITableView
)
{
public
func
registerCells
(
on
tableView
:
UITableView
)
{
registerCell
(
type
:
ForecastTimePeriodCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastTimePeriodCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
ForecastInfoCell
.
self
,
tableView
:
tableView
)
}
}
public
func
cellFromTableView
(
tableView
:
UITableView
,
indexPath
:
IndexPath
)
->
UITableViewCell
{
public
func
cellFromTableView
(
tableView
:
UITableView
,
indexPath
:
IndexPath
,
viewModel
:
ForecastViewModel
)
->
UITableViewCell
{
guard
let
cellType
=
ForecastCellType
(
rawValue
:
indexPath
.
row
)
else
{
guard
let
cellType
=
ForecastCellType
(
rawValue
:
indexPath
.
row
)
else
{
return
UITableViewCell
()
return
UITableViewCell
()
}
}
guard
let
loc
=
self
.
onGetLocation
?()
else
{
return
UITableViewCell
()
}
switch
cellType
{
switch
cellType
{
case
.
forecastPeriod
:
case
.
forecastPeriod
:
let
cell
=
dequeueReusableCell
(
type
:
ForecastTimePeriodCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
let
cell
=
dequeueReusableCell
(
type
:
ForecastTimePeriodCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
cell
.
configure
(
with
:
loc
)
forecastPeriodCellFrame
=
cell
.
frame
if
let
daily
=
viewModel
.
location
?
.
daily
,
let
hourly
=
viewModel
.
location
?
.
hourly
{
cell
.
configure
(
daily
:
daily
,
hourly
:
hourly
)
}
return
cell
case
.
forecastInfo
:
let
cell
=
dequeueReusableCell
(
type
:
ForecastInfoCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
if
let
location
=
viewModel
.
location
,
let
today
=
(
location
.
daily
.
first
{
$0
.
isToday
})
{
cell
.
configure
(
dailyWeather
:
today
)
}
return
cell
return
cell
}
}
}
}
...
...
1Weather/UI/View controllers/Forecast/Cells/ForecastInfoCell.swift
0 → 100644
View file @
445be99f
//
// ForecastInfoCell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 17.03.2021.
//
import
UIKit
class
ForecastInfoCell
:
UITableViewCell
{
//Private
private
let
topContainer
=
UIView
()
private
let
tempLabel
=
UILabel
()
private
let
weatherTypeLabel
=
UILabel
()
private
let
weatherDescriptionLabel
=
UILabel
()
private
let
weatherTypeImageView
=
UIImageView
()
private
let
conditionsStackView
=
UIStackView
()
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
prepareCell
()
prepareTopContainer
()
prepareWeatherViews
()
prepareConditionsStackView
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
public
func
configure
(
dailyWeather
:
DailyWeather
)
{
weatherTypeImageView
.
image
=
dailyWeather
.
type
.
image
(
isDay
:
true
)
let
maxTemp
=
dailyWeather
.
maxTemp
?
.
shortString
??
"--"
let
minTemp
=
dailyWeather
.
minTemp
?
.
shortString
??
"--"
tempLabel
.
text
=
"
\(
maxTemp
)
/
\(
minTemp
)
"
weatherTypeLabel
.
text
=
dailyWeather
.
type
.
localized
(
isDay
:
true
)
weatherDescriptionLabel
.
text
=
"Feels like -- - Due to high humidity"
}
}
//MARK:- Prepare
private
extension
ForecastInfoCell
{
func
prepareCell
()
{
selectionStyle
=
.
none
contentView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
}
func
prepareTopContainer
()
{
topContainer
.
backgroundColor
=
.
white
topContainer
.
layer
.
cornerRadius
=
15
contentView
.
addSubview
(
topContainer
)
topContainer
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
16
)
make
.
top
.
equalToSuperview
()
.
inset
(
18
)
}
}
func
prepareWeatherViews
()
{
tempLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
44
)
tempLabel
.
textColor
=
ThemeManager
.
currentTheme
.
primaryTextColor
tempLabel
.
setContentHuggingPriority
(
.
fittingSizeLevel
,
for
:
.
vertical
)
topContainer
.
addSubview
(
tempLabel
)
weatherTypeLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
16
)
weatherTypeLabel
.
textColor
=
ThemeManager
.
currentTheme
.
primaryTextColor
topContainer
.
addSubview
(
weatherTypeLabel
)
weatherDescriptionLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
12
)
weatherDescriptionLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
topContainer
.
addSubview
(
weatherDescriptionLabel
)
weatherTypeImageView
.
contentMode
=
.
scaleAspectFit
weatherTypeImageView
.
clipsToBounds
=
true
topContainer
.
addSubview
(
weatherTypeImageView
)
//Constraints
tempLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalToSuperview
()
.
inset
(
25
)
make
.
left
.
equalToSuperview
()
.
inset
(
18
)
}
weatherTypeLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
.
inset
(
18
)
make
.
top
.
equalTo
(
tempLabel
.
snp
.
bottom
)
.
offset
(
10
)
}
weatherDescriptionLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
.
inset
(
18
)
make
.
top
.
equalTo
(
weatherTypeLabel
.
snp
.
bottom
)
.
offset
(
5
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
27
)
}
weatherTypeImageView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
width
.
height
.
equalTo
(
90
)
make
.
top
.
equalToSuperview
()
.
inset
(
30
)
make
.
right
.
equalToSuperview
()
.
inset
(
28
)
}
}
func
prepareConditionsStackView
()
{
contentView
.
addSubview
(
conditionsStackView
)
conditionsStackView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalTo
(
topContainer
.
snp
.
bottom
)
.
offset
(
15
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
15
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
18
)
}
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastTimePeriodCell.swift
View file @
445be99f
...
@@ -32,8 +32,8 @@ class ForecastTimePeriodCell: UITableViewCell {
...
@@ -32,8 +32,8 @@ class ForecastTimePeriodCell: UITableViewCell {
}
}
//Public
//Public
public
func
configure
(
with
location
:
Location
)
{
public
func
configure
(
daily
:[
DailyWeather
],
hourly
:[
HourlyWeather
]
)
{
self
.
forecastTimePeriodView
.
set
(
location
:
location
)
self
.
forecastTimePeriodView
.
set
(
daily
:
daily
,
hourly
:
hourly
)
if
graphIsDrawn
==
false
{
if
graphIsDrawn
==
false
{
self
.
handleSegmentDidChange
()
self
.
handleSegmentDidChange
()
...
...
1Weather/UI/View controllers/Forecast/DaysControlView.swift
0 → 100644
View file @
445be99f
//
// DaysControlView.swift
// 1Weather
//
// Created by Dmitry Stepanets on 17.03.2021.
//
import
UIKit
class
DaysControlView
:
UIView
{
//Private
private
let
scrollView
=
UIScrollView
()
private
let
stackView
=
UIStackView
()
private
let
gradientView
=
GradientView
(
startColor
:
UIColor
(
hex
:
0xffffff
)
.
withAlphaComponent
(
0
),
endColor
:
UIColor
(
hex
:
0xdaddec
),
opacity
:
0.5
)
private
var
statusBarHeight
:
CGFloat
{
var
statusBarHeight
:
CGFloat
=
0
if
#available(iOS 13.0, *)
{
let
window
=
UIApplication
.
shared
.
windows
.
filter
{
$0
.
isKeyWindow
}
.
first
statusBarHeight
=
window
?
.
windowScene
?
.
statusBarManager
?
.
statusBarFrame
.
height
??
0
}
else
{
statusBarHeight
=
UIApplication
.
shared
.
statusBarFrame
.
height
}
return
statusBarHeight
}
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
prepareView
()
prepareScrollView
()
prepareStackView
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
public
func
configure
(
dailyWeather
:
[
DailyWeather
])
{
stackView
.
arrangedSubviews
.
forEach
{
stackView
.
removeArrangedSubview
(
$0
)
$0
.
removeFromSuperview
()
}
for
index
in
0
..<
dailyWeather
.
count
{
let
button
=
DayControlButton
()
button
.
addTarget
(
self
,
action
:
#selector(
handleDayButton(button:)
)
,
for
:
.
touchUpInside
)
button
.
configure
(
dailyWeather
:
dailyWeather
[
index
])
button
.
isSelected
=
index
==
0
stackView
.
addArrangedSubview
(
button
)
}
stackView
.
layoutIfNeeded
()
}
@objc
private
func
handleDayButton
(
button
:
DayControlButton
)
{
guard
let
buttons
=
stackView
.
arrangedSubviews
as?
[
DayControlButton
]
else
{
return
}
buttons
.
forEach
{
$0
.
isSelected
=
$0
===
button
}
}
}
//MARK:- Prepare
private
extension
DaysControlView
{
func
prepareView
()
{
self
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
insertSubview
(
gradientView
,
at
:
0
)
gradientView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
edges
.
equalToSuperview
()
}
}
func
prepareScrollView
()
{
scrollView
.
showsVerticalScrollIndicator
=
false
scrollView
.
showsHorizontalScrollIndicator
=
false
addSubview
(
scrollView
)
scrollView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalToSuperview
()
.
inset
(
statusBarHeight
+
22
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
.
inset
(
18
)
make
.
height
.
greaterThanOrEqualTo
(
50
)
}
}
func
prepareStackView
()
{
stackView
.
axis
=
.
horizontal
stackView
.
distribution
=
.
equalSpacing
stackView
.
alignment
=
.
center
stackView
.
spacing
=
10
stackView
.
clipsToBounds
=
false
stackView
.
isLayoutMarginsRelativeArrangement
=
true
stackView
.
layoutMargins
=
.
init
(
top
:
0
,
left
:
10
,
bottom
:
0
,
right
:
10
)
scrollView
.
addSubview
(
stackView
)
stackView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
edges
.
height
.
equalToSuperview
()
}
}
}
//MARK:- Button
private
class
DayControlButton
:
UIControl
{
//Private
private
let
dayLabel
=
UILabel
()
private
static
var
dateFormatter
:
DateFormatter
=
{
let
fmt
=
DateFormatter
()
fmt
.
dateFormat
=
"d, E"
return
fmt
}()
private
static
var
calendar
:
Calendar
=
{
return
Calendar
(
identifier
:
Calendar
.
current
.
identifier
)
}()
//Public
var
index
:
Int
=
-
1
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
//Button
self
.
backgroundColor
=
UIColor
.
white
.
withAlphaComponent
(
0.5
)
self
.
layer
.
cornerRadius
=
8
self
.
layer
.
borderWidth
=
1
self
.
layer
.
borderColor
=
UIColor
(
hex
:
0xdcdcdc
)
.
cgColor
//Label
dayLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
14
)
dayLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
dayLabel
.
textAlignment
=
.
center
addSubview
(
dayLabel
)
self
.
snp
.
makeConstraints
{
(
make
)
in
make
.
height
.
equalTo
(
50
)
make
.
width
.
equalTo
(
70
)
}
dayLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
centerY
.
equalToSuperview
()
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
2
)
}
}
override
var
isSelected
:
Bool
{
didSet
{
if
isSelected
{
self
.
backgroundColor
=
UIColor
(
hex
:
0x1f67f3
)
self
.
dayLabel
.
textColor
=
UIColor
.
white
self
.
dayLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
16
)
}
else
{
self
.
backgroundColor
=
UIColor
.
white
.
withAlphaComponent
(
0.5
)
self
.
dayLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
self
.
dayLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
14
)
}
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
func
configure
(
dailyWeather
:
DailyWeather
)
{
DayControlButton
.
dateFormatter
.
timeZone
=
dailyWeather
.
timeZone
DayControlButton
.
calendar
.
timeZone
=
dailyWeather
.
timeZone
if
DayControlButton
.
calendar
.
isDateInToday
(
dailyWeather
.
date
)
{
dayLabel
.
text
=
"day.today"
.
localized
()
}
else
{
dayLabel
.
text
=
DayControlButton
.
dateFormatter
.
string
(
from
:
dailyWeather
.
date
)
}
}
}
1Weather/UI/View controllers/Forecast/ForecastViewController.swift
View file @
445be99f
...
@@ -10,7 +10,7 @@ import UIKit
...
@@ -10,7 +10,7 @@ import UIKit
class
ForecastViewController
:
UIViewController
{
class
ForecastViewController
:
UIViewController
{
//Private
//Private
private
let
cityButton
=
NavigationCityButton
()
private
let
cityButton
=
NavigationCityButton
()
private
let
days
StackView
=
UIStack
View
()
private
let
days
ControlView
=
DaysControl
View
()
private
let
tableView
=
UITableView
()
private
let
tableView
=
UITableView
()
private
let
viewModel
:
ForecastViewModel
private
let
viewModel
:
ForecastViewModel
private
var
localizationObserver
:
Any
?
private
var
localizationObserver
:
Any
?
...
@@ -32,7 +32,7 @@ class ForecastViewController: UIViewController {
...
@@ -32,7 +32,7 @@ class ForecastViewController: UIViewController {
prepareViewController
()
prepareViewController
()
prepareNavigationBar
()
prepareNavigationBar
()
prepareTableView
()
prepareTableView
()
prepareDay
sStack
View
()
prepareDay
Controls
View
()
refreshCityButton
()
refreshCityButton
()
}
}
...
@@ -82,15 +82,11 @@ private extension ForecastViewController {
...
@@ -82,15 +82,11 @@ private extension ForecastViewController {
self
.
navigationItem
.
rightBarButtonItem
=
notificationBarButton
self
.
navigationItem
.
rightBarButtonItem
=
notificationBarButton
}
}
func
prepareDaysStackView
()
{
func
prepareDayControlsView
()
{
let
dView
=
UIView
()
daysControlView
.
alpha
=
0
dView
.
backgroundColor
=
.
red
view
.
addSubview
(
daysControlView
)
view
.
addSubview
(
dView
)
daysControlView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
left
.
right
.
equalToSuperview
()
dView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalTo
(
50
)
make
.
top
.
equalTo
(
self
.
view
.
safeAreaLayoutGuide
.
snp
.
top
)
}
}
}
}
...
@@ -114,7 +110,36 @@ private extension ForecastViewController {
...
@@ -114,7 +110,36 @@ private extension ForecastViewController {
//MARK:- UITableView Delegate
//MARK:- UITableView Delegate
extension
ForecastViewController
:
UITableViewDelegate
{
extension
ForecastViewController
:
UITableViewDelegate
{
func
scrollViewDidScroll
(
_
scrollView
:
UIScrollView
)
{
let
cellFrame
=
viewModel
.
forecastCellFactory
.
forecastPeriodCellFrame
guard
let
navVC
=
self
.
navigationController
,
cellFrame
.
origin
.
y
>
0
,
viewModel
.
location
?
.
daily
.
isEmpty
==
false
else
{
return
}
let
startPointY
=
cellFrame
.
origin
.
y
+
cellFrame
.
height
-
self
.
daysControlView
.
frame
.
height
if
scrollView
.
contentOffset
.
y
>=
startPointY
{
if
!
navVC
.
isNavigationBarHidden
{
navVC
.
setNavigationBarHidden
(
true
,
animated
:
true
)
UIView
.
animate
(
withDuration
:
0.35
)
{
self
.
daysControlView
.
alpha
=
1
}
}
}
else
{
if
navVC
.
isNavigationBarHidden
{
navVC
.
setNavigationBarHidden
(
false
,
animated
:
true
)
UIView
.
animate
(
withDuration
:
0.35
)
{
self
.
daysControlView
.
alpha
=
0
}
}
}
}
}
}
//MARK:- UITableView DataSource
//MARK:- UITableView DataSource
...
@@ -124,7 +149,9 @@ extension ForecastViewController: UITableViewDataSource {
...
@@ -124,7 +149,9 @@ extension ForecastViewController: UITableViewDataSource {
}
}
func
tableView
(
_
tableView
:
UITableView
,
cellForRowAt
indexPath
:
IndexPath
)
->
UITableViewCell
{
func
tableView
(
_
tableView
:
UITableView
,
cellForRowAt
indexPath
:
IndexPath
)
->
UITableViewCell
{
return
viewModel
.
forecastCellFactory
.
cellFromTableView
(
tableView
:
tableView
,
indexPath
:
indexPath
)
return
viewModel
.
forecastCellFactory
.
cellFromTableView
(
tableView
:
tableView
,
indexPath
:
indexPath
,
viewModel
:
viewModel
)
}
}
}
}
...
@@ -133,5 +160,12 @@ extension ForecastViewController: ViewModelDelegate {
...
@@ -133,5 +160,12 @@ extension ForecastViewController: ViewModelDelegate {
func
viewModelDidChange
<
P
>
(
model
:
P
)
where
P
:
ViewModelProtocol
{
func
viewModelDidChange
<
P
>
(
model
:
P
)
where
P
:
ViewModelProtocol
{
refreshCityButton
()
refreshCityButton
()
tableView
.
reloadData
()
tableView
.
reloadData
()
if
let
dailyWeather
=
viewModel
.
location
?
.
daily
{
daysControlView
.
configure
(
dailyWeather
:
dailyWeather
)
}
else
{
daysControlView
.
alpha
=
0
}
}
}
}
}
1Weather/UI/View controllers/Today/Cells/CityDayTimesCell/CityDayTimesCell.swift
View file @
445be99f
...
@@ -33,8 +33,10 @@ class CityDayTimesCell: UITableViewCell {
...
@@ -33,8 +33,10 @@ class CityDayTimesCell: UITableViewCell {
public
func
configure
(
with
location
:
Location
)
{
public
func
configure
(
with
location
:
Location
)
{
for
subview
in
stackView
.
subviews
{
for
subview
in
stackView
.
subviews
{
stackView
.
removeArrangedSubview
(
subview
)
subview
.
removeFromSuperview
()
subview
.
removeFromSuperview
()
}
}
let
maxNumberOfItems
=
4
let
maxNumberOfItems
=
4
var
currentlyShowing
=
0
var
currentlyShowing
=
0
var
i
=
0
var
i
=
0
...
@@ -43,7 +45,7 @@ class CityDayTimesCell: UITableViewCell {
...
@@ -43,7 +45,7 @@ class CityDayTimesCell: UITableViewCell {
i
+=
1
i
+=
1
if
dayTimeWeather
.
date
>=
Date
()
{
if
dayTimeWeather
.
date
>=
Date
()
{
let
view
=
DayTimeView
(
dayTimeWeather
:
dayTimeWeather
)
let
view
=
DayTimeView
(
dayTimeWeather
:
dayTimeWeather
,
withSeparator
:
currentlyShowing
!=
maxNumberOfItems
)
stackView
.
addArrangedSubview
(
view
)
stackView
.
addArrangedSubview
(
view
)
currentlyShowing
+=
1
currentlyShowing
+=
1
}
}
...
...
1Weather/UI/View controllers/Today/Cells/CityDayTimesCell/DayTimeView.swift
View file @
445be99f
...
@@ -53,6 +53,9 @@ private extension DayTimeView {
...
@@ -53,6 +53,9 @@ private extension DayTimeView {
tempLabel
.
text
=
"--"
tempLabel
.
text
=
"--"
addSubview
(
tempLabel
)
addSubview
(
tempLabel
)
dayTimeConditionLabel
.
numberOfLines
=
2
dayTimeConditionLabel
.
lineBreakMode
=
.
byWordWrapping
dayTimeConditionLabel
.
textAlignment
=
.
center
dayTimeConditionLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
14
)
dayTimeConditionLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
14
)
dayTimeConditionLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
dayTimeConditionLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
dayTimeConditionLabel
.
text
=
"--"
dayTimeConditionLabel
.
text
=
"--"
...
@@ -77,7 +80,7 @@ private extension DayTimeView {
...
@@ -77,7 +80,7 @@ private extension DayTimeView {
}
}
dayTimeConditionLabel
.
snp
.
makeConstraints
{
(
make
)
in
dayTimeConditionLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
centerX
.
equalToSuperview
(
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
2
)
make
.
top
.
equalTo
(
tempLabel
.
snp
.
bottom
)
.
offset
(
14
)
make
.
top
.
equalTo
(
tempLabel
.
snp
.
bottom
)
.
offset
(
14
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
24
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
24
)
}
}
...
...
1Weather/UI/View controllers/Today/Cells/CityForecastTimePeriodCell.swift
View file @
445be99f
...
@@ -33,7 +33,7 @@ class CityForecastTimePeriodCell: UITableViewCell {
...
@@ -33,7 +33,7 @@ class CityForecastTimePeriodCell: UITableViewCell {
//Public
//Public
public
func
configure
(
with
location
:
Location
)
{
public
func
configure
(
with
location
:
Location
)
{
self
.
forecastTimePeriodView
.
set
(
location
:
location
)
self
.
forecastTimePeriodView
.
set
(
daily
:
location
.
daily
,
hourly
:
location
.
hourly
)
if
graphIsDrawn
==
false
{
if
graphIsDrawn
==
false
{
self
.
handleSegmentDidChange
()
self
.
handleSegmentDidChange
()
...
...
1Weather/UI/View controllers/Today/Cells/TodayCellFactory.swift
View file @
445be99f
...
@@ -20,7 +20,6 @@ private enum TodayCellType:Int, CaseIterable {
...
@@ -20,7 +20,6 @@ private enum TodayCellType:Int, CaseIterable {
class
TodayCellFactory
{
class
TodayCellFactory
{
public
var
onGetLocation
:(()
->
Location
?)?
public
var
onGetLocation
:(()
->
Location
?)?
public
var
forecastPeriodCellFrame
:
CGRect
=
.
zero
public
var
numberOfRows
:
Int
{
public
var
numberOfRows
:
Int
{
return
TodayCellType
.
allCases
.
count
return
TodayCellType
.
allCases
.
count
}
}
...
@@ -60,7 +59,6 @@ class TodayCellFactory {
...
@@ -60,7 +59,6 @@ class TodayCellFactory {
return
cell
return
cell
case
.
forecastPeriod
:
case
.
forecastPeriod
:
let
cell
=
dequeueReusableCell
(
type
:
CityForecastTimePeriodCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
let
cell
=
dequeueReusableCell
(
type
:
CityForecastTimePeriodCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
forecastPeriodCellFrame
=
cell
.
frame
cell
.
configure
(
with
:
loc
)
cell
.
configure
(
with
:
loc
)
return
cell
return
cell
case
.
precipitation
:
case
.
precipitation
:
...
@@ -84,9 +82,6 @@ class TodayCellFactory {
...
@@ -84,9 +82,6 @@ class TodayCellFactory {
public
func
willDisplay
(
cell
:
UITableViewCell
)
{
public
func
willDisplay
(
cell
:
UITableViewCell
)
{
switch
cell
{
switch
cell
{
case
let
timePeriodCell
as
CityForecastTimePeriodCell
:
break
// timePeriodCell.drawGraphIfNeeded()
case
let
sunCell
as
CitySunCell
:
case
let
sunCell
as
CitySunCell
:
sunCell
.
updateSunPosition
()
sunCell
.
updateSunPosition
()
case
let
moonCell
as
CityMoonCell
:
case
let
moonCell
as
CityMoonCell
:
...
...
1Weather/UI/View controllers/Today/TodayViewController.swift
View file @
445be99f
...
@@ -13,18 +13,7 @@ class TodayViewController: UIViewController {
...
@@ -13,18 +13,7 @@ class TodayViewController: UIViewController {
private
let
cityButton
=
NavigationCityButton
()
private
let
cityButton
=
NavigationCityButton
()
private
let
viewModel
:
TodayViewModel
private
let
viewModel
:
TodayViewModel
private
let
tableView
=
UITableView
()
private
let
tableView
=
UITableView
()
private
var
dayControlsNavigationBar
:
DayControlsNavigationBar
?
private
var
localizationObserver
:
Any
?
private
var
localizationObserver
:
Any
?
private
func
getStatusBarHeight
()
->
CGFloat
{
var
statusBarHeight
:
CGFloat
=
0
if
#available(iOS 13.0, *)
{
let
window
=
UIApplication
.
shared
.
windows
.
filter
{
$0
.
isKeyWindow
}
.
first
statusBarHeight
=
window
?
.
windowScene
?
.
statusBarManager
?
.
statusBarFrame
.
height
??
0
}
else
{
statusBarHeight
=
UIApplication
.
shared
.
statusBarFrame
.
height
}
return
statusBarHeight
}
deinit
{
deinit
{
if
let
observer
=
localizationObserver
{
if
let
observer
=
localizationObserver
{
...
@@ -48,16 +37,6 @@ class TodayViewController: UIViewController {
...
@@ -48,16 +37,6 @@ class TodayViewController: UIViewController {
prepareNavigationBar
()
prepareNavigationBar
()
prepareTableView
()
prepareTableView
()
let
dView
=
UIView
()
dView
.
backgroundColor
=
.
red
view
.
addSubview
(
dView
)
dView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalTo
(
50
)
make
.
top
.
equalToSuperview
()
.
inset
(
self
.
getStatusBarHeight
())
}
viewModel
.
delegate
=
self
viewModel
.
delegate
=
self
viewModel
.
updateWeather
()
viewModel
.
updateWeather
()
}
}
...
@@ -89,8 +68,6 @@ private extension TodayViewController {
...
@@ -89,8 +68,6 @@ private extension TodayViewController {
}
}
func
prepareNavigationBar
()
{
func
prepareNavigationBar
()
{
self
.
dayControlsNavigationBar
=
self
.
navigationController
?
.
navigationBar
as?
DayControlsNavigationBar
//City button
//City button
cityButton
.
isHidden
=
true
cityButton
.
isHidden
=
true
cityButton
.
addTarget
(
self
,
action
:
#selector(
handleCityButton
)
,
for
:
.
touchUpInside
)
cityButton
.
addTarget
(
self
,
action
:
#selector(
handleCityButton
)
,
for
:
.
touchUpInside
)
...
@@ -149,24 +126,6 @@ extension TodayViewController: UITableViewDelegate {
...
@@ -149,24 +126,6 @@ extension TodayViewController: UITableViewDelegate {
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
}
func
scrollViewDidScroll
(
_
scrollView
:
UIScrollView
)
{
let
cellFrame
=
viewModel
.
todayCellFactory
.
forecastPeriodCellFrame
guard
cellFrame
.
origin
.
y
>
0
else
{
return
}
let
controlsHeight
:
CGFloat
=
50
let
startPointY
=
cellFrame
.
origin
.
y
+
cellFrame
.
height
-
controlsHeight
if
scrollView
.
contentOffset
.
y
>=
startPointY
{
let
cellOffset
=
scrollView
.
contentOffset
.
y
-
startPointY
let
progress
=
cellOffset
/
controlsHeight
dayControlsNavigationBar
?
.
showControls
(
progressValue
:
progress
)
print
(
"progress:
\(
progress
)
"
)
}
else
{
dayControlsNavigationBar
?
.
showControls
(
progressValue
:
0
)
}
}
func
tableView
(
_
tableView
:
UITableView
,
willDisplay
cell
:
UITableViewCell
,
forRowAt
indexPath
:
IndexPath
)
{
func
tableView
(
_
tableView
:
UITableView
,
willDisplay
cell
:
UITableViewCell
,
forRowAt
indexPath
:
IndexPath
)
{
viewModel
.
todayCellFactory
.
willDisplay
(
cell
:
cell
)
viewModel
.
todayCellFactory
.
willDisplay
(
cell
:
cell
)
}
}
...
...
1Weather/ViewModels/ForecastViewModel.swift
View file @
445be99f
...
@@ -23,11 +23,6 @@ class ForecastViewModel: ViewModelProtocol {
...
@@ -23,11 +23,6 @@ class ForecastViewModel: ViewModelProtocol {
public
init
(
locationManager
:
LocationManager
)
{
public
init
(
locationManager
:
LocationManager
)
{
self
.
locationManager
=
locationManager
self
.
locationManager
=
locationManager
locationManager
.
add
(
delegate
:
self
)
locationManager
.
add
(
delegate
:
self
)
//Setup factory callback
forecastCellFactory
.
onGetLocation
=
{[
weak
self
]
in
return
self
?
.
location
}
}
}
public
func
updateWeather
()
{
public
func
updateWeather
()
{
...
...
Pods/Pods.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
445be99f
...
@@ -40,19 +40,19 @@
...
@@ -40,19 +40,19 @@
<
k
e
y
>
isShown
<
/k
e
y
>
<
k
e
y
>
isShown
<
/k
e
y
>
<
fa
ls
e
/
>
<
fa
ls
e
/
>
<
k
e
y
>
orderHint
<
/k
e
y
>
<
k
e
y
>
orderHint
<
/k
e
y
>
<
int
e
g
e
r
>
1
<
/int
e
g
e
r
>
<
int
e
g
e
r
>
2
<
/int
e
g
e
r
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
k
e
y
>
SnapKit.xcscheme
<
/k
e
y
>
<
k
e
y
>
SnapKit.xcscheme
<
/k
e
y
>
<
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
isShown
<
/k
e
y
>
<
k
e
y
>
isShown
<
/k
e
y
>
<
fa
ls
e
/
>
<
fa
ls
e
/
>
<
k
e
y
>
orderHint
<
/k
e
y
>
<
k
e
y
>
orderHint
<
/k
e
y
>
<
int
e
g
e
r
>
2
<
/int
e
g
e
r
>
<
int
e
g
e
r
>
3
<
/int
e
g
e
r
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
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
>
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
>
<
/
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