Commit a8f9810e by Dmitry Stepanets

Working on adding rainfall dimension

parent 9432979a
...@@ -268,6 +268,7 @@ ...@@ -268,6 +268,7 @@
"settings.unit.wind" = "Wind"; "settings.unit.wind" = "Wind";
"settings.unit.pressure" = "Pressure"; "settings.unit.pressure" = "Pressure";
"settings.unit.distance" = "Distance"; "settings.unit.distance" = "Distance";
"settings.unit.rainfall" = "Rainfall";
"settings.language" = "Language"; "settings.language" = "Language";
"settings.manageNotifications" = "Manage Notifications"; "settings.manageNotifications" = "Manage Notifications";
"settings.locationAccess" = "Locations Access"; "settings.locationAccess" = "Locations Access";
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import UIKit import UIKit
import OneWeatherCore import OneWeatherCore
import OneWeatherAnalytics
class PrecipitationCell: UITableViewCell { class PrecipitationCell: UITableViewCell {
//Private //Private
...@@ -176,6 +177,7 @@ class PrecipitationCell: UITableViewCell { ...@@ -176,6 +177,7 @@ class PrecipitationCell: UITableViewCell {
else { else {
scrollView.isHidden = true scrollView.isHidden = true
minutelyForecastView.isHidden = false minutelyForecastView.isHidden = false
AppAnalytics.shared.log(event: .ANALYTICS_MINUTELY_PRECIP_TODAY_SEEN)
} }
} }
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
import UIKit import UIKit
import OneWeatherCore import OneWeatherCore
import Accelerate import Accelerate
import OneWeatherAnalytics
enum MinutelyForecastType { enum MinutelyForecastType {
case temperature case temperature
...@@ -126,6 +127,7 @@ class MinutelyForecastView: UIView { ...@@ -126,6 +127,7 @@ class MinutelyForecastView: UIView {
private var lastSelectedLevelIndex = 0 private var lastSelectedLevelIndex = 0
private var minutelyForecast = [MinutelyItem]() private var minutelyForecast = [MinutelyItem]()
private var timer: Timer? private var timer: Timer?
private var trackUserSwipe = false
private var forecastType = MinutelyForecastType.temperature private var forecastType = MinutelyForecastType.temperature
private lazy var dateFormatter: DateFormatter = { private lazy var dateFormatter: DateFormatter = {
let formatter = DateFormatter() let formatter = DateFormatter()
...@@ -503,8 +505,14 @@ private extension MinutelyForecastView { ...@@ -503,8 +505,14 @@ private extension MinutelyForecastView {
//MARK:- UIScrollView Delegate //MARK:- UIScrollView Delegate
extension MinutelyForecastView: UIScrollViewDelegate { extension MinutelyForecastView: UIScrollViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.trackUserSwipe = false
}
func scrollViewDidScroll(_ scrollView: UIScrollView) { func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.panGestureRecognizer.state == .began { if scrollView.panGestureRecognizer.state == .began {
self.trackUserSwipe = true
AppAnalytics.shared.log(event: .ANALYTICS_MINUTELY_SWIPE)
timer?.invalidate() timer?.invalidate()
timer = nil timer = nil
...@@ -526,7 +534,7 @@ extension MinutelyForecastView: UIScrollViewDelegate { ...@@ -526,7 +534,7 @@ extension MinutelyForecastView: UIScrollViewDelegate {
self.updateDetailsView(minutelyItem: minutelyForecast[cachedValue.key]) self.updateDetailsView(minutelyItem: minutelyForecast[cachedValue.key])
if lastSelectedLevelIndex != cachedValue.key { if trackUserSwipe && lastSelectedLevelIndex != cachedValue.key {
lastSelectedLevelIndex = cachedValue.key lastSelectedLevelIndex = cachedValue.key
feedbackGenerator.prepare() feedbackGenerator.prepare()
feedbackGenerator.selectionChanged() feedbackGenerator.selectionChanged()
......
...@@ -149,10 +149,20 @@ class ForecastCellFactory: CellFactory { ...@@ -149,10 +149,20 @@ class ForecastCellFactory: CellFactory {
return cell return cell
case .forecastHourly: case .forecastHourly:
let cell = dequeueReusableCell(type: ForecastHourlyCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: ForecastHourlyCell.self, tableView: tableView, indexPath: indexPath)
if let hourly = forecastViewModel.location?.hourly { if timePeriod == .minutely {
if cellsToUpdate.contains(.forecastHourly) { if let location = forecastViewModel.location {
cell.configure(hourly: hourly) if cellsToUpdate.contains(.forecastHourly) {
cellsToUpdate.remove(.forecastHourly) cell.configure(withMinutelyLocation: location)
cellsToUpdate.remove(.forecastHourly)
}
}
}
else {
if let hourly = forecastViewModel.location?.hourly {
if cellsToUpdate.contains(.forecastHourly) {
cell.configure(hourly: hourly)
cellsToUpdate.remove(.forecastHourly)
}
} }
} }
return cell return cell
...@@ -187,10 +197,8 @@ class ForecastCellFactory: CellFactory { ...@@ -187,10 +197,8 @@ class ForecastCellFactory: CellFactory {
switch timePeriod { switch timePeriod {
case .daily: case .daily:
return self.dailySection.rows[indexPath.row] return self.dailySection.rows[indexPath.row]
case .hourly: case .hourly, .minutely:
return self.hourlySection.rows[indexPath.row] return self.hourlySection.rows[indexPath.row]
default:
return .minutely
} }
} }
......
...@@ -11,6 +11,7 @@ import OneWeatherCore ...@@ -11,6 +11,7 @@ import OneWeatherCore
class ForecastHourlyCell: UITableViewCell { class ForecastHourlyCell: UITableViewCell {
//Private //Private
private let tempLabel = UILabel() private let tempLabel = UILabel()
private let minutelyForecastView = MinutelyForecastView()
private let forecastTimePeriodView = ForecastTimePeriodView() private let forecastTimePeriodView = ForecastTimePeriodView()
private let descriptionView = ForecastDescriptionView(lightStyleBackgroundColor: UIColor(hex: 0xfaedda).withAlphaComponent(0.5), private let descriptionView = ForecastDescriptionView(lightStyleBackgroundColor: UIColor(hex: 0xfaedda).withAlphaComponent(0.5),
gradientColors: [UIColor(hex: 0xe81e15).withAlphaComponent(0.33).cgColor, gradientColors: [UIColor(hex: 0xe81e15).withAlphaComponent(0.33).cgColor,
...@@ -22,6 +23,7 @@ class ForecastHourlyCell: UITableViewCell { ...@@ -22,6 +23,7 @@ class ForecastHourlyCell: UITableViewCell {
prepareCell() prepareCell()
prepareTempLabel() prepareTempLabel()
prepareTimePeriodView() prepareTimePeriodView()
prepareMinutelyView()
prepareDescriptionView() prepareDescriptionView()
updateUI() updateUI()
} }
...@@ -45,6 +47,14 @@ class ForecastHourlyCell: UITableViewCell { ...@@ -45,6 +47,14 @@ class ForecastHourlyCell: UITableViewCell {
public func configure(hourly:[HourlyWeather]) { public func configure(hourly:[HourlyWeather]) {
self.forecastTimePeriodView.set(daily: nil, hourly: hourly) self.forecastTimePeriodView.set(daily: nil, hourly: hourly)
self.forecastTimePeriodView.set(forecastType: .hourly, buttonType: ForecastPeriodButton.self) self.forecastTimePeriodView.set(forecastType: .hourly, buttonType: ForecastPeriodButton.self)
self.forecastTimePeriodView.isHidden = false
self.minutelyForecastView.isHidden = true
}
public func configure(withMinutelyLocation location: Location) {
self.minutelyForecastView.configure(with: location, forecastType: .temperature)
self.minutelyForecastView.isHidden = false
self.forecastTimePeriodView.isHidden = true
} }
} }
...@@ -74,6 +84,14 @@ private extension ForecastHourlyCell { ...@@ -74,6 +84,14 @@ private extension ForecastHourlyCell {
} }
} }
func prepareMinutelyView() {
contentView.addSubview(minutelyForecastView)
minutelyForecastView.snp.makeConstraints { make in
make.edges.equalTo(forecastTimePeriodView)
}
}
func prepareDescriptionView() { func prepareDescriptionView() {
//TODO: Hide the description for now //TODO: Hide the description for now
descriptionView.isHidden = true descriptionView.isHidden = true
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import UIKit import UIKit
import OneWeatherAnalytics import OneWeatherAnalytics
import OneWeatherCore
class ForecastViewController: UIViewController { class ForecastViewController: UIViewController {
//Private //Private
...@@ -19,6 +20,7 @@ class ForecastViewController: UIViewController { ...@@ -19,6 +20,7 @@ class ForecastViewController: UIViewController {
private let tableView = UITableView() private let tableView = UITableView()
private let viewModel:ForecastViewModel private let viewModel:ForecastViewModel
private var timePeriodCellFrame = CGRect.zero private var timePeriodCellFrame = CGRect.zero
private let featureAvailability = FeatureAvailabilityManager.shared
private var localizationObserver:Any? private var localizationObserver:Any?
private var timePeriod:TimePeriod { private var timePeriod:TimePeriod {
return TimePeriod(rawValue: timePeriodControl.selectedSegmentIndex) ?? .daily return TimePeriod(rawValue: timePeriodControl.selectedSegmentIndex) ?? .daily
...@@ -57,6 +59,7 @@ class ForecastViewController: UIViewController { ...@@ -57,6 +59,7 @@ class ForecastViewController: UIViewController {
super.viewDidAppear(animated) super.viewDidAppear(animated)
analytics(log: .ANALYTICS_VIEW_FORECAST) analytics(log: .ANALYTICS_VIEW_FORECAST)
analyticsLogCurrentTimePeriod() analyticsLogCurrentTimePeriod()
refreshTimePeriodControl()
} }
override func viewDidLayoutSubviews() { override func viewDidLayoutSubviews() {
...@@ -89,6 +92,18 @@ class ForecastViewController: UIViewController { ...@@ -89,6 +92,18 @@ class ForecastViewController: UIViewController {
} }
} }
private func refreshTimePeriodControl() {
if featureAvailability?.isAvailable(feature: .minutelyForecast) == true {
self.timePeriodControl.set(items: ["forecast.timePeriod.daily".localized(),
"forecast.timePeriod.hourly".localized(),
"forecast.timePeriod.minutely".localized()])
}
else {
self.timePeriodControl.set(items: ["forecast.timePeriod.daily".localized(),
"forecast.timePeriod.hourly".localized()])
}
}
public func switchTo(timePeriod: TimePeriod) { public func switchTo(timePeriod: TimePeriod) {
if self.timePeriodControl.selectedSegmentIndex != timePeriod.rawValue { if self.timePeriodControl.selectedSegmentIndex != timePeriod.rawValue {
self.timePeriodControl.selectedSegmentIndex = timePeriod.rawValue self.timePeriodControl.selectedSegmentIndex = timePeriod.rawValue
...@@ -260,6 +275,7 @@ extension ForecastViewController: UITableViewDataSource { ...@@ -260,6 +275,7 @@ extension ForecastViewController: UITableViewDataSource {
extension ForecastViewController: ForecastViewModelDelegate { extension ForecastViewController: ForecastViewModelDelegate {
func viewModelDidChange<P>(model: P) where P : ViewModelProtocol { func viewModelDidChange<P>(model: P) where P : ViewModelProtocol {
refreshCityButton() refreshCityButton()
refreshTimePeriodControl()
forecastCellFactory.setNeedsUpdate() forecastCellFactory.setNeedsUpdate()
tableView.reloadData() tableView.reloadData()
refreshDayButtons() refreshDayButtons()
......
...@@ -16,6 +16,7 @@ public enum SettingsRow { ...@@ -16,6 +16,7 @@ public enum SettingsRow {
case wind case wind
case pressure case pressure
case distance case distance
case rainfall
case language case language
case manageNotifications case manageNotifications
case locationAccess case locationAccess
...@@ -26,7 +27,7 @@ public enum SettingsRow { ...@@ -26,7 +27,7 @@ public enum SettingsRow {
return [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMaxXMinYCorner] return [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMaxXMinYCorner]
case .temperature: case .temperature:
return [.layerMinXMinYCorner, .layerMaxXMinYCorner] return [.layerMinXMinYCorner, .layerMaxXMinYCorner]
case .distance: case .rainfall:
return [.layerMinXMaxYCorner, .layerMaxXMaxYCorner] return [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
case .language: case .language:
return [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMaxXMinYCorner] return [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMaxXMinYCorner]
...@@ -51,6 +52,8 @@ public enum SettingsRow { ...@@ -51,6 +52,8 @@ public enum SettingsRow {
return "settings.unit.pressure".localized() return "settings.unit.pressure".localized()
case .distance: case .distance:
return "settings.unit.distance".localized() return "settings.unit.distance".localized()
case .rainfall:
return "settings.unit.rainfall".localized()
case .language: case .language:
return "settings.language".localized() return "settings.language".localized()
case .manageNotifications: case .manageNotifications:
...@@ -149,6 +152,9 @@ class SettingsCellFactory: CellFactory { ...@@ -149,6 +152,9 @@ class SettingsCellFactory: CellFactory {
case .distance: case .distance:
name = viewModel.settings.distanceType.name name = viewModel.settings.distanceType.name
symbol = viewModel.settings.distanceType.symbol symbol = viewModel.settings.distanceType.symbol
case .rainfall:
name = "mm"
symbol = "mm/h"
default: default:
break break
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import UIKit import UIKit
import OneWeatherCore import OneWeatherCore
import OneWeatherAnalytics
class TodayForecastTimePeriodCell: UITableViewCell { class TodayForecastTimePeriodCell: UITableViewCell {
//Private //Private
...@@ -67,6 +68,8 @@ class TodayForecastTimePeriodCell: UITableViewCell { ...@@ -67,6 +68,8 @@ class TodayForecastTimePeriodCell: UITableViewCell {
let forecastType = timePeriod == .daily ? ForecastType.daily : ForecastType.hourly let forecastType = timePeriod == .daily ? ForecastType.daily : ForecastType.hourly
self.forecastTimePeriodView.set(forecastType: forecastType, buttonType: ForecastPeriodButton.self) self.forecastTimePeriodView.set(forecastType: forecastType, buttonType: ForecastPeriodButton.self)
case .minutely: case .minutely:
AppAnalytics.shared.log(event: .ANALYTICS_VIEW_FORECAST_MINUTELY)
AppAnalytics.shared.log(event: .ANALYTICS_MINUTELY_TEMP_TODAY_SEEN)
forecastTimePeriodView.isHidden = true forecastTimePeriodView.isHidden = true
minutelyForecastView.isHidden = false minutelyForecastView.isHidden = false
} }
......
...@@ -151,6 +151,7 @@ public enum AnalyticsEvent: String { ...@@ -151,6 +151,7 @@ public enum AnalyticsEvent: String {
// MARK: Minutely // MARK: Minutely
case ANALYTICS_MINUTELY_PRECIP_TODAY_SEEN = "MINUTELY_PRECIP_TODAY_SEEN" case ANALYTICS_MINUTELY_PRECIP_TODAY_SEEN = "MINUTELY_PRECIP_TODAY_SEEN"
case ANALYTICS_MINUTELY_PRECIP_TODAY_TAP = "MINUTELY_PRECIP_TODAY_TAP" case ANALYTICS_MINUTELY_PRECIP_TODAY_TAP = "MINUTELY_PRECIP_TODAY_TAP"
case ANALYTICS_MINUTELY_SWIPE = "MINUTELY_SWIPE"
/// When the user taps on the title of the minutely precipitation graph /// When the user taps on the title of the minutely precipitation graph
case ANALYTICS_MINUTELY_PRECIP_TODAY_TITLE = "MINUTELY_PRECIP_TODAY_TITLE" case ANALYTICS_MINUTELY_PRECIP_TODAY_TITLE = "MINUTELY_PRECIP_TODAY_TITLE"
case ANALYTICS_MINUTELY_TEMP_TODAY_SEEN = "MINUTELY_TEMP_TODAY_SEEN" case ANALYTICS_MINUTELY_TEMP_TODAY_SEEN = "MINUTELY_TEMP_TODAY_SEEN"
......
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