Commit 5947ac81 by Dmitriy Stepanets

Changed ViewControllers update logic based on location update

parent 45c821a5
......@@ -352,15 +352,12 @@
CD0A2CC325FA5857006148A4 /* ForecastTimePeriod */ = {
isa = PBXGroup;
children = (
CD5D231B2615C6CA00B549DA /* Buttons */,
CD9B6B1325DBCDE2001D9B80 /* GraphView.swift */,
CDC6126525E9085600188DA7 /* GraphLine.swift */,
CDC6126925E90C8800188DA7 /* GraphLineSettings.swift */,
CD71708F25FA317700A63C27 /* ForecastTimePeriodView.swift */,
CDEE8AD625DA882200C289DE /* ForecastPeriodButton.swift */,
CD3F6E6825FA59D4002DB99B /* ForecastDetailPeriodButton.swift */,
CD3F6E6B25FA5A90002DB99B /* PeriodButtonProtocol.swift */,
CD593BC126088A5900C93428 /* TimePeriodOffsetHolder.swift */,
CDE2BF242609D9140085C930 /* ForecastWindButton.swift */,
);
path = ForecastTimePeriod;
sourceTree = "<group>";
......@@ -535,6 +532,17 @@
path = Cells;
sourceTree = "<group>";
};
CD5D231B2615C6CA00B549DA /* Buttons */ = {
isa = PBXGroup;
children = (
CDEE8AD625DA882200C289DE /* ForecastPeriodButton.swift */,
CD3F6E6825FA59D4002DB99B /* ForecastDetailPeriodButton.swift */,
CD3F6E6B25FA5A90002DB99B /* PeriodButtonProtocol.swift */,
CDE2BF242609D9140085C930 /* ForecastWindButton.swift */,
);
path = Buttons;
sourceTree = "<group>";
};
CD647D0025ED07AF0034578B /* ViewModels */ = {
isa = PBXGroup;
children = (
......
......@@ -32,8 +32,7 @@ class PrecipitationCell: UITableViewCell {
}
public func configure(with dayily:[DailyWeather]) {
guard stackView.arrangedSubviews.isEmpty else { return }
self.stackView.removeAll()
self.headingButton.isHidden = false
for index in 0..<dayily.count {
let precipButton = PrecipButton()
......@@ -46,8 +45,7 @@ class PrecipitationCell: UITableViewCell {
}
public func configure(with hourly:[HourlyWeather]) {
guard stackView.arrangedSubviews.isEmpty else { return }
self.stackView.removeAll()
self.headingLabel.font = AppFont.SFPro.bold(size: 18)
self.headingButton.isHidden = true
self.headingLabel.text = "precipitation.title".localized().capitalized
......
......@@ -52,12 +52,12 @@ class SunPhaseCell: UITableViewCell {
private var sunProgress:CGFloat = 0.0
//Computed
private static let dateFormatter: DateFormatter = {
private static var dateFormatter: DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "h:mm a"
return fmt
}()
private static let nowDateFormatter:DateFormatter = {
private static var nowDateFormatter:DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd h:mm a"
return fmt
......@@ -111,7 +111,8 @@ class SunPhaseCell: UITableViewCell {
let nowDate = SunPhaseCell.nowDateFormatter.date(from: nowString) ?? Date()
//For pretty dash line view setting up min and max values
let progress = CGFloat((nowDate.timeIntervalSince1970 - sunset.timeIntervalSince1970) / sunTimePeriod)
let secondsToSunset = sunset.timeIntervalSince1970 - nowDate.timeIntervalSince1970
let progress = CGFloat((sunTimePeriod - secondsToSunset) / sunTimePeriod)
var pathProgress = max(0.04, progress)
pathProgress = min(0.96, pathProgress)
self.sunProgress = pathProgress
......
......@@ -20,13 +20,24 @@ private enum DailyForecastCellType:Int, CaseIterable {
private enum HourlyForecastCellType: Int, CaseIterable {
case day
case tempInfo
case forecastHourly
case precipitation
case wind
}
private struct CellsToUpdate:OptionSet {
let rawValue: Int
static let dailyTimePeriod = CellsToUpdate(rawValue: 1 << 0)
static let hourlyTimePeriod = CellsToUpdate(rawValue: 1 << 1)
static let dailyForecastInfoCell = CellsToUpdate(rawValue: 1 << 2)
static let precipitation = CellsToUpdate(rawValue: 1 << 4)
static let wind = CellsToUpdate(rawValue: 1 << 5)
}
class ForecastCellFactory: CellFactoryProtocol {
//Private
private var cellsToUpdate:CellsToUpdate = [.dailyTimePeriod, .hourlyTimePeriod, .dailyForecastInfoCell, .precipitation, .wind]
private let forecastViewModel:ForecastViewModel
private var currentTimePeriod = TimePeriod.daily
......@@ -67,6 +78,10 @@ class ForecastCellFactory: CellFactoryProtocol {
}
}
public func setNeedsUpdate() {
self.cellsToUpdate = [.dailyTimePeriod, .hourlyTimePeriod, .dailyForecastInfoCell, .precipitation, .wind]
}
public func willDisplay(cell:UITableViewCell) {
switch cell {
case let sunCell as SunPhaseCell:
......@@ -90,15 +105,22 @@ class ForecastCellFactory: CellFactoryProtocol {
cell.delegate = self
if let daily = forecastViewModel.location?.daily {
cell.configure(daily: daily,
offset: forecastViewModel.offsetHolder.currentOffset,
selectedButtonIndex: forecastViewModel.selectedDailyWeatherIndex)
cell.setOffset(offset: forecastViewModel.offsetHolder.currentOffset,
selectedButton: forecastViewModel.selectedDailyWeatherIndex)
if cellsToUpdate.contains(.dailyTimePeriod) {
cell.configure(daily: daily)
cellsToUpdate.remove(.dailyTimePeriod)
}
}
return cell
case .forecastInfo:
let cell = dequeueReusableCell(type: ForecastInfoCell.self, tableView: tableView, indexPath: indexPath)
if let daily = forecastViewModel.selectedDailyWeather {
cell.configure(dailyWeather: daily)
if cellsToUpdate.contains(.dailyForecastInfoCell) {
cell.configure(dailyWeather: daily)
cellsToUpdate.remove(.dailyForecastInfoCell)
}
}
return cell
......@@ -129,22 +151,31 @@ class ForecastCellFactory: CellFactoryProtocol {
cell.configure(today: today)
}
return cell
case .tempInfo:
case .forecastHourly:
let cell = dequeueReusableCell(type: ForecastHourlyCell.self, tableView: tableView, indexPath: indexPath)
if let hourly = forecastViewModel.location?.hourly {
cell.configure(hourly: hourly)
if cellsToUpdate.contains(.hourlyTimePeriod) {
cell.configure(hourly: hourly)
cellsToUpdate.remove(.hourlyTimePeriod)
}
}
return cell
case .precipitation:
let cell = dequeueReusableCell(type: PrecipitationCell.self, tableView: tableView, indexPath: indexPath)
if let hourly = forecastViewModel.location?.hourly {
cell.configure(with: hourly)
if cellsToUpdate.contains(.precipitation) {
cell.configure(with: hourly)
cellsToUpdate.remove(.precipitation)
}
}
return cell
case .wind:
let cell = dequeueReusableCell(type: ForecastWindSpeedCell.self, tableView: tableView, indexPath: indexPath)
if let hourly = forecastViewModel.location?.hourly {
cell.configure(with: hourly)
if cellsToUpdate.contains(.wind) {
cell.configure(with: hourly)
cellsToUpdate.remove(.wind)
}
}
return cell
}
......
......@@ -48,12 +48,13 @@ class ForecastDailyCell: UITableViewCell {
}
//Public
public func configure(daily:[DailyWeather], offset:CGFloat = 0, selectedButtonIndex:Int = 0) {
public func configure(daily:[DailyWeather]) {
self.forecastTimePeriodView.set(daily: daily, hourly: nil)
if self.forecastTimePeriodView.isEmpty {
self.forecastTimePeriodView.set(forecastType: .daily, buttonType: ForecastDetailPeriodButton.self)
}
self.forecastTimePeriodView.selectButtonAt(index: selectedButtonIndex)
self.forecastTimePeriodView.set(forecastType: .daily, buttonType: ForecastDetailPeriodButton.self)
}
public func setOffset(offset:CGFloat, selectedButton:Int = 0) {
self.forecastTimePeriodView.selectButtonAt(index: selectedButton)
self.forecastTimePeriodView.update(offset: offset)
}
}
......
......@@ -217,6 +217,7 @@ extension ForecastViewController: UITableViewDataSource {
extension ForecastViewController: ForecastViewModelDelegate {
func viewModelDidChange<P>(model: P) where P : ViewModelProtocol {
refreshCityButton()
forecastCellFactory.setNeedsUpdate()
tableView.reloadData()
refreshDayButtons()
}
......
......@@ -7,11 +7,6 @@
import UIKit
//MARK:- Cities View Controller
private enum EditButtonStyle {
case edit
case done
}
class LocationViewController:UIViewController {
//Private
private let cellFactory:LocationCellFactory
......@@ -19,7 +14,6 @@ class LocationViewController:UIViewController {
private let searchBar = UISearchBar()
private let locationButton = SelfSizingButton(frame: .zero)
private let tableView = UITableView(frame: .zero, style: .grouped)
private let editButton = SelfSizingButton()
private let locationsViewModel = LocationsViewModel()
private let searchQueue:OperationQueue = {
let queue = OperationQueue()
......@@ -49,7 +43,7 @@ class LocationViewController:UIViewController {
prepareSearchBar()
prepareLocationButton()
prepareTableView()
prepareEditButton()
// prepareEditButton()
setupObservers()
updateUI()
}
......@@ -71,21 +65,6 @@ class LocationViewController:UIViewController {
super.traitCollectionDidChange(previousTraitCollection)
updateUI()
}
private func updateEditButton(style:EditButtonStyle) {
switch style {
case .edit:
UIView.performWithoutAnimation {
self.editButton.setImage(UIImage(named: "edit_pencil"), for: .normal)
self.editButton.setTitle("EDIT".localized, for: .normal)
}
case .done:
UIView.performWithoutAnimation {
self.editButton.setImage(nil, for: .normal)
self.editButton.setTitle("DONE".localized, for: .normal)
}
}
}
private func close() {
self.navigationController?.dismiss(animated: true)
......@@ -118,11 +97,6 @@ class LocationViewController:UIViewController {
// }
locationsViewModel.useCurrentLocation(requestedBy: self)
}
@objc private func handleEditButton(button:UIButton) {
tableView.setEditing(!tableView.isEditing, animated: true)
self.updateEditButton(style: tableView.isEditing ? .done : .edit)
}
}
//MARK:- Saved cities prepare
......@@ -186,17 +160,6 @@ private extension LocationViewController {
}
}
func prepareEditButton() {
editButton.setImage(UIImage(named: "edit_pencil"), for: .normal)
editButton.tintColor = ThemeManager.Colors.locationBlue
editButton.setTitle("EDIT".localized, for: .normal)
editButton.setTitleColor(ThemeManager.Colors.locationBlue.highlighted, for: .highlighted)
editButton.setTitleColor(ThemeManager.Colors.locationBlue, for: .normal)
editButton.titleLabel?.font = AppFont.SFPro.regular(size: 12)
editButton.titleEdgeInsets = .init(top: 0, left: 6, bottom: 0, right: 0)
editButton.addTarget(self, action: #selector(handleEditButton(button:)), for: .touchUpInside)
}
func setupObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
......@@ -282,11 +245,11 @@ extension LocationViewController: UITableViewDelegate {
titleLabel.text = "search.savedCities".localized().capitalized + " (\(self.locationsViewModel.cities.count))"
//Add Edit button
container.addSubview(editButton)
editButton.snp.makeConstraints { (make) in
make.right.equalToSuperview().inset(24)
make.bottom.equalTo(titleLabel)
}
// container.addSubview(editButton)
// editButton.snp.makeConstraints { (make) in
// make.right.equalToSuperview().inset(24)
// make.bottom.equalTo(titleLabel)
// }
case .popularCities:
titleLabel.text = "\(locationsViewModel.cities.count) " + "search.popularCities".localized()
case .searchResults:
......@@ -309,14 +272,6 @@ extension LocationViewController: UITableViewDelegate {
return true
}
func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {
self.updateEditButton(style: .done)
}
func tableView(_ tableView: UITableView, didEndEditingRowAt indexPath: IndexPath?) {
self.updateEditButton(style: .edit)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let cityToDelete = self.locationsViewModel.cities[indexPath.row]
......
......@@ -19,14 +19,24 @@ private enum TodayCellType:Int {
case moon
}
private struct CellsToUpdate:OptionSet {
let rawValue: Int
static let condition = CellsToUpdate(rawValue: 1 << 0)
static let timePeriod = CellsToUpdate(rawValue: 1 << 1)
static let precipitation = CellsToUpdate(rawValue: 1 << 2)
static let dayTime = CellsToUpdate(rawValue: 1 << 3)
}
private struct TodaySection {
var rows:[TodayCellType]
}
class TodayCellFactory: CellFactoryProtocol {
//Private
private var cellsToUpdate:CellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime]
private let todayViewModel:TodayViewModel
private var todaySection = TodaySection(rows: [/*.alert,*/ .forecast, .ad,
private var todaySection = TodaySection(rows: [.alert, .forecast, .ad,
.conditions, .forecastPeriod, .precipitation,
.dayTime, .sun, .moon])
......@@ -74,19 +84,31 @@ class TodayCellFactory: CellFactoryProtocol {
return cell
case .conditions:
let cell = dequeueReusableCell(type: TodayConditionsCell.self, tableView: tableView, indexPath: indexPath)
cell.configure(with: loc)
if cellsToUpdate.contains(.condition) {
cell.configure(with: loc)
cellsToUpdate.remove(.condition)
}
return cell
case .forecastPeriod:
let cell = dequeueReusableCell(type: TodayForecastTimePeriodCell.self, tableView: tableView, indexPath: indexPath)
cell.configure(with: loc)
if cellsToUpdate.contains(.timePeriod) {
cell.configure(with: loc)
cellsToUpdate.remove(.timePeriod)
}
return cell
case .precipitation:
let cell = dequeueReusableCell(type: PrecipitationCell.self, tableView: tableView, indexPath: indexPath)
cell.configure(with: loc.daily)
if cellsToUpdate.contains(.precipitation) {
cell.configure(with: loc.daily)
cellsToUpdate.remove(.precipitation)
}
return cell
case .dayTime:
let cell = dequeueReusableCell(type: TodayDayTimesCell.self, tableView: tableView, indexPath: indexPath)
cell.configure(with: loc)
if cellsToUpdate.contains(.dayTime) {
cell.configure(with: loc)
cellsToUpdate.remove(.dayTime)
}
return cell
case .sun:
let cell = dequeueReusableCell(type: SunPhaseCell.self, tableView: tableView, indexPath: indexPath)
......@@ -99,6 +121,10 @@ class TodayCellFactory: CellFactoryProtocol {
}
}
public func setNeedsUpdate() {
cellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime]
}
public func willDisplay(cell:UITableViewCell) {
switch cell {
case let sunCell as SunPhaseCell:
......
......@@ -36,28 +36,7 @@ class TodayForecastTimePeriodCell: UITableViewCell {
public func configure(with location:Location) {
self.location = location
self.forecastTimePeriodView.set(daily: location.daily, hourly: location.hourly)
drawGraphIfNeeded()
}
private func drawGraphIfNeeded() {
guard let timePeriod = TimePeriod(rawValue: self.periodSegmentedControl.selectedSegmentIndex) else {
return
}
if graphIsDrawn == false {
switch timePeriod {
case .daily:
if self.location?.daily.isEmpty == false {
forecastTimePeriodView.set(forecastType: .daily, buttonType: ForecastPeriodButton.self)
self.graphIsDrawn = true
}
case .hourly:
if self.location?.hourly.isEmpty == false {
forecastTimePeriodView.set(forecastType: .hourly, buttonType: ForecastPeriodButton.self)
self.graphIsDrawn = true
}
}
}
self.handleSegmentDidChange()
}
@objc private func handleSegmentDidChange() {
......
......@@ -141,6 +141,7 @@ extension TodayViewController: ViewModelDelegate {
cityButton.configure(with: viewModel.location)
cityButton.isHidden = false
tableView.isHidden = false
todayCellFactory.setNeedsUpdate()
tableView.reloadData()
}
}
......@@ -10,8 +10,8 @@ import UIKit
class TodayViewModel: ViewModelProtocol {
//Public
public weak var delegate:ViewModelDelegate?
private(set) var location:Location?
private let locationManager = LocationManager.shared
private(set) var location:Location?
deinit {
locationManager.remove(delegate: self)
......
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