Commit 8118ec37 by Demid Merzlyakov

Onboarding (no privacy notice).

parent 862b5676
...@@ -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 */,
......
...@@ -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 {
......
...@@ -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)
} }
......
//
// 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)
}
}
...@@ -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
}
}
} }
} }
...@@ -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)
}
}
}
} }
} }
} }
......
...@@ -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,11 +105,22 @@ class LocationViewController:UIViewController { ...@@ -103,11 +105,22 @@ 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
let closeButton = UIBarButtonItem(title: "general.close".localized().capitalized, if openedFromOnboarding {
style: .done, if #available(iOS 13, *) {
target: self, self.isModalInPresentation = true
action: #selector(handleCloseButton)) }
navigationItem.leftBarButtonItem = closeButton navigationItem.leftBarButtonItem = nil
}
else {
if #available(iOS 13, *) {
self.isModalInPresentation = false
}
let closeButton = UIBarButtonItem(title: "general.close".localized().capitalized,
style: .done,
target: self,
action: #selector(handleCloseButton))
navigationItem.leftBarButtonItem = closeButton
}
} }
func prepareSearchBar() { func prepareSearchBar() {
...@@ -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) {
......
//
// 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)
}
}
}
...@@ -44,6 +44,11 @@ class TodayViewController: UIViewController { ...@@ -44,6 +44,11 @@ class TodayViewController: UIViewController {
viewModel.delegate = self viewModel.delegate = self
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()
}
}
//
// 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
}
}
...@@ -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:TodayViewModelDelegate?
//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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment