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
8118ec37
Commit
8118ec37
authored
Apr 28, 2021
by
Demid Merzlyakov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Onboarding (no privacy notice).
parent
862b5676
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
283 additions
and
26 deletions
+283
-26
1Weather.xcodeproj/project.pbxproj
+20
-0
1Weather/Coordinators/CoordinatorProtocol.swift
+1
-0
1Weather/Coordinators/LocationSearchCoordinator.swift
+4
-1
1Weather/Coordinators/OnboardingCoordinator.swift
+43
-0
1Weather/Coordinators/TodayCoordinator.swift
+31
-1
1Weather/Model/LocationManager.swift
+27
-1
1Weather/UI/View controllers/Locations/LocationViewController.swift
+31
-21
1Weather/UI/View controllers/Onboarding/OnboardingViewController.swift
+74
-0
1Weather/UI/View controllers/Today/TodayViewController.swift
+18
-1
1Weather/ViewModels/OnboardingViewModel.swift
+21
-0
1Weather/ViewModels/TodayViewModel.swift
+13
-1
No files found.
1Weather.xcodeproj/project.pbxproj
View file @
8118ec37
...
@@ -251,6 +251,9 @@
...
@@ -251,6 +251,9 @@
CEC5270325E7BB4000DA58A5
/* WdtSurfaceObservation.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5270225E7BB4000DA58A5
/* WdtSurfaceObservation.swift */
;
};
CEC5270325E7BB4000DA58A5
/* WdtSurfaceObservation.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5270225E7BB4000DA58A5
/* WdtSurfaceObservation.swift */
;
};
CEC5275D25E8E50B00DA58A5
/* WdtDailySummary.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5275C25E8E50B00DA58A5
/* WdtDailySummary.swift */
;
};
CEC5275D25E8E50B00DA58A5
/* WdtDailySummary.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5275C25E8E50B00DA58A5
/* WdtDailySummary.swift */
;
};
CEC5276025E92DDA00DA58A5
/* WdtHourlySummary.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5275F25E92DDA00DA58A5
/* WdtHourlySummary.swift */
;
};
CEC5276025E92DDA00DA58A5
/* WdtHourlySummary.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5275F25E92DDA00DA58A5
/* WdtHourlySummary.swift */
;
};
CEC8FBAF2639756A0001A6BF
/* OnboardingViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBAE2639756A0001A6BF
/* OnboardingViewController.swift */
;
};
CEC8FBB2263976240001A6BF
/* OnboardingCoordinator.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBB1263976240001A6BF
/* OnboardingCoordinator.swift */
;
};
CEC8FBB5263976400001A6BF
/* OnboardingViewModel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBB4263976400001A6BF
/* OnboardingViewModel.swift */
;
};
CEDE4E8225EEFD56007457E9
/* WdtWeatherCode.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEDE4E7E25EEFD56007457E9
/* WdtWeatherCode.swift */
;
};
CEDE4E8225EEFD56007457E9
/* WdtWeatherCode.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEDE4E7E25EEFD56007457E9
/* WdtWeatherCode.swift */
;
};
CEDE4E8325EEFD56007457E9
/* WdtLocationResponse.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEDE4E7F25EEFD56007457E9
/* WdtLocationResponse.swift */
;
};
CEDE4E8325EEFD56007457E9
/* WdtLocationResponse.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEDE4E7F25EEFD56007457E9
/* WdtLocationResponse.swift */
;
};
CEDE4E8425EEFD56007457E9
/* WdtDailySummariesArray.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEDE4E8025EEFD56007457E9
/* WdtDailySummariesArray.swift */
;
};
CEDE4E8425EEFD56007457E9
/* WdtDailySummariesArray.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEDE4E8025EEFD56007457E9
/* WdtDailySummariesArray.swift */
;
};
...
@@ -570,6 +573,9 @@
...
@@ -570,6 +573,9 @@
CEC5270225E7BB4000DA58A5
/* WdtSurfaceObservation.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtSurfaceObservation.swift
;
sourceTree
=
"<group>"
;
};
CEC5270225E7BB4000DA58A5
/* WdtSurfaceObservation.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtSurfaceObservation.swift
;
sourceTree
=
"<group>"
;
};
CEC5275C25E8E50B00DA58A5
/* WdtDailySummary.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtDailySummary.swift
;
sourceTree
=
"<group>"
;
};
CEC5275C25E8E50B00DA58A5
/* WdtDailySummary.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtDailySummary.swift
;
sourceTree
=
"<group>"
;
};
CEC5275F25E92DDA00DA58A5
/* WdtHourlySummary.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtHourlySummary.swift
;
sourceTree
=
"<group>"
;
};
CEC5275F25E92DDA00DA58A5
/* WdtHourlySummary.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtHourlySummary.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBAE2639756A0001A6BF
/* OnboardingViewController.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingViewController.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBB1263976240001A6BF
/* OnboardingCoordinator.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingCoordinator.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBB4263976400001A6BF
/* OnboardingViewModel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingViewModel.swift
;
sourceTree
=
"<group>"
;
};
CEDE4E7E25EEFD56007457E9
/* WdtWeatherCode.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtWeatherCode.swift
;
sourceTree
=
"<group>"
;
};
CEDE4E7E25EEFD56007457E9
/* WdtWeatherCode.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtWeatherCode.swift
;
sourceTree
=
"<group>"
;
};
CEDE4E7F25EEFD56007457E9
/* WdtLocationResponse.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtLocationResponse.swift
;
sourceTree
=
"<group>"
;
};
CEDE4E7F25EEFD56007457E9
/* WdtLocationResponse.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtLocationResponse.swift
;
sourceTree
=
"<group>"
;
};
CEDE4E8025EEFD56007457E9
/* WdtDailySummariesArray.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtDailySummariesArray.swift
;
sourceTree
=
"<group>"
;
};
CEDE4E8025EEFD56007457E9
/* WdtDailySummariesArray.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtDailySummariesArray.swift
;
sourceTree
=
"<group>"
;
};
...
@@ -764,6 +770,7 @@
...
@@ -764,6 +770,7 @@
CE0457942632B3F900B3C19A
/* NotificationsCoordinator.swift */
,
CE0457942632B3F900B3C19A
/* NotificationsCoordinator.swift */
,
87D815A92636D5E60015A6D1
/* NWSAlertCoordinator.swift */
,
87D815A92636D5E60015A6D1
/* NWSAlertCoordinator.swift */
,
CD7BF1572620410800A30DF5
/* RadarCoordinator.swift */
,
CD7BF1572620410800A30DF5
/* RadarCoordinator.swift */
,
CEC8FBB1263976240001A6BF
/* OnboardingCoordinator.swift */
,
);
);
path
=
Coordinators
;
path
=
Coordinators
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
@@ -869,6 +876,7 @@
...
@@ -869,6 +876,7 @@
CE04578F2632B3BC00B3C19A
/* NotificationsViewModel.swift */
,
CE04578F2632B3BC00B3C19A
/* NotificationsViewModel.swift */
,
87D815AB2636D61D0015A6D1
/* NWSAlertViewModel.swift */
,
87D815AB2636D61D0015A6D1
/* NWSAlertViewModel.swift */
,
CD6761872625C3360079D273
/* RadarViewModel.swift */
,
CD6761872625C3360079D273
/* RadarViewModel.swift */
,
CEC8FBB4263976400001A6BF
/* OnboardingViewModel.swift */
,
);
);
path
=
ViewModels
;
path
=
ViewModels
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
@@ -894,6 +902,7 @@
...
@@ -894,6 +902,7 @@
CD6B3038257267E2004B34B3
/* View controllers */
=
{
CD6B3038257267E2004B34B3
/* View controllers */
=
{
isa
=
PBXGroup
;
isa
=
PBXGroup
;
children
=
(
children
=
(
CEC8FBAD263975170001A6BF
/* Onboarding */
,
CD8B60AF263819780055CB3F
/* Notifications */
,
CD8B60AF263819780055CB3F
/* Notifications */
,
CD8B60A5263819400055CB3F
/* NWSAlert */
,
CD8B60A5263819400055CB3F
/* NWSAlert */
,
CD17C5F425D15B3400EE884E
/* Today */
,
CD17C5F425D15B3400EE884E
/* Today */
,
...
@@ -1493,6 +1502,14 @@
...
@@ -1493,6 +1502,14 @@
path
=
ModelObjects
;
path
=
ModelObjects
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
};
};
CEC8FBAD263975170001A6BF
/* Onboarding */
=
{
isa
=
PBXGroup
;
children
=
(
CEC8FBAE2639756A0001A6BF
/* OnboardingViewController.swift */
,
);
path
=
Onboarding
;
sourceTree
=
"<group>"
;
};
CEDE4E7D25EEFD56007457E9
/* HelperObjects */
=
{
CEDE4E7D25EEFD56007457E9
/* HelperObjects */
=
{
isa
=
PBXGroup
;
isa
=
PBXGroup
;
children
=
(
children
=
(
...
@@ -1903,6 +1920,7 @@
...
@@ -1903,6 +1920,7 @@
CD43DF032636C6640010C9F7
/* CACornerMask+All.swift in Sources */
,
CD43DF032636C6640010C9F7
/* CACornerMask+All.swift in Sources */
,
CDC6124F25E7964700188DA7
/* TodayDayTimesCell.swift in Sources */
,
CDC6124F25E7964700188DA7
/* TodayDayTimesCell.swift in Sources */
,
CD593BC226088A5900C93428
/* TimePeriodOffsetHolder.swift in Sources */
,
CD593BC226088A5900C93428
/* TimePeriodOffsetHolder.swift in Sources */
,
CEC8FBB5263976400001A6BF
/* OnboardingViewModel.swift in Sources */
,
CE8962A226175DF500CA274A
/* _CoreAirQuality.swift in Sources */
,
CE8962A226175DF500CA274A
/* _CoreAirQuality.swift in Sources */
,
CD17C5FB25D15B6B00EE884E
/* AppCoordinator.swift in Sources */
,
CD17C5FB25D15B6B00EE884E
/* AppCoordinator.swift in Sources */
,
CDAD97B426207D14007FCFB1
/* MapTimeControlView.swift in Sources */
,
CDAD97B426207D14007FCFB1
/* MapTimeControlView.swift in Sources */
,
...
@@ -1922,6 +1940,7 @@
...
@@ -1922,6 +1940,7 @@
CEF959652600C2F900975FAA
/* AnalyticsService.swift in Sources */
,
CEF959652600C2F900975FAA
/* AnalyticsService.swift in Sources */
,
CD39F2F225DE94C4009FE398
/* SunPhaseCell.swift in Sources */
,
CD39F2F225DE94C4009FE398
/* SunPhaseCell.swift in Sources */
,
CD6B304325726AD1004B34B3
/* DefaultTheme.swift in Sources */
,
CD6B304325726AD1004B34B3
/* DefaultTheme.swift in Sources */
,
CEC8FBB2263976240001A6BF
/* OnboardingCoordinator.swift in Sources */
,
CD8B60B626381E0F0055CB3F
/* AdsUserDefaultsWrapper.swift in Sources */
,
CD8B60B626381E0F0055CB3F
/* AdsUserDefaultsWrapper.swift in Sources */
,
CD9B6B1425DBCDE2001D9B80
/* GraphView.swift in Sources */
,
CD9B6B1425DBCDE2001D9B80
/* GraphView.swift in Sources */
,
CD39F2EE25DE858D009FE398
/* NotificationName+Localization.swift in Sources */
,
CD39F2EE25DE858D009FE398
/* NotificationName+Localization.swift in Sources */
,
...
@@ -2001,6 +2020,7 @@
...
@@ -2001,6 +2020,7 @@
CEC5270025E7BACB00DA58A5
/* WdtLocation.swift in Sources */
,
CEC5270025E7BACB00DA58A5
/* WdtLocation.swift in Sources */
,
CE8962A726175DF500CA274A
/* _CoreLocation.swift in Sources */
,
CE8962A726175DF500CA274A
/* _CoreLocation.swift in Sources */
,
CD67617026259D220079D273
/* RadarMapLayersController.swift in Sources */
,
CD67617026259D220079D273
/* RadarMapLayersController.swift in Sources */
,
CEC8FBAF2639756A0001A6BF
/* OnboardingViewController.swift in Sources */
,
CD866A65260F642600E96A5C
/* SettingsDetailsViewController.swift in Sources */
,
CD866A65260F642600E96A5C
/* SettingsDetailsViewController.swift in Sources */
,
CD647D0225ED07D60034578B
/* TodayViewModel.swift in Sources */
,
CD647D0225ED07D60034578B
/* TodayViewModel.swift in Sources */
,
CD593BD32608BC3F00C93428
/* ForecastDayCell.swift in Sources */
,
CD593BD32608BC3F00C93428
/* ForecastDayCell.swift in Sources */
,
...
...
1Weather/Coordinators/CoordinatorProtocol.swift
View file @
8118ec37
...
@@ -13,6 +13,7 @@ protocol Coordinator: AnyObject {
...
@@ -13,6 +13,7 @@ protocol Coordinator: AnyObject {
var
parentCoordinator
:
Coordinator
?
{
get
set
}
var
parentCoordinator
:
Coordinator
?
{
get
set
}
func
start
()
func
start
()
func
viewControllerDidEnd
(
controller
:
UIViewController
)
func
viewControllerDidEnd
(
controller
:
UIViewController
)
func
childDidFinish
(
child
:
Coordinator
)
}
}
extension
Coordinator
{
extension
Coordinator
{
...
...
1Weather/Coordinators/LocationSearchCoordinator.swift
View file @
8118ec37
...
@@ -14,14 +14,17 @@ class LocationSearchCoordinator: Coordinator {
...
@@ -14,14 +14,17 @@ class LocationSearchCoordinator: Coordinator {
//Public
//Public
var
childCoordinators
=
[
Coordinator
]()
var
childCoordinators
=
[
Coordinator
]()
var
parentCoordinator
:
Coordinator
?
var
parentCoordinator
:
Coordinator
?
let
fromOnboarding
:
Bool
init
(
parentViewController
:
UIViewController
)
{
init
(
parentViewController
:
UIViewController
,
fromOnboarding
:
Bool
=
false
)
{
self
.
parentViewController
=
parentViewController
self
.
parentViewController
=
parentViewController
self
.
fromOnboarding
=
fromOnboarding
}
}
func
start
()
{
func
start
()
{
let
searchViewController
=
LocationViewController
(
coordinator
:
self
)
let
searchViewController
=
LocationViewController
(
coordinator
:
self
)
searchViewController
.
openedFromOnboarding
=
fromOnboarding
let
navigationController
=
UINavigationController
(
rootViewController
:
searchViewController
)
let
navigationController
=
UINavigationController
(
rootViewController
:
searchViewController
)
self
.
parentViewController
.
present
(
navigationController
,
animated
:
true
)
self
.
parentViewController
.
present
(
navigationController
,
animated
:
true
)
}
}
...
...
1Weather/Coordinators/OnboardingCoordinator.swift
0 → 100644
View file @
8118ec37
//
// OnboardingCoordinator.swift
// 1Weather
//
// Created by Demid Merzlyakov on 28.04.2021.
//
import
UIKit
class
OnboardingCoordinator
:
Coordinator
{
private
let
parentViewController
:
UIViewController
public
var
childCoordinators
=
[
Coordinator
]()
public
var
parentCoordinator
:
Coordinator
?
private
let
locationManager
:
LocationManager
private
var
onboardingViewController
:
OnboardingViewController
?
init
(
parentViewController
:
UIViewController
,
locationManager
:
LocationManager
=
LocationManager
.
shared
)
{
self
.
parentViewController
=
parentViewController
self
.
locationManager
=
locationManager
}
public
func
start
()
{
onboardingViewController
=
OnboardingViewController
(
coordinator
:
self
,
locationManager
:
locationManager
)
onboardingViewController
?
.
modalPresentationStyle
=
.
overFullScreen
onboardingViewController
?
.
modalTransitionStyle
=
.
crossDissolve
if
let
onboardingViewController
=
onboardingViewController
{
parentViewController
.
present
(
onboardingViewController
,
animated
:
true
)
}
}
public
func
openLocationsSearch
()
{
guard
let
onboardingViewController
=
self
.
onboardingViewController
else
{
return
}
let
searchCoordinator
=
LocationSearchCoordinator
(
parentViewController
:
onboardingViewController
,
fromOnboarding
:
true
)
searchCoordinator
.
parentCoordinator
=
self
searchCoordinator
.
start
()
}
func
viewControllerDidEnd
(
controller
:
UIViewController
)
{
parentCoordinator
?
.
childDidFinish
(
child
:
self
)
}
}
1Weather/Coordinators/TodayCoordinator.swift
View file @
8118ec37
...
@@ -7,12 +7,18 @@
...
@@ -7,12 +7,18 @@
import
UIKit
import
UIKit
protocol
TodayCoordinatorDelegate
:
class
{
func
childCoordinatorDidFinish
(
in
coordinator
:
TodayCoordinator
)
}
class
TodayCoordinator
:
Coordinator
{
class
TodayCoordinator
:
Coordinator
{
// MARK: - Private
// MARK: - Private
private
let
navigationController
=
UINavigationController
(
nibName
:
nil
,
bundle
:
nil
)
private
let
navigationController
=
UINavigationController
(
nibName
:
nil
,
bundle
:
nil
)
private
var
tabBarController
:
UITabBarController
?
private
var
tabBarController
:
UITabBarController
?
var
todayViewController
:
TodayViewController
?
// MARK: - Public
// MARK: - Public
public
weak
var
delegate
:
TodayCoordinatorDelegate
?
public
var
childCoordinators
=
[
Coordinator
]()
public
var
childCoordinators
=
[
Coordinator
]()
public
var
parentCoordinator
:
Coordinator
?
public
var
parentCoordinator
:
Coordinator
?
...
@@ -21,7 +27,11 @@ class TodayCoordinator: Coordinator {
...
@@ -21,7 +27,11 @@ class TodayCoordinator: Coordinator {
}
}
public
func
start
()
{
public
func
start
()
{
let
todayViewController
=
TodayViewController
(
coordinator
:
self
)
todayViewController
=
TodayViewController
(
coordinator
:
self
)
self
.
delegate
=
todayViewController
guard
let
todayViewController
=
self
.
todayViewController
else
{
return
}
navigationController
.
viewControllers
=
[
todayViewController
]
navigationController
.
viewControllers
=
[
todayViewController
]
tabBarController
?
.
add
(
viewController
:
navigationController
)
tabBarController
?
.
add
(
viewController
:
navigationController
)
}
}
...
@@ -38,7 +48,27 @@ class TodayCoordinator: Coordinator {
...
@@ -38,7 +48,27 @@ class TodayCoordinator: Coordinator {
notificationsCoordinator
.
start
()
notificationsCoordinator
.
start
()
}
}
public
func
openOnboarding
()
{
guard
let
todayViewController
=
self
.
todayViewController
else
{
return
}
let
onboardingCoordinator
=
OnboardingCoordinator
(
parentViewController
:
todayViewController
,
locationManager
:
LocationManager
.
shared
)
// get rid of singleton
onboardingCoordinator
.
parentCoordinator
=
self
onboardingCoordinator
.
start
()
}
public
func
viewControllerDidEnd
(
controller
:
UIViewController
)
{
public
func
viewControllerDidEnd
(
controller
:
UIViewController
)
{
parentCoordinator
?
.
childDidFinish
(
child
:
self
)
}
func
childDidFinish
(
child
:
Coordinator
)
{
self
.
delegate
?
.
childCoordinatorDidFinish
(
in
:
self
)
for
(
index
,
coordinator
)
in
childCoordinators
.
enumerated
()
{
if
coordinator
===
child
{
childCoordinators
.
remove
(
at
:
index
)
break
}
}
}
}
}
}
1Weather/Model/LocationManager.swift
View file @
8118ec37
...
@@ -175,6 +175,18 @@ public class LocationManager {
...
@@ -175,6 +175,18 @@ public class LocationManager {
storage
:
DelayedSaveStorage
(
storage
:
CoreDataStorage
(),
delay
:
2
))
storage
:
DelayedSaveStorage
(
storage
:
CoreDataStorage
(),
delay
:
2
))
public
let
maxLocationsCount
=
12
public
let
maxLocationsCount
=
12
private
var
loadedLocations
=
false
private
var
actionAfterLocationLoad
:
(([
Location
])
->
())?
public
func
doAfterLocationLoad
(
_
action
:
@escaping
([
Location
])
->
())
{
DispatchQueue
.
main
.
async
{
if
self
.
loadedLocations
{
action
(
self
.
locations
)
}
else
{
self
.
actionAfterLocationLoad
=
action
}
}
}
public
init
(
weatherUpdateSource
:
WeatherSource
,
healthSource
:
HealthSource
,
nwsAlertsManager
:
NWSAlertsManager
,
fipsSource
:
FIPSSource
,
pushNotificationsManager
:
PushNotificationsManager
,
storage
:
Storage
)
{
public
init
(
weatherUpdateSource
:
WeatherSource
,
healthSource
:
HealthSource
,
nwsAlertsManager
:
NWSAlertsManager
,
fipsSource
:
FIPSSource
,
pushNotificationsManager
:
PushNotificationsManager
,
storage
:
Storage
)
{
self
.
weatherUpdateSource
=
weatherUpdateSource
self
.
weatherUpdateSource
=
weatherUpdateSource
...
@@ -191,16 +203,30 @@ public class LocationManager {
...
@@ -191,16 +203,30 @@ public class LocationManager {
storage
.
load
{
[
weak
self
]
(
locations
,
selectedIndex
,
error
)
in
storage
.
load
{
[
weak
self
]
(
locations
,
selectedIndex
,
error
)
in
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
guard
let
self
=
self
else
{
return
}
guard
let
self
=
self
else
{
return
}
defer
{
self
.
actionAfterLocationLoad
?(
self
.
locations
)
}
self
.
loadedLocations
=
true
guard
error
==
nil
else
{
guard
error
==
nil
else
{
self
.
log
.
error
(
"Error while loading locations:
\(
error
!
)
"
)
self
.
log
.
error
(
"Error while loading locations:
\(
error
!
)
"
)
return
return
}
}
guard
let
locations
=
locations
else
{
guard
var
locations
=
locations
else
{
assertionFailure
(
"Either error or locations have to be nil, not both"
)
assertionFailure
(
"Either error or locations have to be nil, not both"
)
return
return
}
}
if
locations
.
first
?
.
deviceLocation
==
true
&&
!
self
.
deviceLocationMonitor
.
hasLocationPermissions
{
locations
.
removeFirst
()
}
self
.
nwsAlertsManager
.
loadAlerts
(
from
:
locations
)
self
.
nwsAlertsManager
.
loadAlerts
(
from
:
locations
)
self
.
set
(
locations
:
locations
,
selectedIndex
:
selectedIndex
)
self
.
set
(
locations
:
locations
,
selectedIndex
:
selectedIndex
)
if
self
.
deviceLocationMonitor
.
hasLocationPermissions
{
if
locations
.
first
?
.
deviceLocation
!=
true
{
if
let
lastKnownLocation
=
self
.
deviceLocationMonitor
.
lastKnownLocation
{
self
.
addIfNeeded
(
partialLocation
:
lastKnownLocation
,
selectLocation
:
false
)
}
}
}
}
}
}
}
}
}
...
...
1Weather/UI/View controllers/Locations/LocationViewController.swift
View file @
8118ec37
...
@@ -21,6 +21,7 @@ class LocationViewController:UIViewController {
...
@@ -21,6 +21,7 @@ class LocationViewController:UIViewController {
return
queue
return
queue
}()
}()
public
var
openedFromOnboarding
:
Bool
=
false
init
(
coordinator
:
LocationSearchCoordinator
)
{
init
(
coordinator
:
LocationSearchCoordinator
)
{
self
.
coordinator
=
coordinator
self
.
coordinator
=
coordinator
...
@@ -55,10 +56,9 @@ class LocationViewController:UIViewController {
...
@@ -55,10 +56,9 @@ class LocationViewController:UIViewController {
override
func
viewDidAppear
(
_
animated
:
Bool
)
{
override
func
viewDidAppear
(
_
animated
:
Bool
)
{
super
.
viewDidAppear
(
animated
)
super
.
viewDidAppear
(
animated
)
#warning("TODO Flurry analytics")
if
openedFromOnboarding
{
// if openedFromOnboarding {
analytics
(
log
:
.
ANALYTICS_FTUE_SEARCH_SEEN
)
// analytics(log: .ANALYTICS_FTUE_SEARCH_SEEN)
}
// }
}
}
override
func
traitCollectionDidChange
(
_
previousTraitCollection
:
UITraitCollection
?)
{
override
func
traitCollectionDidChange
(
_
previousTraitCollection
:
UITraitCollection
?)
{
...
@@ -67,7 +67,10 @@ class LocationViewController:UIViewController {
...
@@ -67,7 +67,10 @@ class LocationViewController:UIViewController {
}
}
private
func
close
()
{
private
func
close
()
{
self
.
navigationController
?
.
dismiss
(
animated
:
true
)
self
.
navigationController
?
.
dismiss
(
animated
:
true
,
completion
:
{
[
weak
self
]
in
guard
let
self
=
self
else
{
return
}
self
.
coordinator
.
viewControllerDidEnd
(
controller
:
self
)
})
}
}
private
func
updateUI
()
{
private
func
updateUI
()
{
...
@@ -91,10 +94,9 @@ class LocationViewController:UIViewController {
...
@@ -91,10 +94,9 @@ class LocationViewController:UIViewController {
}
}
@objc
private
func
handleLocationButton
()
{
@objc
private
func
handleLocationButton
()
{
#warning("TODO Flurry analytics")
if
openedFromOnboarding
{
// if openedFromOnboarding {
analytics
(
log
:
.
ANALYTICS_FTUE_SEARCH_GPS
)
// analytics(log: .ANALYTICS_FTUE_SEARCH_GPS)
}
// }
locationsViewModel
.
useCurrentLocation
(
requestedBy
:
self
)
locationsViewModel
.
useCurrentLocation
(
requestedBy
:
self
)
}
}
}
}
...
@@ -103,12 +105,23 @@ class LocationViewController:UIViewController {
...
@@ -103,12 +105,23 @@ class LocationViewController:UIViewController {
private
extension
LocationViewController
{
private
extension
LocationViewController
{
func
prepareController
()
{
func
prepareController
()
{
navigationItem
.
title
=
"search.title"
.
localized
()
.
capitalized
navigationItem
.
title
=
"search.title"
.
localized
()
.
capitalized
if
openedFromOnboarding
{
if
#available(iOS 13, *)
{
self
.
isModalInPresentation
=
true
}
navigationItem
.
leftBarButtonItem
=
nil
}
else
{
if
#available(iOS 13, *)
{
self
.
isModalInPresentation
=
false
}
let
closeButton
=
UIBarButtonItem
(
title
:
"general.close"
.
localized
()
.
capitalized
,
let
closeButton
=
UIBarButtonItem
(
title
:
"general.close"
.
localized
()
.
capitalized
,
style
:
.
done
,
style
:
.
done
,
target
:
self
,
target
:
self
,
action
:
#selector(
handleCloseButton
)
)
action
:
#selector(
handleCloseButton
)
)
navigationItem
.
leftBarButtonItem
=
closeButton
navigationItem
.
leftBarButtonItem
=
closeButton
}
}
}
func
prepareSearchBar
()
{
func
prepareSearchBar
()
{
searchBar
.
searchBarStyle
=
.
minimal
searchBar
.
searchBarStyle
=
.
minimal
...
@@ -342,16 +355,14 @@ extension LocationViewController: UITableViewDelegate {
...
@@ -342,16 +355,14 @@ extension LocationViewController: UITableViewDelegate {
locationsViewModel
.
select
(
city
:
locationsViewModel
.
cities
[
indexPath
.
row
])
locationsViewModel
.
select
(
city
:
locationsViewModel
.
cities
[
indexPath
.
row
])
case
.
searchResults
:
case
.
searchResults
:
locationsViewModel
.
add
(
city
:
locationsViewModel
.
cities
[
indexPath
.
row
])
locationsViewModel
.
add
(
city
:
locationsViewModel
.
cities
[
indexPath
.
row
])
#warning("TODO Flurry analytics")
if
openedFromOnboarding
{
// if openedFromOnboarding {
analytics
(
log
:
.
ANALYTICS_FTUE_SEARCH_ADD
)
// analytics(log: .ANALYTICS_FTUE_SEARCH_ADD)
}
// }
case
.
popularCities
:
case
.
popularCities
:
locationsViewModel
.
add
(
city
:
locationsViewModel
.
cities
[
indexPath
.
row
])
locationsViewModel
.
add
(
city
:
locationsViewModel
.
cities
[
indexPath
.
row
])
#warning("TODO Flurry analytics")
if
openedFromOnboarding
{
// if openedFromOnboarding {
analytics
(
log
:
.
ANALYTICS_FTUE_SEARCH_POPULAR
)
// analytics(log: .ANALYTICS_FTUE_SEARCH_POPULAR)
}
// }
}
}
}
}
}
}
...
@@ -362,10 +373,9 @@ extension LocationViewController: UISearchBarDelegate {
...
@@ -362,10 +373,9 @@ extension LocationViewController: UISearchBarDelegate {
searchBar
.
setShowsCancelButton
(
true
,
animated
:
true
)
searchBar
.
setShowsCancelButton
(
true
,
animated
:
true
)
self
.
locationsViewModel
.
displayMode
=
.
popularCities
self
.
locationsViewModel
.
displayMode
=
.
popularCities
self
.
locationsViewModel
.
fetchPopularCities
()
self
.
locationsViewModel
.
fetchPopularCities
()
#warning("TODO Flurry analytics")
if
openedFromOnboarding
{
// if openedFromOnboarding {
analytics
(
log
:
.
ANALYTICS_FTUE_SEARCH_TAP
)
// analytics(log: .ANALYTICS_FTUE_SEARCH_TAP)
}
// }
}
}
func
searchBar
(
_
searchBar
:
UISearchBar
,
textDidChange
searchText
:
String
)
{
func
searchBar
(
_
searchBar
:
UISearchBar
,
textDidChange
searchText
:
String
)
{
...
...
1Weather/UI/View controllers/Onboarding/OnboardingViewController.swift
0 → 100644
View file @
8118ec37
//
// OnboardingViewController.swift
// 1Weather
//
// Created by Demid Merzlyakov on 28.04.2021.
//
import
UIKit
class
OnboardingViewController
:
UIViewController
{
private
let
coordinator
:
OnboardingCoordinator
private
let
locationManager
:
LocationManager
init
(
coordinator
:
OnboardingCoordinator
,
locationManager
:
LocationManager
)
{
self
.
coordinator
=
coordinator
self
.
locationManager
=
locationManager
super
.
init
(
nibName
:
nil
,
bundle
:
nil
)
self
.
locationManager
.
add
(
delegate
:
self
)
self
.
title
=
""
}
@available(*, unavailable)
required
init
?(
coder
:
NSCoder
)
{
return
nil
}
override
func
viewDidLoad
()
{
prepareBackground
()
}
override
func
viewDidAppear
(
_
animated
:
Bool
)
{
super
.
viewDidAppear
(
animated
)
promptForLocationAccess
()
}
private
func
close
(
animated
:
Bool
)
{
self
.
presentingViewController
?
.
dismiss
(
animated
:
animated
,
completion
:
{
[
weak
self
]
in
guard
let
self
=
self
else
{
return
}
self
.
coordinator
.
viewControllerDidEnd
(
controller
:
self
)
})
}
private
func
promptForLocationAccess
()
{
locationManager
.
useCurrentLocation
(
presentDialogsIn
:
self
)
{
[
weak
self
]
(
result
)
in
guard
let
self
=
self
else
{
return
}
switch
result
{
case
.
success
:
self
.
close
(
animated
:
true
)
case
.
denied
:
self
.
coordinator
.
openLocationsSearch
()
case
.
useSearch
:
self
.
coordinator
.
openLocationsSearch
()
}
}
}
//MARK: - UI Preparation
private
func
prepareBackground
()
{
view
.
backgroundColor
=
UIColor
.
black
.
withAlphaComponent
(
0.79
)
view
.
isOpaque
=
false
}
}
extension
OnboardingViewController
:
LocationManagerDelegate
{
func
locationManager
(
_
locationManager
:
LocationManager
,
changedSelectedLocation
newLocation
:
Location
?)
{
// do nothing
}
func
locationManager
(
_
locationManager
:
LocationManager
,
updatedLocationsList
newList
:
[
Location
])
{
if
newList
.
count
>
0
{
close
(
animated
:
true
)
}
}
}
1Weather/UI/View controllers/Today/TodayViewController.swift
View file @
8118ec37
...
@@ -45,6 +45,11 @@ class TodayViewController: UIViewController {
...
@@ -45,6 +45,11 @@ class TodayViewController: UIViewController {
viewModel
.
updateWeather
()
viewModel
.
updateWeather
()
}
}
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
viewModel
.
showOnboardingIfNeeded
()
}
override
func
viewWillTransition
(
to
size
:
CGSize
,
with
coordinator
:
UIViewControllerTransitionCoordinator
)
{
override
func
viewWillTransition
(
to
size
:
CGSize
,
with
coordinator
:
UIViewControllerTransitionCoordinator
)
{
super
.
viewWillTransition
(
to
:
size
,
with
:
coordinator
)
super
.
viewWillTransition
(
to
:
size
,
with
:
coordinator
)
...
@@ -138,7 +143,11 @@ extension TodayViewController: UITableViewDelegate {
...
@@ -138,7 +143,11 @@ extension TodayViewController: UITableViewDelegate {
}
}
//MARK:- ViewModel Delegate
//MARK:- ViewModel Delegate
extension
TodayViewController
:
ViewModelDelegate
{
extension
TodayViewController
:
TodayViewModelDelegate
{
func
showOnboarding
(
viewModel
:
TodayViewModel
)
{
coordinator
.
openOnboarding
()
}
func
viewModelDidChange
<
P
>
(
model
:
P
)
where
P
:
ViewModelProtocol
{
func
viewModelDidChange
<
P
>
(
model
:
P
)
where
P
:
ViewModelProtocol
{
cityButton
.
configure
(
with
:
viewModel
.
location
)
cityButton
.
configure
(
with
:
viewModel
.
location
)
cityButton
.
isHidden
=
false
cityButton
.
isHidden
=
false
...
@@ -146,3 +155,11 @@ extension TodayViewController: ViewModelDelegate {
...
@@ -146,3 +155,11 @@ extension TodayViewController: ViewModelDelegate {
tableView
.
reloadData
()
tableView
.
reloadData
()
}
}
}
}
// MARK: - TodayCoordinatorDelegate
extension
TodayViewController
:
TodayCoordinatorDelegate
{
func
childCoordinatorDidFinish
(
in
coordinator
:
TodayCoordinator
)
{
viewModel
.
showOnboardingIfNeeded
()
}
}
1Weather/ViewModels/OnboardingViewModel.swift
0 → 100644
View file @
8118ec37
//
// OnboardingViewModel.swift
// 1Weather
//
// Created by Demid Merzlyakov on 28.04.2021.
//
import
UIKit
protocol
OnboardingViewModelDelegate
:
ViewModelDelegate
{
func
viewModelAsksToOpenSearch
(
_
viewModel
:
OnboardingViewController
)
}
class
OnboardingViewModel
:
ViewModelProtocol
{
public
weak
var
delegate
:
OnboardingViewModelDelegate
?
private
let
locationManager
:
LocationManager
public
init
(
locationManager
:
LocationManager
)
{
self
.
locationManager
=
locationManager
}
}
1Weather/ViewModels/TodayViewModel.swift
View file @
8118ec37
...
@@ -7,9 +7,13 @@
...
@@ -7,9 +7,13 @@
import
UIKit
import
UIKit
protocol
TodayViewModelDelegate
:
ViewModelDelegate
{
func
showOnboarding
(
viewModel
:
TodayViewModel
)
}
class
TodayViewModel
:
ViewModelProtocol
{
class
TodayViewModel
:
ViewModelProtocol
{
//Public
//Public
public
weak
var
delegate
:
ViewModelDelegate
?
public
weak
var
delegate
:
Today
ViewModelDelegate
?
//Private
//Private
private
let
locationManager
=
LocationManager
.
shared
private
let
locationManager
=
LocationManager
.
shared
...
@@ -33,6 +37,14 @@ class TodayViewModel: ViewModelProtocol {
...
@@ -33,6 +37,14 @@ class TodayViewModel: ViewModelProtocol {
public
func
updateWeather
()
{
public
func
updateWeather
()
{
locationManager
.
updateEverythingIfNeeded
()
locationManager
.
updateEverythingIfNeeded
()
}
}
public
func
showOnboardingIfNeeded
()
{
locationManager
.
doAfterLocationLoad
{
(
locations
)
in
if
locations
.
count
==
0
{
self
.
delegate
?
.
showOnboarding
(
viewModel
:
self
)
}
}
}
}
}
//MARK:- LocationManager Delegate
//MARK:- LocationManager Delegate
...
...
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