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
2d426c1d
Commit
2d426c1d
authored
Mar 18, 2021
by
Dmitriy Stepanets
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Working on action on forecast selection button
parent
445be99f
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
616 additions
and
126 deletions
+616
-126
1Weather.xcodeproj/project.pbxproj
+41
-5
1Weather.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
+1
-1
1Weather.xcworkspace/xcuserdata/dstepanets.xcuserdatad/UserInterfaceState.xcuserstate
+0
-0
1Weather/Extensions/Calendar+TimeZone.swift
+16
-0
1Weather/Extensions/UIStackView+RemoveAll.swift
+17
-0
1Weather/Model/HelperTypes.swift
+48
-0
1Weather/Model/ModelObjects/DailyWeather.swift
+1
-6
1Weather/Model/ModelObjects/Location.swift
+1
-2
1Weather/UI/Helpers/ForecastTimePeriod/ForecastDetailPeriodButton.swift
+2
-1
1Weather/UI/Helpers/ForecastTimePeriod/ForecastPeriodButton.swift
+1
-1
1Weather/UI/Helpers/ForecastTimePeriod/ForecastTimePeriodView.swift
+24
-19
1Weather/UI/View controllers/Forecast/Cells/ForecastCellFactory.swift
+49
-8
1Weather/UI/View controllers/Forecast/Cells/ForecastInfoCell/ForecastConditionView.swift
+89
-0
1Weather/UI/View controllers/Forecast/Cells/ForecastInfoCell/ForecastInfoCell.swift
+30
-2
1Weather/UI/View controllers/Forecast/Cells/ForecastPrecipitationCell/DayTimePrecipitationView.swift
+85
-0
1Weather/UI/View controllers/Forecast/Cells/ForecastPrecipitationCell/ForecastPrecipitationCell.swift
+95
-0
1Weather/UI/View controllers/Forecast/Cells/ForecastPrecipitationCell/ForecastPrecipitationView.swift
+32
-0
1Weather/UI/View controllers/Forecast/Cells/ForecastTimePeriodCell.swift
+15
-0
1Weather/UI/View controllers/Forecast/DaysControlView.swift
+1
-5
1Weather/UI/View controllers/Forecast/ForecastViewController.swift
+29
-9
1Weather/UI/View controllers/Today/Cells/CityConditions/CityConditionButton.swift
+10
-58
1Weather/UI/View controllers/Today/Cells/CityConditions/CityConditionsCell.swift
+1
-1
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipButton.swift
+2
-2
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipitationView.swift
+3
-3
1Weather/ViewModels/ForecastViewModel.swift
+22
-2
Pods/Pods.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
+1
-1
No files found.
1Weather.xcodeproj/project.pbxproj
View file @
2d426c1d
...
@@ -20,6 +20,11 @@
...
@@ -20,6 +20,11 @@
CD17C60225D15C8500EE884E
/* CoordinatorProtocol.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD17C60125D15C8500EE884E
/* CoordinatorProtocol.swift */
;
};
CD17C60225D15C8500EE884E
/* CoordinatorProtocol.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD17C60125D15C8500EE884E
/* CoordinatorProtocol.swift */
;
};
CD1DDD30260218AE00AC62B2
/* DaysControlView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD1DDD2F260218AE00AC62B2
/* DaysControlView.swift */
;
};
CD1DDD30260218AE00AC62B2
/* DaysControlView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD1DDD2F260218AE00AC62B2
/* DaysControlView.swift */
;
};
CD1DDD332602305200AC62B2
/* ForecastInfoCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD1DDD322602305200AC62B2
/* ForecastInfoCell.swift */
;
};
CD1DDD332602305200AC62B2
/* ForecastInfoCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD1DDD322602305200AC62B2
/* ForecastInfoCell.swift */
;
};
CD251ED82603633800ED7A65
/* ForecastPrecipitationCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD251ED72603633800ED7A65
/* ForecastPrecipitationCell.swift */
;
};
CD251EDC26036E5400ED7A65
/* DayTimePrecipitationView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD251EDB26036E5400ED7A65
/* DayTimePrecipitationView.swift */
;
};
CD35DFCC260341B000F2138F
/* Calendar+TimeZone.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD35DFCB260341B000F2138F
/* Calendar+TimeZone.swift */
;
};
CD35DFD0260344A500F2138F
/* ForecastConditionView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD35DFCF260344A500F2138F
/* ForecastConditionView.swift */
;
};
CD35DFD426034BCD00F2138F
/* UIStackView+RemoveAll.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD35DFD326034BCD00F2138F
/* UIStackView+RemoveAll.swift */
;
};
CD39F2EE25DE858D009FE398
/* NotificationName+Localization.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD39F2ED25DE858D009FE398
/* NotificationName+Localization.swift */
;
};
CD39F2EE25DE858D009FE398
/* NotificationName+Localization.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD39F2ED25DE858D009FE398
/* NotificationName+Localization.swift */
;
};
CD39F2F225DE94C4009FE398
/* CitySunCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD39F2F125DE94C4009FE398
/* CitySunCell.swift */
;
};
CD39F2F225DE94C4009FE398
/* CitySunCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD39F2F125DE94C4009FE398
/* CitySunCell.swift */
;
};
CD39F2F525DE9571009FE398
/* ArrowButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD39F2F425DE9571009FE398
/* ArrowButton.swift */
;
};
CD39F2F525DE9571009FE398
/* ArrowButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD39F2F425DE9571009FE398
/* ArrowButton.swift */
;
};
...
@@ -44,7 +49,7 @@
...
@@ -44,7 +49,7 @@
CD86246525E66E8A0097F3FB
/* CityPrecipCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD86246425E66E8A0097F3FB
/* CityPrecipCell.swift */
;
};
CD86246525E66E8A0097F3FB
/* CityPrecipCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD86246425E66E8A0097F3FB
/* CityPrecipCell.swift */
;
};
CD86246925E672A20097F3FB
/* PrecipButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD86246825E672A20097F3FB
/* PrecipButton.swift */
;
};
CD86246925E672A20097F3FB
/* PrecipButton.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD86246825E672A20097F3FB
/* PrecipButton.swift */
;
};
CD86246C25E6826A0097F3FB
/* InnerShadowLayer.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD86246B25E6826A0097F3FB
/* InnerShadowLayer.swift */
;
};
CD86246C25E6826A0097F3FB
/* InnerShadowLayer.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD86246B25E6826A0097F3FB
/* InnerShadowLayer.swift */
;
};
CD86C22225F0DCCB00F38A16
/* Precip
View.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD86C22125F0DCCB00F38A16
/* Precip
View.swift */
;
};
CD86C22225F0DCCB00F38A16
/* Precip
itationView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD86C22125F0DCCB00F38A16
/* Precipitation
View.swift */
;
};
CD8E040D25F8F3D2001785B6
/* ForecastTimePeriodCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD8E040C25F8F3D2001785B6
/* ForecastTimePeriodCell.swift */
;
};
CD8E040D25F8F3D2001785B6
/* ForecastTimePeriodCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD8E040C25F8F3D2001785B6
/* ForecastTimePeriodCell.swift */
;
};
CD8E041225F8F775001785B6
/* ForecastViewModel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD8E041125F8F775001785B6
/* ForecastViewModel.swift */
;
};
CD8E041225F8F775001785B6
/* ForecastViewModel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD8E041125F8F775001785B6
/* ForecastViewModel.swift */
;
};
CD8E041625F8F91B001785B6
/* ForecastCellFactory.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD8E041525F8F91B001785B6
/* ForecastCellFactory.swift */
;
};
CD8E041625F8F91B001785B6
/* ForecastCellFactory.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CD8E041525F8F91B001785B6
/* ForecastCellFactory.swift */
;
};
...
@@ -111,6 +116,11 @@
...
@@ -111,6 +116,11 @@
CD17C60125D15C8500EE884E
/* CoordinatorProtocol.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CoordinatorProtocol.swift
;
sourceTree
=
"<group>"
;
};
CD17C60125D15C8500EE884E
/* CoordinatorProtocol.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CoordinatorProtocol.swift
;
sourceTree
=
"<group>"
;
};
CD1DDD2F260218AE00AC62B2
/* DaysControlView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
DaysControlView.swift
;
sourceTree
=
"<group>"
;
};
CD1DDD2F260218AE00AC62B2
/* DaysControlView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
DaysControlView.swift
;
sourceTree
=
"<group>"
;
};
CD1DDD322602305200AC62B2
/* ForecastInfoCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastInfoCell.swift
;
sourceTree
=
"<group>"
;
};
CD1DDD322602305200AC62B2
/* ForecastInfoCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastInfoCell.swift
;
sourceTree
=
"<group>"
;
};
CD251ED72603633800ED7A65
/* ForecastPrecipitationCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastPrecipitationCell.swift
;
sourceTree
=
"<group>"
;
};
CD251EDB26036E5400ED7A65
/* DayTimePrecipitationView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
DayTimePrecipitationView.swift
;
sourceTree
=
"<group>"
;
};
CD35DFCB260341B000F2138F
/* Calendar+TimeZone.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"Calendar+TimeZone.swift"
;
sourceTree
=
"<group>"
;
};
CD35DFCF260344A500F2138F
/* ForecastConditionView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastConditionView.swift
;
sourceTree
=
"<group>"
;
};
CD35DFD326034BCD00F2138F
/* UIStackView+RemoveAll.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"UIStackView+RemoveAll.swift"
;
sourceTree
=
"<group>"
;
};
CD39F2ED25DE858D009FE398
/* NotificationName+Localization.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"NotificationName+Localization.swift"
;
sourceTree
=
"<group>"
;
};
CD39F2ED25DE858D009FE398
/* NotificationName+Localization.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"NotificationName+Localization.swift"
;
sourceTree
=
"<group>"
;
};
CD39F2F125DE94C4009FE398
/* CitySunCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CitySunCell.swift
;
sourceTree
=
"<group>"
;
};
CD39F2F125DE94C4009FE398
/* CitySunCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CitySunCell.swift
;
sourceTree
=
"<group>"
;
};
CD39F2F425DE9571009FE398
/* ArrowButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ArrowButton.swift
;
sourceTree
=
"<group>"
;
};
CD39F2F425DE9571009FE398
/* ArrowButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ArrowButton.swift
;
sourceTree
=
"<group>"
;
};
...
@@ -135,7 +145,7 @@
...
@@ -135,7 +145,7 @@
CD86246425E66E8A0097F3FB
/* CityPrecipCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CityPrecipCell.swift
;
sourceTree
=
"<group>"
;
};
CD86246425E66E8A0097F3FB
/* CityPrecipCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CityPrecipCell.swift
;
sourceTree
=
"<group>"
;
};
CD86246825E672A20097F3FB
/* PrecipButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
PrecipButton.swift
;
sourceTree
=
"<group>"
;
};
CD86246825E672A20097F3FB
/* PrecipButton.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
PrecipButton.swift
;
sourceTree
=
"<group>"
;
};
CD86246B25E6826A0097F3FB
/* InnerShadowLayer.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
InnerShadowLayer.swift
;
sourceTree
=
"<group>"
;
};
CD86246B25E6826A0097F3FB
/* InnerShadowLayer.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
InnerShadowLayer.swift
;
sourceTree
=
"<group>"
;
};
CD86C22125F0DCCB00F38A16
/* Precip
View.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Precip
View.swift
;
sourceTree
=
"<group>"
;
};
CD86C22125F0DCCB00F38A16
/* Precip
itationView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Precipitation
View.swift
;
sourceTree
=
"<group>"
;
};
CD8E040C25F8F3D2001785B6
/* ForecastTimePeriodCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastTimePeriodCell.swift
;
sourceTree
=
"<group>"
;
};
CD8E040C25F8F3D2001785B6
/* ForecastTimePeriodCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastTimePeriodCell.swift
;
sourceTree
=
"<group>"
;
};
CD8E041125F8F775001785B6
/* ForecastViewModel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastViewModel.swift
;
sourceTree
=
"<group>"
;
};
CD8E041125F8F775001785B6
/* ForecastViewModel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastViewModel.swift
;
sourceTree
=
"<group>"
;
};
CD8E041525F8F91B001785B6
/* ForecastCellFactory.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastCellFactory.swift
;
sourceTree
=
"<group>"
;
};
CD8E041525F8F91B001785B6
/* ForecastCellFactory.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ForecastCellFactory.swift
;
sourceTree
=
"<group>"
;
};
...
@@ -266,6 +276,8 @@
...
@@ -266,6 +276,8 @@
CDE18DC925D165F100C80ED9
/* UITabBarController+Append.swift */
,
CDE18DC925D165F100C80ED9
/* UITabBarController+Append.swift */
,
CD39F2ED25DE858D009FE398
/* NotificationName+Localization.swift */
,
CD39F2ED25DE858D009FE398
/* NotificationName+Localization.swift */
,
CDA5542F25EFA13F00A2E08C
/* Measurement+String.swift */
,
CDA5542F25EFA13F00A2E08C
/* Measurement+String.swift */
,
CD35DFCB260341B000F2138F
/* Calendar+TimeZone.swift */
,
CD35DFD326034BCD00F2138F
/* UIStackView+RemoveAll.swift */
,
);
);
path
=
Extensions
;
path
=
Extensions
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
@@ -298,6 +310,24 @@
...
@@ -298,6 +310,24 @@
path
=
Coordinators
;
path
=
Coordinators
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
};
};
CD251EDA26036E2F00ED7A65
/* ForecastPrecipitationCell */
=
{
isa
=
PBXGroup
;
children
=
(
CD251ED72603633800ED7A65
/* ForecastPrecipitationCell.swift */
,
CD251EDB26036E5400ED7A65
/* DayTimePrecipitationView.swift */
,
);
path
=
ForecastPrecipitationCell
;
sourceTree
=
"<group>"
;
};
CD35DFCE2603448300F2138F
/* ForecastInfoCell */
=
{
isa
=
PBXGroup
;
children
=
(
CD1DDD322602305200AC62B2
/* ForecastInfoCell.swift */
,
CD35DFCF260344A500F2138F
/* ForecastConditionView.swift */
,
);
path
=
ForecastInfoCell
;
sourceTree
=
"<group>"
;
};
CD647D0025ED07AF0034578B
/* ViewModels */
=
{
CD647D0025ED07AF0034578B
/* ViewModels */
=
{
isa
=
PBXGroup
;
isa
=
PBXGroup
;
children
=
(
children
=
(
...
@@ -378,7 +408,7 @@
...
@@ -378,7 +408,7 @@
children
=
(
children
=
(
CD86246425E66E8A0097F3FB
/* CityPrecipCell.swift */
,
CD86246425E66E8A0097F3FB
/* CityPrecipCell.swift */
,
CD86246825E672A20097F3FB
/* PrecipButton.swift */
,
CD86246825E672A20097F3FB
/* PrecipButton.swift */
,
CD86C22125F0DCCB00F38A16
/* PrecipView.swift */
,
CD86C22125F0DCCB00F38A16
/* Precip
itation
View.swift */
,
);
);
path
=
CityPrecipCell
;
path
=
CityPrecipCell
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
@@ -386,9 +416,10 @@
...
@@ -386,9 +416,10 @@
CD8E040B25F8F39B001785B6
/* Cells */
=
{
CD8E040B25F8F39B001785B6
/* Cells */
=
{
isa
=
PBXGroup
;
isa
=
PBXGroup
;
children
=
(
children
=
(
CD35DFCE2603448300F2138F
/* ForecastInfoCell */
,
CD251EDA26036E2F00ED7A65
/* ForecastPrecipitationCell */
,
CD8E041525F8F91B001785B6
/* ForecastCellFactory.swift */
,
CD8E041525F8F91B001785B6
/* ForecastCellFactory.swift */
,
CD8E040C25F8F3D2001785B6
/* ForecastTimePeriodCell.swift */
,
CD8E040C25F8F3D2001785B6
/* ForecastTimePeriodCell.swift */
,
CD1DDD322602305200AC62B2
/* ForecastInfoCell.swift */
,
);
);
path
=
Cells
;
path
=
Cells
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
@@ -671,6 +702,7 @@
...
@@ -671,6 +702,7 @@
isa
=
PBXSourcesBuildPhase
;
isa
=
PBXSourcesBuildPhase
;
buildActionMask
=
2147483647
;
buildActionMask
=
2147483647
;
files
=
(
files
=
(
CD35DFD0260344A500F2138F
/* ForecastConditionView.swift in Sources */
,
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 */
,
...
@@ -695,10 +727,11 @@
...
@@ -695,10 +727,11 @@
CD39F2EE25DE858D009FE398
/* NotificationName+Localization.swift in Sources */
,
CD39F2EE25DE858D009FE398
/* NotificationName+Localization.swift in Sources */
,
CEAFF08F25DFC6ED00DF4EBF
/* HourlyWeather.swift in Sources */
,
CEAFF08F25DFC6ED00DF4EBF
/* HourlyWeather.swift in Sources */
,
CD71709025FA317700A63C27
/* ForecastTimePeriodView.swift in Sources */
,
CD71709025FA317700A63C27
/* ForecastTimePeriodView.swift in Sources */
,
CD35DFD426034BCD00F2138F
/* UIStackView+RemoveAll.swift in Sources */
,
CDE18DD825D16CB200C80ED9
/* NavigationCityButton.swift in Sources */
,
CDE18DD825D16CB200C80ED9
/* NavigationCityButton.swift in Sources */
,
CD17C60225D15C8500EE884E
/* CoordinatorProtocol.swift in Sources */
,
CD17C60225D15C8500EE884E
/* CoordinatorProtocol.swift in Sources */
,
CDA5542825EF734200A2E08C
/* TodayCellFactory.swift in Sources */
,
CDA5542825EF734200A2E08C
/* TodayCellFactory.swift in Sources */
,
CD86C22225F0DCCB00F38A16
/* PrecipView.swift in Sources */
,
CD86C22225F0DCCB00F38A16
/* Precip
itation
View.swift in Sources */
,
CD17C5FF25D15B7C00EE884E
/* TodayCoordinator.swift in Sources */
,
CD17C5FF25D15B7C00EE884E
/* TodayCoordinator.swift in Sources */
,
CD822FF525D6817000A05501
/* CityForecastCell.swift in Sources */
,
CD822FF525D6817000A05501
/* CityForecastCell.swift in Sources */
,
CEDE4E8525EEFD56007457E9
/* WdtHourlySummariesArray.swift in Sources */
,
CEDE4E8525EEFD56007457E9
/* WdtHourlySummariesArray.swift in Sources */
,
...
@@ -712,6 +745,7 @@
...
@@ -712,6 +745,7 @@
CEDE4E8325EEFD56007457E9
/* WdtLocationResponse.swift in Sources */
,
CEDE4E8325EEFD56007457E9
/* WdtLocationResponse.swift in Sources */
,
CD8E041625F8F91B001785B6
/* ForecastCellFactory.swift in Sources */
,
CD8E041625F8F91B001785B6
/* ForecastCellFactory.swift in Sources */
,
CDC6125325E79C8F00188DA7
/* DayTimeView.swift in Sources */
,
CDC6125325E79C8F00188DA7
/* DayTimeView.swift in Sources */
,
CD251EDC26036E5400ED7A65
/* DayTimePrecipitationView.swift in Sources */
,
CD86246925E672A20097F3FB
/* PrecipButton.swift in Sources */
,
CD86246925E672A20097F3FB
/* PrecipButton.swift in Sources */
,
CD3F6E6C25FA5A90002DB99B
/* PeriodButtonProtocol.swift in Sources */
,
CD3F6E6C25FA5A90002DB99B
/* PeriodButtonProtocol.swift in Sources */
,
CEDE4E8225EEFD56007457E9
/* WdtWeatherCode.swift in Sources */
,
CEDE4E8225EEFD56007457E9
/* WdtWeatherCode.swift in Sources */
,
...
@@ -721,12 +755,14 @@
...
@@ -721,12 +755,14 @@
CDC6126225E8DAB800188DA7
/* CityMoonCell.swift in Sources */
,
CDC6126225E8DAB800188DA7
/* CityMoonCell.swift in Sources */
,
CD6B303E25726960004B34B3
/* ThemeProtocol.swift in Sources */
,
CD6B303E25726960004B34B3
/* ThemeProtocol.swift in Sources */
,
CD6B303B2572680C004B34B3
/* SelfSizingButton.swift in Sources */
,
CD6B303B2572680C004B34B3
/* SelfSizingButton.swift in Sources */
,
CD35DFCC260341B000F2138F
/* Calendar+TimeZone.swift in Sources */
,
CD9B6B1125DBC723001D9B80
/* CubicCurveAlgorithm.swift in Sources */
,
CD9B6B1125DBC723001D9B80
/* CubicCurveAlgorithm.swift in Sources */
,
CEC5270025E7BACB00DA58A5
/* WdtLocation.swift in Sources */
,
CEC5270025E7BACB00DA58A5
/* WdtLocation.swift in Sources */
,
CD647D0225ED07D60034578B
/* TodayViewModel.swift in Sources */
,
CD647D0225ED07D60034578B
/* TodayViewModel.swift in Sources */
,
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 */
,
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 */
,
CD822FFE25D6976F00A05501
/* TodayAdCell.swift in Sources */
,
CD822FFE25D6976F00A05501
/* TodayAdCell.swift in Sources */
,
...
...
1Weather.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
2d426c1d
...
@@ -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 @
2d426c1d
No preview for this file type
1Weather/Extensions/Calendar+TimeZone.swift
0 → 100644
View file @
2d426c1d
//
// Calendar+TimeZone.swift
// 1Weather
//
// Created by Dmitry Stepanets on 18.03.2021.
//
import
UIKit
extension
Calendar
{
static
func
timeZoneCalendar
(
timeZone
:
TimeZone
)
->
Self
{
var
cal
=
Calendar
(
identifier
:
current
.
identifier
)
cal
.
timeZone
=
timeZone
return
cal
}
}
1Weather/Extensions/UIStackView+RemoveAll.swift
0 → 100644
View file @
2d426c1d
//
// UIStackView+RemoveAll.swift
// 1Weather
//
// Created by Dmitry Stepanets on 18.03.2021.
//
import
UIKit
extension
UIStackView
{
func
removeAll
()
{
arrangedSubviews
.
forEach
{
removeArrangedSubview
(
$0
)
$0
.
removeFromSuperview
()
}
}
}
1Weather/Model/HelperTypes.swift
View file @
2d426c1d
...
@@ -50,6 +50,54 @@ public enum WeatherType: String, CaseIterable {
...
@@ -50,6 +50,54 @@ public enum WeatherType: String, CaseIterable {
}
}
}
}
public
enum
WeatherConditionType
:
CaseIterable
{
case
precipitation
case
humidity
case
uvIndex
case
pressure
case
dewPoint
case
visibility
case
wind
var
localized
:
String
{
switch
self
{
case
.
precipitation
:
return
"condition.precipitation"
.
localized
()
case
.
humidity
:
return
"condition.humidity"
.
localized
()
case
.
uvIndex
:
return
"condition.uvIndex"
.
localized
()
case
.
pressure
:
return
"condition.pressure"
.
localized
()
case
.
dewPoint
:
return
"condition.dewPoint"
.
localized
()
case
.
visibility
:
return
"condition.visibility"
.
localized
()
case
.
wind
:
return
"condition.wind"
.
localized
()
}
}
var
image
:
UIImage
?
{
switch
self
{
case
.
precipitation
:
return
UIImage
(
named
:
"precipitation"
)
case
.
humidity
:
return
UIImage
(
named
:
"humidity"
)
case
.
uvIndex
:
return
UIImage
(
named
:
"uv_index"
)
case
.
pressure
:
return
UIImage
(
named
:
"pressure"
)
case
.
dewPoint
:
return
UIImage
(
named
:
"dewPoint"
)
case
.
visibility
:
return
UIImage
(
named
:
"visibility"
)
case
.
wind
:
return
UIImage
(
named
:
"blowingDust"
)
}
}
}
public
enum
WindDirection
:
String
,
Codable
,
CaseIterable
{
public
enum
WindDirection
:
String
,
Codable
,
CaseIterable
{
case
north
=
"N"
case
north
=
"N"
case
northNorthEast
=
"NNE"
case
northNorthEast
=
"NNE"
...
...
1Weather/Model/ModelObjects/DailyWeather.swift
View file @
2d426c1d
...
@@ -8,18 +8,13 @@
...
@@ -8,18 +8,13 @@
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
{
public
var
isToday
:
Bool
{
DailyWeather
.
timeZoneCaledar
.
timeZone
=
timeZone
return
Calendar
.
timeZoneCalendar
(
timeZone
:
timeZone
)
.
isDateInToday
(
date
)
return
DailyWeather
.
timeZoneCaledar
.
isDateInToday
(
date
)
}
}
public
var
minTemp
:
Temperature
?
public
var
minTemp
:
Temperature
?
...
...
1Weather/Model/ModelObjects/Location.swift
View file @
2d426c1d
...
@@ -46,8 +46,7 @@ public struct Location: Equatable, Hashable {
...
@@ -46,8 +46,7 @@ public struct Location: Equatable, Hashable {
public
var
daily
=
[
DailyWeather
]()
public
var
daily
=
[
DailyWeather
]()
public
var
hourly
=
[
HourlyWeather
]()
{
public
var
hourly
=
[
HourlyWeather
]()
{
didSet
{
didSet
{
var
calendar
=
Calendar
(
identifier
:
.
gregorian
)
let
calendar
=
Calendar
.
timeZoneCalendar
(
timeZone
:
self
.
timeZone
)
calendar
.
timeZone
=
self
.
timeZone
dayTimeForecast
=
hourly
.
compactMap
{
dayTimeForecast
=
hourly
.
compactMap
{
guard
let
dayTime
=
DayTime
(
hour
:
calendar
.
component
(
.
hour
,
from
:
$0
.
date
))
else
{
guard
let
dayTime
=
DayTime
(
hour
:
calendar
.
component
(
.
hour
,
from
:
$0
.
date
))
else
{
...
...
1Weather/UI/Helpers/ForecastTimePeriod/ForecastDetailPeriodButton.swift
View file @
2d426c1d
...
@@ -83,7 +83,7 @@ class ForecastDetailPeriodButton: UIControl, PeriodButtonProtocol {
...
@@ -83,7 +83,7 @@ class ForecastDetailPeriodButton: UIControl, PeriodButtonProtocol {
}
}
func
configure
(
dailyWeather
:
DailyWeather
)
{
func
configure
(
dailyWeather
:
DailyWeather
)
{
if
Calendar
.
current
.
isDateInToday
(
dailyWeather
.
date
)
{
if
Calendar
.
timeZoneCalendar
(
timeZone
:
dailyWeather
.
timeZone
)
.
isDateInToday
(
dailyWeather
.
date
)
{
dateLabel
.
text
=
"day.today"
.
localized
()
dateLabel
.
text
=
"day.today"
.
localized
()
}
}
else
{
else
{
...
@@ -200,6 +200,7 @@ private extension ForecastDetailPeriodButton {
...
@@ -200,6 +200,7 @@ private extension ForecastDetailPeriodButton {
precipLabel
.
snp
.
makeConstraints
{
(
make
)
in
precipLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalTo
(
precipImageView
.
snp
.
right
)
.
inset
(
2
)
make
.
left
.
equalTo
(
precipImageView
.
snp
.
right
)
.
inset
(
2
)
make
.
right
.
equalToSuperview
()
make
.
right
.
equalToSuperview
()
make
.
centerY
.
equalTo
(
precipImageView
)
}
}
addSubview
(
container
)
addSubview
(
container
)
...
...
1Weather/UI/Helpers/ForecastTimePeriod/ForecastPeriodButton.swift
View file @
2d426c1d
...
@@ -89,7 +89,7 @@ class ForecastPeriodButton: UIControl, PeriodButtonProtocol {
...
@@ -89,7 +89,7 @@ class ForecastPeriodButton: UIControl, PeriodButtonProtocol {
self
.
minTempLabel
.
text
=
dailyWeather
.
minTemp
?
.
shortString
self
.
minTempLabel
.
text
=
dailyWeather
.
minTemp
?
.
shortString
self
.
indicatorImageView
.
image
=
nil
self
.
indicatorImageView
.
image
=
nil
self
.
forecastImageView
.
image
=
dailyWeather
.
type
.
image
(
isDay
:
true
)
self
.
forecastImageView
.
image
=
dailyWeather
.
type
.
image
(
isDay
:
true
)
if
Calendar
.
current
.
isDateInToday
(
dailyWeather
.
date
)
{
if
Calendar
.
timeZoneCalendar
(
timeZone
:
dailyWeather
.
timeZone
)
.
isDateInToday
(
dailyWeather
.
date
)
{
self
.
timeLabel
.
text
=
"day.today"
.
localized
()
self
.
timeLabel
.
text
=
"day.today"
.
localized
()
}
}
else
{
else
{
...
...
1Weather/UI/Helpers/ForecastTimePeriod/ForecastTimePeriodView.swift
View file @
2d426c1d
...
@@ -16,6 +16,10 @@ private struct HourlyGraphPoints {
...
@@ -16,6 +16,10 @@ private struct HourlyGraphPoints {
let
points
:
[
CGPoint
]
let
points
:
[
CGPoint
]
}
}
protocol
ForecastTimePeriodViewDelegate
:
class
{
func
forecastTimePeriodView
(
view
:
ForecastTimePeriodView
,
didSelectButtonAt
index
:
Int
)
}
class
ForecastTimePeriodView
:
UIView
{
class
ForecastTimePeriodView
:
UIView
{
//Private
//Private
private
let
scrollView
=
UIScrollView
()
private
let
scrollView
=
UIScrollView
()
...
@@ -28,6 +32,9 @@ class ForecastTimePeriodView: UIView {
...
@@ -28,6 +32,9 @@ class ForecastTimePeriodView: UIView {
private
var
daily
=
[
DailyWeather
]()
private
var
daily
=
[
DailyWeather
]()
private
var
hourly
=
[
HourlyWeather
]()
private
var
hourly
=
[
HourlyWeather
]()
//Public
weak
var
delegate
:
ForecastTimePeriodViewDelegate
?
//MARK:- View life cycle
//MARK:- View life cycle
init
()
{
init
()
{
super
.
init
(
frame
:
.
zero
)
super
.
init
(
frame
:
.
zero
)
...
@@ -53,17 +60,27 @@ class ForecastTimePeriodView: UIView {
...
@@ -53,17 +60,27 @@ class ForecastTimePeriodView: UIView {
}
}
}
}
public
func
set
(
timePeriod
:
TimePeriod
,
buttonType
:
PeriodButtonProtocol
.
Type
)
{
public
func
set
(
timePeriod
:
TimePeriod
,
buttonType
:
PeriodButtonProtocol
.
Type
,
selectedIndex
:
Int
=
0
)
{
self
.
currentTimePeriod
=
timePeriod
self
.
currentTimePeriod
=
timePeriod
rebuildButtons
(
buttonType
:
buttonType
)
rebuildButtons
(
buttonType
:
buttonType
,
selectedIndex
:
selectedIndex
)
}
}
//Private
//Private
private
func
rebuildButtons
(
buttonType
:
PeriodButtonProtocol
.
Type
)
{
@objc
private
func
handleForecastButton
(
button
:
UIControl
)
{
stackView
.
arrangedSubviews
.
forEach
{
stackView
.
arrangedSubviews
.
enumerated
()
.
forEach
{
stackView
.
removeArrangedSubview
(
$0
)
if
let
periodButton
=
$1
as?
PeriodButtonProtocol
{
$0
.
removeFromSuperview
()
periodButton
.
isSelected
=
periodButton
===
button
if
periodButton
.
isSelected
{
tintGraphAt
(
button
:
periodButton
)
delegate
?
.
forecastTimePeriodView
(
view
:
self
,
didSelectButtonAt
:
$0
)
}
}
}
}
}
private
func
rebuildButtons
(
buttonType
:
PeriodButtonProtocol
.
Type
,
selectedIndex
:
Int
)
{
stackView
.
removeAll
()
let
numberOfButtons
:
Int
let
numberOfButtons
:
Int
switch
currentTimePeriod
{
switch
currentTimePeriod
{
...
@@ -83,7 +100,7 @@ class ForecastTimePeriodView: UIView {
...
@@ -83,7 +100,7 @@ class ForecastTimePeriodView: UIView {
}
}
forecastButton
.
index
=
index
forecastButton
.
index
=
index
forecastButton
.
addTarget
(
self
,
action
:
#selector(
handleForecastButton(button:)
)
,
for
:
.
touchUpInside
)
forecastButton
.
addTarget
(
self
,
action
:
#selector(
handleForecastButton(button:)
)
,
for
:
.
touchUpInside
)
forecastButton
.
isSelected
=
index
==
1
forecastButton
.
isSelected
=
index
==
selectedIndex
stackView
.
addArrangedSubview
(
forecastButton
)
stackView
.
addArrangedSubview
(
forecastButton
)
forecastButton
.
snp
.
makeConstraints
{
(
make
)
in
forecastButton
.
snp
.
makeConstraints
{
(
make
)
in
...
@@ -218,18 +235,6 @@ class ForecastTimePeriodView: UIView {
...
@@ -218,18 +235,6 @@ class ForecastTimePeriodView: UIView {
self
.
graphView
.
tintMainDotAt
(
point
:
hourlyGraphPoints
.
points
[
button
.
index
])
self
.
graphView
.
tintMainDotAt
(
point
:
hourlyGraphPoints
.
points
[
button
.
index
])
}
}
}
}
@objc
private
func
handleForecastButton
(
button
:
UIControl
)
{
stackView
.
arrangedSubviews
.
forEach
{
if
let
periodButton
=
$0
as?
PeriodButtonProtocol
{
periodButton
.
isSelected
=
periodButton
===
button
if
periodButton
.
isSelected
{
tintGraphAt
(
button
:
periodButton
)
}
}
}
}
}
}
private
extension
ForecastTimePeriodView
{
private
extension
ForecastTimePeriodView
{
...
...
1Weather/UI/View controllers/Forecast/Cells/ForecastCellFactory.swift
View file @
2d426c1d
...
@@ -14,22 +14,32 @@ private enum ForecastCellType:Int, CaseIterable {
...
@@ -14,22 +14,32 @@ private enum ForecastCellType:Int, CaseIterable {
// case conditions
// case conditions
// case precipitation
// case precipitation
// case dayTime
// case dayTime
//
case sun
case
sun
//
case moon
case
moon
}
}
class
ForecastCellFactory
{
class
ForecastCellFactory
{
//Private
private
let
forecastViewModel
:
ForecastViewModel
//Public
public
var
forecastPeriodCellFrame
:
CGRect
=
.
zero
public
var
forecastPeriodCellFrame
:
CGRect
=
.
zero
public
var
numberOfRows
:
Int
{
public
var
numberOfRows
:
Int
{
return
ForecastCellType
.
allCases
.
count
return
ForecastCellType
.
allCases
.
count
}
}
public
init
(
viewModel
:
ForecastViewModel
)
{
self
.
forecastViewModel
=
viewModel
}
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
)
registerCell
(
type
:
ForecastInfoCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CitySunCell
.
self
,
tableView
:
tableView
)
registerCell
(
type
:
CityMoonCell
.
self
,
tableView
:
tableView
)
}
}
public
func
cellFromTableView
(
tableView
:
UITableView
,
indexPath
:
IndexPath
,
viewModel
:
ForecastViewModel
)
->
UITableViewCell
{
public
func
cellFromTableView
(
tableView
:
UITableView
,
indexPath
:
IndexPath
)
->
UITableViewCell
{
guard
let
cellType
=
ForecastCellType
(
rawValue
:
indexPath
.
row
)
else
{
guard
let
cellType
=
ForecastCellType
(
rawValue
:
indexPath
.
row
)
else
{
return
UITableViewCell
()
return
UITableViewCell
()
}
}
...
@@ -37,20 +47,44 @@ class ForecastCellFactory {
...
@@ -37,20 +47,44 @@ class ForecastCellFactory {
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
.
delegate
=
self
forecastPeriodCellFrame
=
cell
.
frame
forecastPeriodCellFrame
=
cell
.
frame
if
let
daily
=
v
iewModel
.
location
?
.
daily
,
if
let
daily
=
forecastV
iewModel
.
location
?
.
daily
,
let
hourly
=
v
iewModel
.
location
?
.
hourly
{
let
hourly
=
forecastV
iewModel
.
location
?
.
hourly
{
cell
.
configure
(
daily
:
daily
,
hourly
:
hourly
)
cell
.
configure
(
daily
:
daily
,
hourly
:
hourly
)
}
}
return
cell
return
cell
case
.
forecastInfo
:
case
.
forecastInfo
:
let
cell
=
dequeueReusableCell
(
type
:
ForecastInfoCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
let
cell
=
dequeueReusableCell
(
type
:
ForecastInfoCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
if
let
location
=
viewModel
.
location
,
if
let
daily
=
forecastViewModel
.
selectedDailyWeather
{
let
today
=
(
location
.
daily
.
first
{
$0
.
isToday
})
{
cell
.
configure
(
dailyWeather
:
daily
)
cell
.
configure
(
dailyWeather
:
today
)
}
return
cell
case
.
sun
:
let
cell
=
dequeueReusableCell
(
type
:
CitySunCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
if
let
loc
=
forecastViewModel
.
location
{
cell
.
configure
(
with
:
loc
)
}
}
return
cell
return
cell
case
.
moon
:
let
cell
=
dequeueReusableCell
(
type
:
CityMoonCell
.
self
,
tableView
:
tableView
,
indexPath
:
indexPath
)
if
let
loc
=
forecastViewModel
.
location
{
cell
.
configure
(
with
:
loc
)
}
return
cell
}
}
public
func
willDisplay
(
cell
:
UITableViewCell
)
{
switch
cell
{
case
let
sunCell
as
CitySunCell
:
sunCell
.
updateSunPosition
()
case
let
moonCell
as
CityMoonCell
:
moonCell
.
updateMoonPosition
()
default
:
break
}
}
}
}
...
@@ -64,3 +98,10 @@ class ForecastCellFactory {
...
@@ -64,3 +98,10 @@ class ForecastCellFactory {
return
cell
return
cell
}
}
}
}
//MARK:- ForecastTimePeriodCell Delegate
extension
ForecastCellFactory
:
ForecastTimePeriodCellDelegate
{
func
timePeriodCell
(
cell
:
ForecastTimePeriodCell
,
didSelectButtonAt
index
:
Int
)
{
forecastViewModel
.
selectDailyWeather
(
at
:
index
)
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastInfoCell/ForecastConditionView.swift
0 → 100644
View file @
2d426c1d
//
// ForecastConditionView.swift
// 1Weather
//
// Created by Dmitry Stepanets on 18.03.2021.
//
import
UIKit
class
ForecastConditionView
:
UIView
{
//Private
private
let
type
:
WeatherConditionType
private
let
imageView
=
UIImageView
()
private
let
valueLabel
=
UILabel
()
private
let
nameLabel
=
UILabel
()
init
(
type
:
WeatherConditionType
)
{
self
.
type
=
type
super
.
init
(
frame
:
.
zero
)
prepareImageView
()
prepareLabels
()
}
func
configure
(
dailyWeather
:
DailyWeather
)
{
switch
type
{
case
.
precipitation
:
valueLabel
.
text
=
"
\(
dailyWeather
.
precipitationProbability
??
0
)
%"
case
.
humidity
:
valueLabel
.
text
=
"--"
case
.
uvIndex
:
valueLabel
.
text
=
"--"
case
.
pressure
:
valueLabel
.
text
=
"--"
case
.
dewPoint
:
valueLabel
.
text
=
"--"
case
.
visibility
:
valueLabel
.
text
=
"--"
case
.
wind
:
let
speed
=
dailyWeather
.
windSpeed
?
.
string
??
"--"
let
direction
=
dailyWeather
.
windDirection
?
.
rawValue
??
""
valueLabel
.
text
=
"
\(
direction
)
\(
speed
)
"
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
private
extension
ForecastConditionView
{
func
prepareImageView
()
{
imageView
.
contentMode
=
.
scaleAspectFit
imageView
.
image
=
type
.
image
addSubview
(
imageView
)
imageView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
width
.
height
.
equalTo
(
32
)
make
.
top
.
left
.
bottom
.
equalToSuperview
()
}
}
func
prepareLabels
()
{
valueLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
valueLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
14
)
valueLabel
.
setContentHuggingPriority
(
.
fittingSizeLevel
,
for
:
.
vertical
)
addSubview
(
valueLabel
)
nameLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
nameLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
12
)
nameLabel
.
text
=
type
.
localized
nameLabel
.
setContentCompressionResistancePriority
(
.
init
(
751
),
for
:
.
vertical
)
addSubview
(
nameLabel
)
//Constraints
valueLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalTo
(
imageView
.
snp
.
right
)
.
offset
(
10
)
make
.
top
.
equalToSuperview
()
make
.
right
.
equalToSuperview
()
}
nameLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalTo
(
valueLabel
)
make
.
top
.
equalTo
(
valueLabel
.
snp
.
bottom
)
.
offset
(
5
)
make
.
bottom
.
equalToSuperview
()
make
.
right
.
equalToSuperview
()
}
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastInfoCell.swift
→
1Weather/UI/View controllers/Forecast/Cells/ForecastInfoCell
/ForecastInfoCell
.swift
View file @
2d426c1d
...
@@ -35,7 +35,31 @@ class ForecastInfoCell: UITableViewCell {
...
@@ -35,7 +35,31 @@ class ForecastInfoCell: UITableViewCell {
let
minTemp
=
dailyWeather
.
minTemp
?
.
shortString
??
"--"
let
minTemp
=
dailyWeather
.
minTemp
?
.
shortString
??
"--"
tempLabel
.
text
=
"
\(
maxTemp
)
/
\(
minTemp
)
"
tempLabel
.
text
=
"
\(
maxTemp
)
/
\(
minTemp
)
"
weatherTypeLabel
.
text
=
dailyWeather
.
type
.
localized
(
isDay
:
true
)
weatherTypeLabel
.
text
=
dailyWeather
.
type
.
localized
(
isDay
:
true
)
weatherDescriptionLabel
.
text
=
"Feels like -- - Due to high humidity"
weatherDescriptionLabel
.
text
=
"Feels like --"
//Conditions
conditionsStackView
.
removeAll
()
let
availableConditions
:[
WeatherConditionType
]
=
[
.
precipitation
,
.
uvIndex
,
.
wind
]
let
rowsCount
=
(
CGFloat
(
WeatherConditionType
.
allCases
.
count
)
/
3
)
.
rounded
(
.
up
)
var
currentRow
=
-
1
var
currentConditionsRowStackView
=
UIStackView
()
for
(
index
,
type
)
in
availableConditions
.
enumerated
()
{
if
currentRow
!=
index
/
Int
(
rowsCount
)
{
currentConditionsRowStackView
=
UIStackView
()
currentConditionsRowStackView
.
axis
=
.
horizontal
currentConditionsRowStackView
.
distribution
=
.
equalSpacing
conditionsStackView
.
addArrangedSubview
(
currentConditionsRowStackView
)
}
let
conditionView
=
ForecastConditionView
(
type
:
type
)
conditionView
.
configure
(
dailyWeather
:
dailyWeather
)
currentConditionsRowStackView
.
addArrangedSubview
(
conditionView
)
currentRow
=
index
/
Int
(
rowsCount
)
}
conditionsStackView
.
layoutIfNeeded
()
}
}
}
}
...
@@ -100,11 +124,15 @@ private extension ForecastInfoCell {
...
@@ -100,11 +124,15 @@ private extension ForecastInfoCell {
}
}
func
prepareConditionsStackView
()
{
func
prepareConditionsStackView
()
{
conditionsStackView
.
axis
=
.
vertical
conditionsStackView
.
distribution
=
.
fillEqually
conditionsStackView
.
spacing
=
54
conditionsStackView
.
setContentCompressionResistancePriority
(
.
init
(
rawValue
:
751
),
for
:
.
vertical
)
contentView
.
addSubview
(
conditionsStackView
)
contentView
.
addSubview
(
conditionsStackView
)
conditionsStackView
.
snp
.
makeConstraints
{
(
make
)
in
conditionsStackView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalTo
(
topContainer
.
snp
.
bottom
)
.
offset
(
15
)
make
.
top
.
equalTo
(
topContainer
.
snp
.
bottom
)
.
offset
(
15
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
15
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
15
)
.
priority
(
.
init
(
999
))
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
18
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
18
)
}
}
}
}
...
...
1Weather/UI/View controllers/Forecast/Cells/ForecastPrecipitationCell/DayTimePrecipitationView.swift
0 → 100644
View file @
2d426c1d
//
// DayTimePrecipitationView.swift
// 1Weather
//
// Created by Dmitry Stepanets on 18.03.2021.
//
import
UIKit
class
DayTimePrecipitationView
:
UIView
{
//Private
private
let
dayTimeLabel
=
UILabel
()
private
let
precipitationView
=
PrecipitationView
()
private
let
valueLabel
=
UILabel
()
init
(
withSeparator
:
Bool
=
false
)
{
super
.
init
(
frame
:
.
zero
)
prepareView
()
prepareLabels
()
preparePrecipView
()
if
withSeparator
{
prepareSeparator
()
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
private
extension
DayTimePrecipitationView
{
func
prepareView
()
{
self
.
snp
.
makeConstraints
{
(
make
)
in
make
.
width
.
equalTo
(
90
)
}
}
func
prepareLabels
()
{
dayTimeLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
14
)
dayTimeLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
addSubview
(
dayTimeLabel
)
valueLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
12
)
valueLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
addSubview
(
valueLabel
)
//Constraints
dayTimeLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalToSuperview
()
.
inset
(
24
)
make
.
centerX
.
equalToSuperview
()
}
valueLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
centerX
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
.
inset
(
18
)
}
}
func
preparePrecipView
()
{
addSubview
(
precipitationView
)
precipitationView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalTo
(
dayTimeLabel
.
snp
.
bottom
)
.
offset
(
24
)
.
priority
(
.
medium
)
make
.
bottom
.
equalTo
(
valueLabel
.
snp
.
top
)
.
offset
(
-
20
)
make
.
width
.
equalTo
(
24
)
make
.
centerX
.
equalToSuperview
()
make
.
height
.
equalTo
(
130
)
}
}
func
prepareSeparator
()
{
let
separatorView
=
UIView
()
separatorView
.
backgroundColor
=
UIColor
(
hex
:
0xc2c9d6
)
separatorView
.
alpha
=
0.5
addSubview
(
separatorView
)
separatorView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalTo
(
dayTimeLabel
)
make
.
bottom
.
equalTo
(
precipitationView
)
make
.
right
.
equalToSuperview
()
make
.
width
.
equalTo
(
1
)
}
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastPrecipitationCell/ForecastPrecipitationCell.swift
0 → 100644
View file @
2d426c1d
//
// ForecastPrecipitationCell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 18.03.2021.
//
import
UIKit
class
ForecastPrecipitationCell
:
UITableViewCell
{
//Private
private
let
titleLabel
=
UILabel
()
private
let
stackView
=
UIStackView
()
private
let
infoContainer
=
UIView
()
private
let
infoImageView
=
UIImageView
()
private
let
infoLabel
=
UILabel
()
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
prepareCell
()
prepareTitle
()
prepareStackView
()
prepareInfoContainer
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
//MARK:- Prepare
private
extension
ForecastPrecipitationCell
{
func
prepareCell
()
{
selectionStyle
=
.
none
contentView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
}
func
prepareTitle
()
{
titleLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
16
)
titleLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
titleLabel
.
text
=
"precipitation.title"
.
localized
()
.
uppercased
()
contentView
.
addSubview
(
titleLabel
)
}
func
prepareStackView
()
{
stackView
.
axis
=
.
horizontal
stackView
.
distribution
=
.
fillEqually
stackView
.
alignment
=
.
center
stackView
.
spacing
=
0
stackView
.
clipsToBounds
=
false
stackView
.
isLayoutMarginsRelativeArrangement
=
true
stackView
.
layoutMargins
=
.
init
(
top
:
0
,
left
:
6
,
bottom
:
0
,
right
:
6
)
contentView
.
addSubview
(
stackView
)
stackView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
top
.
equalTo
(
titleLabel
.
snp
.
bottom
)
.
offset
(
18
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
18
)
}
}
func
prepareInfoContainer
()
{
infoImageView
.
contentMode
=
.
scaleAspectFit
infoImageView
.
image
=
UIImage
(
named
:
"humidity"
)
infoContainer
.
addSubview
(
infoImageView
)
infoImageView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
.
inset
(
20
)
make
.
centerY
.
equalToSuperview
()
make
.
width
.
height
.
equalTo
(
12
)
}
infoLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
13
)
infoLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
infoLabel
.
text
=
"Possible light shower between 1 PM - 2 PM"
infoContainer
.
addSubview
(
infoLabel
)
infoLabel
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalTo
(
infoImageView
.
snp
.
right
)
.
offset
(
8
)
make
.
right
.
equalToSuperview
()
.
inset
(
8
)
make
.
centerY
.
equalToSuperview
()
}
infoContainer
.
backgroundColor
=
UIColor
(
hex
:
0xd9ebfe
)
infoContainer
.
layer
.
cornerRadius
=
12
contentView
.
addSubview
(
infoContainer
)
infoContainer
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
18
)
make
.
height
.
equalTo
(
40
)
make
.
top
.
equalTo
(
stackView
.
snp
.
bottom
)
.
offset
(
20
)
.
priority
(
.
medium
)
make
.
bottom
.
equalToSuperview
()
.
inset
(
15
)
}
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastPrecipitationCell/ForecastPrecipitationView.swift
0 → 100644
View file @
2d426c1d
//
// DayTimePrecipitationView.swift
// 1Weather
//
// Created by Dmitry Stepanets on 18.03.2021.
//
import
UIKit
class
DayTimePrecipitationView
:
UIView
{
//Private
private
let
dai
init
(
withSeparator
:
Bool
=
false
)
{
super
.
init
(
frame
:
.
zero
)
}
}
private
extension
DayTimePrecipitationView
{
func
prepareLabels
()
{
}
func
preparePrecipView
()
{
}
func
prepareSeparator
()
{
}
}
1Weather/UI/View controllers/Forecast/Cells/ForecastTimePeriodCell.swift
View file @
2d426c1d
...
@@ -7,6 +7,10 @@
...
@@ -7,6 +7,10 @@
import
UIKit
import
UIKit
protocol
ForecastTimePeriodCellDelegate
:
class
{
func
timePeriodCell
(
cell
:
ForecastTimePeriodCell
,
didSelectButtonAt
index
:
Int
)
}
class
ForecastTimePeriodCell
:
UITableViewCell
{
class
ForecastTimePeriodCell
:
UITableViewCell
{
//Private
//Private
private
let
periodSegmentedControl
=
ForecastTimePeriodControl
(
items
:
[
"forecast.timePeriod.daily"
.
localized
(),
private
let
periodSegmentedControl
=
ForecastTimePeriodControl
(
items
:
[
"forecast.timePeriod.daily"
.
localized
(),
...
@@ -17,6 +21,9 @@ class ForecastTimePeriodCell: UITableViewCell {
...
@@ -17,6 +21,9 @@ class ForecastTimePeriodCell: UITableViewCell {
endColor
:
UIColor
(
hex
:
0xdaddec
),
endColor
:
UIColor
(
hex
:
0xdaddec
),
opacity
:
0.5
)
opacity
:
0.5
)
private
var
graphIsDrawn
=
false
private
var
graphIsDrawn
=
false
//Public
weak
var
delegate
:
ForecastTimePeriodCellDelegate
?
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
...
@@ -74,6 +81,7 @@ private extension ForecastTimePeriodCell {
...
@@ -74,6 +81,7 @@ private extension ForecastTimePeriodCell {
}
}
func
prepareForecastTimePeriodView
()
{
func
prepareForecastTimePeriodView
()
{
forecastTimePeriodView
.
delegate
=
self
contentView
.
addSubview
(
forecastTimePeriodView
)
contentView
.
addSubview
(
forecastTimePeriodView
)
forecastTimePeriodView
.
snp
.
makeConstraints
{
(
make
)
in
forecastTimePeriodView
.
snp
.
makeConstraints
{
(
make
)
in
make
.
left
.
equalToSuperview
()
make
.
left
.
equalToSuperview
()
...
@@ -92,3 +100,10 @@ private extension ForecastTimePeriodCell {
...
@@ -92,3 +100,10 @@ private extension ForecastTimePeriodCell {
}
}
}
}
}
}
//MARK:- ForecastTimePeriodView Delegate
extension
ForecastTimePeriodCell
:
ForecastTimePeriodViewDelegate
{
func
forecastTimePeriodView
(
view
:
ForecastTimePeriodView
,
didSelectButtonAt
index
:
Int
)
{
self
.
delegate
?
.
timePeriodCell
(
cell
:
self
,
didSelectButtonAt
:
index
)
}
}
1Weather/UI/View controllers/Forecast/DaysControlView.swift
View file @
2d426c1d
...
@@ -112,9 +112,6 @@ private class DayControlButton: UIControl {
...
@@ -112,9 +112,6 @@ private class DayControlButton: UIControl {
fmt
.
dateFormat
=
"d, E"
fmt
.
dateFormat
=
"d, E"
return
fmt
return
fmt
}()
}()
private
static
var
calendar
:
Calendar
=
{
return
Calendar
(
identifier
:
Calendar
.
current
.
identifier
)
}()
//Public
//Public
var
index
:
Int
=
-
1
var
index
:
Int
=
-
1
...
@@ -166,9 +163,8 @@ private class DayControlButton: UIControl {
...
@@ -166,9 +163,8 @@ private class DayControlButton: UIControl {
func
configure
(
dailyWeather
:
DailyWeather
)
{
func
configure
(
dailyWeather
:
DailyWeather
)
{
DayControlButton
.
dateFormatter
.
timeZone
=
dailyWeather
.
timeZone
DayControlButton
.
dateFormatter
.
timeZone
=
dailyWeather
.
timeZone
DayControlButton
.
calendar
.
timeZone
=
dailyWeather
.
timeZone
if
DayControlButton
.
calendar
.
isDateInToday
(
dailyWeather
.
date
)
{
if
Calendar
.
timeZoneCalendar
(
timeZone
:
dailyWeather
.
timeZone
)
.
isDateInToday
(
dailyWeather
.
date
)
{
dayLabel
.
text
=
"day.today"
.
localized
()
dayLabel
.
text
=
"day.today"
.
localized
()
}
}
else
{
else
{
...
...
1Weather/UI/View controllers/Forecast/ForecastViewController.swift
View file @
2d426c1d
...
@@ -9,6 +9,7 @@ import UIKit
...
@@ -9,6 +9,7 @@ import UIKit
class
ForecastViewController
:
UIViewController
{
class
ForecastViewController
:
UIViewController
{
//Private
//Private
private
let
forecastCellFactory
:
ForecastCellFactory
private
let
cityButton
=
NavigationCityButton
()
private
let
cityButton
=
NavigationCityButton
()
private
let
daysControlView
=
DaysControlView
()
private
let
daysControlView
=
DaysControlView
()
private
let
tableView
=
UITableView
()
private
let
tableView
=
UITableView
()
...
@@ -17,6 +18,7 @@ class ForecastViewController: UIViewController {
...
@@ -17,6 +18,7 @@ class ForecastViewController: UIViewController {
init
(
viewModel
:
ForecastViewModel
)
{
init
(
viewModel
:
ForecastViewModel
)
{
self
.
viewModel
=
viewModel
self
.
viewModel
=
viewModel
self
.
forecastCellFactory
=
ForecastCellFactory
(
viewModel
:
viewModel
)
super
.
init
(
nibName
:
nil
,
bundle
:
nil
)
super
.
init
(
nibName
:
nil
,
bundle
:
nil
)
}
}
...
@@ -91,7 +93,7 @@ private extension ForecastViewController {
...
@@ -91,7 +93,7 @@ private extension ForecastViewController {
}
}
func
prepareTableView
()
{
func
prepareTableView
()
{
viewModel
.
forecastCellFactory
.
registerCells
(
on
:
tableView
)
forecastCellFactory
.
registerCells
(
on
:
tableView
)
tableView
.
contentInset
=
.
init
(
top
:
0
,
left
:
0
,
bottom
:
15
,
right
:
0
)
tableView
.
contentInset
=
.
init
(
top
:
0
,
left
:
0
,
bottom
:
15
,
right
:
0
)
tableView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
tableView
.
backgroundColor
=
ThemeManager
.
currentTheme
.
baseBackgroundColor
tableView
.
separatorStyle
=
.
none
tableView
.
separatorStyle
=
.
none
...
@@ -111,18 +113,22 @@ private extension ForecastViewController {
...
@@ -111,18 +113,22 @@ private extension ForecastViewController {
//MARK:- UITableView Delegate
//MARK:- UITableView Delegate
extension
ForecastViewController
:
UITableViewDelegate
{
extension
ForecastViewController
:
UITableViewDelegate
{
func
scrollViewDidScroll
(
_
scrollView
:
UIScrollView
)
{
func
scrollViewDidScroll
(
_
scrollView
:
UIScrollView
)
{
let
cellFrame
=
viewModel
.
forecastCellFactory
.
forecastPeriodCellFrame
let
cellFrame
=
forecastCellFactory
.
forecastPeriodCellFrame
guard
guard
let
navVC
=
self
.
navigationController
,
let
navVC
=
self
.
navigationController
,
cellFrame
.
origin
.
y
>
0
,
viewModel
.
location
?
.
daily
.
isEmpty
==
false
viewModel
.
location
?
.
daily
.
isEmpty
==
false
else
{
else
{
return
return
}
}
let
startPointY
=
cellFrame
.
origin
.
y
+
cellFrame
.
height
-
self
.
daysControlView
.
frame
.
height
let
startPointY
=
cellFrame
.
origin
.
y
+
cellFrame
.
height
-
self
.
daysControlView
.
frame
.
height
guard
startPointY
>
0
else
{
//Force reload row to get actual row height
tableView
.
reloadRows
(
at
:
[[
0
,
0
]],
with
:
.
none
)
return
}
if
scrollView
.
contentOffset
.
y
>=
startPointY
{
if
scrollView
.
contentOffset
.
y
>=
startPointY
{
if
!
navVC
.
isNavigationBarHidden
{
if
!
navVC
.
isNavigationBarHidden
{
navVC
.
setNavigationBarHidden
(
true
,
animated
:
true
)
navVC
.
setNavigationBarHidden
(
true
,
animated
:
true
)
...
@@ -140,23 +146,26 @@ extension ForecastViewController: UITableViewDelegate {
...
@@ -140,23 +146,26 @@ extension ForecastViewController: UITableViewDelegate {
}
}
}
}
}
}
func
tableView
(
_
tableView
:
UITableView
,
willDisplay
cell
:
UITableViewCell
,
forRowAt
indexPath
:
IndexPath
)
{
forecastCellFactory
.
willDisplay
(
cell
:
cell
)
}
}
}
//MARK:- UITableView DataSource
//MARK:- UITableView DataSource
extension
ForecastViewController
:
UITableViewDataSource
{
extension
ForecastViewController
:
UITableViewDataSource
{
func
tableView
(
_
tableView
:
UITableView
,
numberOfRowsInSection
section
:
Int
)
->
Int
{
func
tableView
(
_
tableView
:
UITableView
,
numberOfRowsInSection
section
:
Int
)
->
Int
{
return
viewModel
.
forecastCellFactory
.
numberOfRows
return
forecastCellFactory
.
numberOfRows
}
}
func
tableView
(
_
tableView
:
UITableView
,
cellForRowAt
indexPath
:
IndexPath
)
->
UITableViewCell
{
func
tableView
(
_
tableView
:
UITableView
,
cellForRowAt
indexPath
:
IndexPath
)
->
UITableViewCell
{
return
viewModel
.
forecastCellFactory
.
cellFromTableView
(
tableView
:
tableView
,
return
forecastCellFactory
.
cellFromTableView
(
tableView
:
tableView
,
indexPath
:
indexPath
,
indexPath
:
indexPath
)
viewModel
:
viewModel
)
}
}
}
}
//MARK:- ViewModel Delegate
//MARK:- ViewModel Delegate
extension
ForecastViewController
:
ViewModelDelegate
{
extension
ForecastViewController
:
Forecast
ViewModelDelegate
{
func
viewModelDidChange
<
P
>
(
model
:
P
)
where
P
:
ViewModelProtocol
{
func
viewModelDidChange
<
P
>
(
model
:
P
)
where
P
:
ViewModelProtocol
{
refreshCityButton
()
refreshCityButton
()
tableView
.
reloadData
()
tableView
.
reloadData
()
...
@@ -168,4 +177,15 @@ extension ForecastViewController: ViewModelDelegate {
...
@@ -168,4 +177,15 @@ extension ForecastViewController: ViewModelDelegate {
daysControlView
.
alpha
=
0
daysControlView
.
alpha
=
0
}
}
}
}
func
selectedDailyWeatherDidChange
()
{
var
indexPathToReload
=
[
IndexPath
]()
for
index
in
0
..<
forecastCellFactory
.
numberOfRows
{
if
index
==
0
{
continue
}
indexPathToReload
.
append
([
0
,
index
])
}
tableView
.
reloadRows
(
at
:
indexPathToReload
,
with
:
.
none
)
}
}
}
1Weather/UI/View controllers/Today/Cells/CityConditions/CityConditionButton.swift
View file @
2d426c1d
...
@@ -7,35 +7,25 @@
...
@@ -7,35 +7,25 @@
import
UIKit
import
UIKit
enum
CityConditionButtonType
:
CaseIterable
{
case
precipitation
case
humidity
case
uvIndex
case
pressure
case
dewPoint
case
visibility
case
wind
}
class
CityConditionButton
:
UIControl
{
class
CityConditionButton
:
UIControl
{
//Private
//Private
private
let
buttonType
:
CityConditionButt
onType
private
let
conditionType
:
WeatherConditi
onType
private
let
imageView
=
UIImageView
()
private
let
imageView
=
UIImageView
()
private
let
valueLabel
=
UILabel
()
private
let
valueLabel
=
UILabel
()
private
let
nameLabel
=
UILabel
()
private
let
nameLabel
=
UILabel
()
private
let
descriptionLabel
=
UILabel
()
private
let
descriptionLabel
=
UILabel
()
init
(
type
:
CityConditionButt
onType
)
{
init
(
type
:
WeatherConditi
onType
)
{
self
.
butt
onType
=
type
self
.
conditi
onType
=
type
super
.
init
(
frame
:
.
zero
)
super
.
init
(
frame
:
.
zero
)
prepareButton
()
prepareButton
()
prepareImageView
(
type
:
type
)
prepareImageView
()
prepareLabels
(
type
:
type
)
prepareLabels
()
}
}
public
func
configure
(
with
location
:
Location
)
{
public
func
configure
(
with
location
:
Location
)
{
switch
butt
onType
{
switch
conditi
onType
{
case
.
precipitation
:
case
.
precipitation
:
valueLabel
.
text
=
"
\(
location
.
today
?
.
precipitationProbability
??
0
)
%"
valueLabel
.
text
=
"
\(
location
.
today
?
.
precipitationProbability
??
0
)
%"
case
.
humidity
:
case
.
humidity
:
...
@@ -55,44 +45,6 @@ class CityConditionButton: UIControl {
...
@@ -55,44 +45,6 @@ class CityConditionButton: UIControl {
}
}
}
}
private
func
image
(
for
type
:
CityConditionButtonType
)
->
UIImage
?
{
switch
type
{
case
.
precipitation
:
return
UIImage
(
named
:
"precipitation"
)
case
.
humidity
:
return
UIImage
(
named
:
"humidity"
)
case
.
uvIndex
:
return
UIImage
(
named
:
"uv_index"
)
case
.
pressure
:
return
UIImage
(
named
:
"pressure"
)
case
.
dewPoint
:
return
UIImage
(
named
:
"dewPoint"
)
case
.
visibility
:
return
UIImage
(
named
:
"visibility"
)
case
.
wind
:
return
UIImage
(
named
:
"blowingDust"
)
}
}
private
func
title
(
for
type
:
CityConditionButtonType
)
->
String
{
switch
type
{
case
.
precipitation
:
return
"condition.precipitation"
.
localized
()
case
.
humidity
:
return
"condition.humidity"
.
localized
()
case
.
uvIndex
:
return
"condition.uvIndex"
.
localized
()
case
.
pressure
:
return
"condition.pressure"
.
localized
()
case
.
dewPoint
:
return
"condition.dewPoint"
.
localized
()
case
.
visibility
:
return
"condition.visibility"
.
localized
()
case
.
wind
:
return
"condition.wind"
.
localized
()
}
}
required
init
?(
coder
:
NSCoder
)
{
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
fatalError
(
"init(coder:) has not been implemented"
)
}
}
...
@@ -110,11 +62,11 @@ private extension CityConditionButton {
...
@@ -110,11 +62,11 @@ private extension CityConditionButton {
self
.
layer
.
shadowRadius
=
20
self
.
layer
.
shadowRadius
=
20
}
}
func
prepareImageView
(
type
:
CityConditionButtonType
)
{
func
prepareImageView
()
{
imageView
.
isUserInteractionEnabled
=
false
imageView
.
isUserInteractionEnabled
=
false
imageView
.
contentMode
=
.
scaleAspectFit
imageView
.
contentMode
=
.
scaleAspectFit
imageView
.
clipsToBounds
=
true
imageView
.
clipsToBounds
=
true
imageView
.
image
=
image
(
for
:
type
)
imageView
.
image
=
conditionType
.
image
addSubview
(
imageView
)
addSubview
(
imageView
)
imageView
.
snp
.
makeConstraints
{
(
make
)
in
imageView
.
snp
.
makeConstraints
{
(
make
)
in
...
@@ -123,7 +75,7 @@ private extension CityConditionButton {
...
@@ -123,7 +75,7 @@ private extension CityConditionButton {
}
}
}
}
func
prepareLabels
(
type
:
CityConditionButtonType
)
{
func
prepareLabels
()
{
//Value
//Value
valueLabel
.
isUserInteractionEnabled
=
false
valueLabel
.
isUserInteractionEnabled
=
false
valueLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
18
)
valueLabel
.
font
=
AppFont
.
SFPro
.
bold
(
size
:
18
)
...
@@ -142,7 +94,7 @@ private extension CityConditionButton {
...
@@ -142,7 +94,7 @@ private extension CityConditionButton {
nameLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
16
)
nameLabel
.
font
=
AppFont
.
SFPro
.
regular
(
size
:
16
)
nameLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
nameLabel
.
textColor
=
ThemeManager
.
currentTheme
.
secondaryTextColor
nameLabel
.
textAlignment
=
.
left
nameLabel
.
textAlignment
=
.
left
nameLabel
.
text
=
title
(
for
:
type
)
nameLabel
.
text
=
conditionType
.
localized
addSubview
(
nameLabel
)
addSubview
(
nameLabel
)
nameLabel
.
snp
.
makeConstraints
{
(
make
)
in
nameLabel
.
snp
.
makeConstraints
{
(
make
)
in
...
...
1Weather/UI/View controllers/Today/Cells/CityConditions/CityConditionsCell.swift
View file @
2d426c1d
...
@@ -75,7 +75,7 @@ private extension CityConditionsCell {
...
@@ -75,7 +75,7 @@ private extension CityConditionsCell {
make
.
edges
.
height
.
equalToSuperview
()
make
.
edges
.
height
.
equalToSuperview
()
}
}
for
conditionType
in
CityConditionButt
onType
.
allCases
{
for
conditionType
in
WeatherConditi
onType
.
allCases
{
let
button
=
CityConditionButton
(
type
:
conditionType
)
let
button
=
CityConditionButton
(
type
:
conditionType
)
stackView
.
addArrangedSubview
(
button
)
stackView
.
addArrangedSubview
(
button
)
}
}
...
...
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipButton.swift
View file @
2d426c1d
...
@@ -16,7 +16,7 @@ class PrecipButton: UIControl {
...
@@ -16,7 +16,7 @@ class PrecipButton: UIControl {
return
fmt
return
fmt
}()
}()
private
let
valueLabel
=
UILabel
()
private
let
valueLabel
=
UILabel
()
private
let
precipView
=
PrecipView
()
private
let
precipView
=
Precip
itation
View
()
private
let
timeLabel
=
UILabel
()
private
let
timeLabel
=
UILabel
()
override
init
(
frame
:
CGRect
)
{
override
init
(
frame
:
CGRect
)
{
...
@@ -65,7 +65,7 @@ class PrecipButton: UIControl {
...
@@ -65,7 +65,7 @@ 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
Calendar
.
current
.
isDateInToday
(
daily
.
date
)
{
if
Calendar
.
timeZoneCalendar
(
timeZone
:
daily
.
timeZone
)
.
isDateInToday
(
daily
.
date
)
{
self
.
timeLabel
.
text
=
"day.today"
.
localized
()
self
.
timeLabel
.
text
=
"day.today"
.
localized
()
}
}
else
{
else
{
...
...
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/PrecipView.swift
→
1Weather/UI/View controllers/Today/Cells/CityPrecipCell/Precip
itation
View.swift
View file @
2d426c1d
//
//
// PrecipView.swift
// Precip
itation
View.swift
// 1Weather
// 1Weather
//
//
// Created by Dmitry Stepanets on 04.03.2021.
// Created by Dmitry Stepanets on 04.03.2021.
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
import
UIKit
import
UIKit
class
PrecipView
:
UIView
{
class
Precip
itation
View
:
UIView
{
//Private
//Private
private
let
kLevelWidth
:
CGFloat
=
12
private
let
kLevelWidth
:
CGFloat
=
12
private
let
kCapHeight
:
CGFloat
=
4
private
let
kCapHeight
:
CGFloat
=
4
...
@@ -60,7 +60,7 @@ class PrecipView: UIView {
...
@@ -60,7 +60,7 @@ class PrecipView: UIView {
}
}
//MARK:- Prepare
//MARK:- Prepare
private
extension
PrecipView
{
private
extension
Precip
itation
View
{
func
prepareView
()
{
func
prepareView
()
{
//Main
//Main
levelLayer
.
masksToBounds
=
true
levelLayer
.
masksToBounds
=
true
...
...
1Weather/ViewModels/ForecastViewModel.swift
View file @
2d426c1d
...
@@ -7,11 +7,15 @@
...
@@ -7,11 +7,15 @@
import
UIKit
import
UIKit
protocol
ForecastViewModelDelegate
:
ViewModelDelegate
{
func
selectedDailyWeatherDidChange
()
}
class
ForecastViewModel
:
ViewModelProtocol
{
class
ForecastViewModel
:
ViewModelProtocol
{
//Public
//Public
public
let
forecastCellFactory
=
ForecastCellFactory
()
public
weak
var
delegate
:
ForecastViewModelDelegate
?
public
weak
var
delegate
:
ViewModelDelegate
?
public
private(set)
var
location
:
Location
?
public
private(set)
var
location
:
Location
?
public
private(set)
var
selectedDailyWeather
:
DailyWeather
?
//Private
//Private
private
var
locationManager
:
LocationManager
private
var
locationManager
:
LocationManager
...
@@ -28,6 +32,21 @@ class ForecastViewModel: ViewModelProtocol {
...
@@ -28,6 +32,21 @@ class ForecastViewModel: ViewModelProtocol {
public
func
updateWeather
()
{
public
func
updateWeather
()
{
locationManager
.
updateWeather
()
locationManager
.
updateWeather
()
}
}
public
func
select
(
dailyWeather
:
DailyWeather
)
{
self
.
selectedDailyWeather
=
dailyWeather
self
.
delegate
?
.
selectedDailyWeatherDidChange
()
}
public
func
selectDailyWeather
(
at
index
:
Int
)
{
guard
let
daily
=
location
?
.
daily
else
{
return
}
daily
.
enumerated
()
.
forEach
{
if
$0
==
index
{
self
.
selectedDailyWeather
=
$1
}
}
self
.
delegate
?
.
selectedDailyWeatherDidChange
()
}
}
}
//MARK:- LocationManager Delegate
//MARK:- LocationManager Delegate
...
@@ -36,6 +55,7 @@ extension ForecastViewModel: LocationManagerDelegate {
...
@@ -36,6 +55,7 @@ extension ForecastViewModel: LocationManagerDelegate {
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
print
(
"TVM-Forecast"
)
print
(
"TVM-Forecast"
)
self
.
location
=
newLocation
self
.
location
=
newLocation
self
.
selectDailyWeather
(
at
:
0
)
self
.
delegate
?
.
viewModelDidChange
(
model
:
self
)
self
.
delegate
?
.
viewModelDidChange
(
model
:
self
)
}
}
}
}
...
...
Pods/Pods.xcodeproj/xcuserdata/dstepanets.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
2d426c1d
...
@@ -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