Commit ce879c83 by Dmitriy Stepanets

Working on Locations UI logic

parent f0f001bc
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */; }; CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */; };
CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303D25726960004B34B3 /* ThemeProtocol.swift */; }; CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303D25726960004B34B3 /* ThemeProtocol.swift */; };
CD6B304325726AD1004B34B3 /* DefaultTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B304225726AD1004B34B3 /* DefaultTheme.swift */; }; CD6B304325726AD1004B34B3 /* DefaultTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B304225726AD1004B34B3 /* DefaultTheme.swift */; };
CD8091772578D73F003541A4 /* PopularCitiesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8091762578D73F003541A4 /* PopularCitiesManager.swift */; };
CD80917B2578E4A8003541A4 /* UIViewController+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD80917A2578E4A8003541A4 /* UIViewController+Alert.swift */; };
CDA69B2C2574F3C800CB6409 /* CityCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA69B2B2574F3C800CB6409 /* CityCell.swift */; }; CDA69B2C2574F3C800CB6409 /* CityCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA69B2B2574F3C800CB6409 /* CityCell.swift */; };
CDA69B30257500E200CB6409 /* GeoNamesPlace.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA69B2F257500E200CB6409 /* GeoNamesPlace.swift */; }; CDA69B30257500E200CB6409 /* GeoNamesPlace.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA69B2F257500E200CB6409 /* GeoNamesPlace.swift */; };
CDA69B3325750D3400CB6409 /* LocationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA69B3225750D3400CB6409 /* LocationsViewModel.swift */; }; CDA69B3325750D3400CB6409 /* LocationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA69B3225750D3400CB6409 /* LocationsViewModel.swift */; };
...@@ -57,6 +59,8 @@ ...@@ -57,6 +59,8 @@
CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelfSizingButton.swift; sourceTree = "<group>"; }; CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelfSizingButton.swift; sourceTree = "<group>"; };
CD6B303D25726960004B34B3 /* ThemeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeProtocol.swift; sourceTree = "<group>"; }; CD6B303D25726960004B34B3 /* ThemeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeProtocol.swift; sourceTree = "<group>"; };
CD6B304225726AD1004B34B3 /* DefaultTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTheme.swift; sourceTree = "<group>"; }; CD6B304225726AD1004B34B3 /* DefaultTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTheme.swift; sourceTree = "<group>"; };
CD8091762578D73F003541A4 /* PopularCitiesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopularCitiesManager.swift; sourceTree = "<group>"; };
CD80917A2578E4A8003541A4 /* UIViewController+Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Alert.swift"; sourceTree = "<group>"; };
CDA69B2B2574F3C800CB6409 /* CityCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityCell.swift; sourceTree = "<group>"; }; CDA69B2B2574F3C800CB6409 /* CityCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityCell.swift; sourceTree = "<group>"; };
CDA69B2F257500E200CB6409 /* GeoNamesPlace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoNamesPlace.swift; sourceTree = "<group>"; }; CDA69B2F257500E200CB6409 /* GeoNamesPlace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoNamesPlace.swift; sourceTree = "<group>"; };
CDA69B3225750D3400CB6409 /* LocationsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsViewModel.swift; sourceTree = "<group>"; }; CDA69B3225750D3400CB6409 /* LocationsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsViewModel.swift; sourceTree = "<group>"; };
...@@ -112,6 +116,7 @@ ...@@ -112,6 +116,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CD1237DA255D5DFA00C98139 /* PG.playground */, CD1237DA255D5DFA00C98139 /* PG.playground */,
CD8091752578D726003541A4 /* Managers */,
CDD0F1DC2572400200CF5017 /* UI */, CDD0F1DC2572400200CF5017 /* UI */,
CD1237EF255D838600C98139 /* Extensions */, CD1237EF255D838600C98139 /* Extensions */,
CDD0F1E2257240DA00CF5017 /* Resources */, CDD0F1E2257240DA00CF5017 /* Resources */,
...@@ -138,6 +143,7 @@ ...@@ -138,6 +143,7 @@
children = ( children = (
CD1237F0255D83C500C98139 /* UIColor+Hex.swift */, CD1237F0255D83C500C98139 /* UIColor+Hex.swift */,
CD6B3035257262C2004B34B3 /* UIColor+Highlight.swift */, CD6B3035257262C2004B34B3 /* UIColor+Highlight.swift */,
CD80917A2578E4A8003541A4 /* UIViewController+Alert.swift */,
); );
path = Extensions; path = Extensions;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -167,6 +173,14 @@ ...@@ -167,6 +173,14 @@
path = Themes; path = Themes;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
CD8091752578D726003541A4 /* Managers */ = {
isa = PBXGroup;
children = (
CD8091762578D73F003541A4 /* PopularCitiesManager.swift */,
);
path = Managers;
sourceTree = "<group>";
};
CDA69B2A2574F3A700CB6409 /* Cells */ = { CDA69B2A2574F3A700CB6409 /* Cells */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
...@@ -275,7 +289,7 @@ ...@@ -275,7 +289,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 1210; LastSwiftUpdateCheck = 1210;
LastUpgradeCheck = 1210; LastUpgradeCheck = 1220;
TargetAttributes = { TargetAttributes = {
CD1237BE255D5C5900C98139 = { CD1237BE255D5C5900C98139 = {
CreatedOnToolsVersion = 12.1; CreatedOnToolsVersion = 12.1;
...@@ -379,7 +393,9 @@ ...@@ -379,7 +393,9 @@
870880222578ED190076BFB1 /* WdtHourSummary.swift in Sources */, 870880222578ED190076BFB1 /* WdtHourSummary.swift in Sources */,
CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */, CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */,
CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */, CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */,
CD8091772578D73F003541A4 /* PopularCitiesManager.swift in Sources */,
CDA69B2C2574F3C800CB6409 /* CityCell.swift in Sources */, CDA69B2C2574F3C800CB6409 /* CityCell.swift in Sources */,
CD80917B2578E4A8003541A4 /* UIViewController+Alert.swift in Sources */,
CD1237DE255D612300C98139 /* CurrentForecastCell.swift in Sources */, CD1237DE255D612300C98139 /* CurrentForecastCell.swift in Sources */,
CEAD00A12577B2D5003596AD /* StuffThatIsPresentInTheMainProject.swift in Sources */, CEAD00A12577B2D5003596AD /* StuffThatIsPresentInTheMainProject.swift in Sources */,
); );
......
//
// UIViewController+Alert.swift
// 1Weather
//
// Created by Dmitry Stepanets on 03.12.2020.
//
import UIKit
extension UIViewController {
func showAlert(withTitle title:String?, message:String?) {
guard message != nil, message?.isEmpty == false else { return }
DispatchQueue.main.async {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
self.present(alert, animated: true)
}
}
}
//
// PopularCitiesManager.swift
// 1Weather
//
// Created by Dmitry Stepanets on 03.12.2020.
//
import UIKit
class PopularCitiesManager {
func fetchPopularCities(completion:@escaping (_ result: Result<[GeoNamesPlace], Error>) -> Void) {
let ny = GeoNamesPlace()
ny.city = "New York"
ny.stateCode = "00001"
ny.state = "NY"
ny.country = "USA"
let chicago = GeoNamesPlace()
chicago.city = "Chicago"
chicago.stateCode = "00002"
chicago.state = "IL"
chicago.country = "USA"
let wg = GeoNamesPlace()
wg.city = "Washington DC"
wg.stateCode = "00003"
wg.state = "DC"
wg.country = "USA"
let boston = GeoNamesPlace()
boston.city = "Boston"
boston.stateCode = "00004"
boston.state = "MA"
boston.country = "USA"
completion(.success([ny, chicago, wg, boston]))
}
}
...@@ -14,6 +14,7 @@ public struct ThemeManager { ...@@ -14,6 +14,7 @@ public struct ThemeManager {
static let citySelected = UIColor(hex: 0x599A0E) static let citySelected = UIColor(hex: 0x599A0E)
static let cityNoSelected = UIColor(hex: 0xC5C5C5).withAlphaComponent(0.5) static let cityNoSelected = UIColor(hex: 0xC5C5C5).withAlphaComponent(0.5)
static let cityAddButtonBG = UIColor(hex: 0x131315) static let cityAddButtonBG = UIColor(hex: 0x131315)
static let searchBarTint = UIColor(hex: 0xEBEBF5).withAlphaComponent(0.6)
} }
static var currentTheme:ThemeProtocol { static var currentTheme:ThemeProtocol {
......
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
import UIKit import UIKit
class WdtLocation: NSObject, NSCoding { class WdtLocation: NSObject, NSCoding {
static let LOCATION = "location" static let LOCATION = "location"
static let CONDITIONS = "conditions" static let CONDITIONS = "conditions"
static let DAYSUMMARIES = "daysummaries" static let DAYSUMMARIES = "daysummaries"
...@@ -33,6 +31,27 @@ class WdtLocation: NSObject, NSCoding { ...@@ -33,6 +31,27 @@ class WdtLocation: NSObject, NSCoding {
var zip: String? var zip: String?
fileprivate var _nickName: String? fileprivate var _nickName: String?
var nickName: String? var nickName: String?
var fullName: String {
get {
var sb = String()
if city?.count ?? 0 > 0 {
sb.append(city!)
sb.append(", ")
}
if region?.count ?? 0 > 0 {
sb.append(region!)
sb.append(", ")
}
if country?.count ?? 0 > 0 {
sb.append(country!)
sb.append(", ")
}
if (sb.count > 0) {
sb = sb.trim(", ") // trim comma and space
}
return sb
}
}
var cityName: String { var cityName: String {
get { get {
...@@ -125,7 +144,6 @@ class WdtLocation: NSObject, NSCoding { ...@@ -125,7 +144,6 @@ class WdtLocation: NSObject, NSCoding {
cityState = "" cityState = ""
uvDesc = "" uvDesc = ""
detailName = "" detailName = ""
fullName = ""
locationId = "us" locationId = "us"
fileName = "us" fileName = "us"
simpleFileName = "us" simpleFileName = "us"
...@@ -139,7 +157,6 @@ class WdtLocation: NSObject, NSCoding { ...@@ -139,7 +157,6 @@ class WdtLocation: NSObject, NSCoding {
cityState = "" cityState = ""
uvDesc = "" uvDesc = ""
detailName = "" detailName = ""
fullName = ""
locationId = "us" locationId = "us"
fileName = "us" fileName = "us"
simpleFileName = "us" simpleFileName = "us"
...@@ -177,7 +194,6 @@ class WdtLocation: NSObject, NSCoding { ...@@ -177,7 +194,6 @@ class WdtLocation: NSObject, NSCoding {
cityState = "" cityState = ""
uvDesc = "" uvDesc = ""
detailName = "" detailName = ""
fullName = ""
locationId = "" locationId = ""
fileName = "" fileName = ""
simpleFileName = "" simpleFileName = ""
...@@ -242,8 +258,6 @@ class WdtLocation: NSObject, NSCoding { ...@@ -242,8 +258,6 @@ class WdtLocation: NSObject, NSCoding {
var detailName: String var detailName: String
var fullName: String
var isDay: Bool = false var isDay: Bool = false
......
...@@ -11,6 +11,33 @@ import UserNotifications ...@@ -11,6 +11,33 @@ import UserNotifications
class WeatherUpdateManager: NSObject { class WeatherUpdateManager: NSObject {
static let shared = WeatherUpdateManager() static let shared = WeatherUpdateManager()
private override init() {
super.init()
let sf = WdtLocation(zip: "000001",
city: "San-Francisco",
region: "CA",
countryCode: "US",
country: "USA",
lat: "0",
lng: "0")
sf.currentConditions = WdtCondition()
sf.currentConditions?.tempC = "30"
sf.selectedLocation = true
let seattle = WdtLocation(zip: "000002",
city: "Seattle",
region: "WA",
countryCode: "US",
country: "USA",
lat: "0",
lng: "0")
seattle.currentConditions = WdtCondition()
seattle.currentConditions?.tempC = "17"
seattle.selectedLocation = false
self.allWdtLocations = [sf, seattle]
}
var allLocationsCount: Int { var allLocationsCount: Int {
return allWdtLocations?.count ?? 0 return allWdtLocations?.count ?? 0
...@@ -23,6 +50,16 @@ class WeatherUpdateManager: NSObject { ...@@ -23,6 +50,16 @@ class WeatherUpdateManager: NSObject {
// Return true if it added as a new location, false if it didn't add it or it was a dup // Return true if it added as a new location, false if it didn't add it or it was a dup
func addLocation(_ location: WdtLocation) -> Bool { func addLocation(_ location: WdtLocation) -> Bool {
print("Add location \(location)") print("Add location \(location)")
allWdtLocations?.forEach{$0.selectedLocation = false}
if let index = (allWdtLocations?.firstIndex{$0.hash == location.hash}) {
allWdtLocations?[index].selectedLocation = true
}
else {
location.selectedLocation = true
allWdtLocations?.append(location)
}
return true return true
} }
...@@ -30,6 +67,15 @@ class WeatherUpdateManager: NSObject { ...@@ -30,6 +67,15 @@ class WeatherUpdateManager: NSObject {
// Return true if it added as a new location, false if it didn't add it or it was a dup // Return true if it added as a new location, false if it didn't add it or it was a dup
func deleteLocation(_ location: WdtLocation) -> Bool { func deleteLocation(_ location: WdtLocation) -> Bool {
print("Delete location \(location)") print("Delete location \(location)")
if let locationToDeleteIndex = (allWdtLocations?.firstIndex{location.hash == $0.hash}) {
allWdtLocations?.remove(at: locationToDeleteIndex)
if location.selectedLocation {
allWdtLocations?.first?.selectedLocation = true
}
}
return true return true
} }
......
...@@ -10,6 +10,8 @@ import UIKit ...@@ -10,6 +10,8 @@ import UIKit
class CityCell: UITableViewCell { class CityCell: UITableViewCell {
//Public //Public
static let kIdentifier = "cityCell" static let kIdentifier = "cityCell"
var onSelect:(() -> Void)?
var onAdd:(() -> Void)?
//Private //Private
private let cityLabel = UILabel() private let cityLabel = UILabel()
...@@ -27,20 +29,40 @@ class CityCell: UITableViewCell { ...@@ -27,20 +29,40 @@ class CityCell: UITableViewCell {
prepareTemperatureLabel() prepareTemperatureLabel()
} }
func configure(geoName:GeoNamesPlace, mode:LocationsViewModelDisplayMode) { func configure(wdtLocation:WdtLocation, mode:LocationsViewModelDisplayMode) {
cityLabel.text = geoName.city cityLabel.text = wdtLocation.cityStateName
addButton.isHidden = mode == .savedCities temperatureLabel.text = wdtLocation.currentConditions?.temp ?? "--"
selectedButton.isHidden = mode != .savedCities
switch mode {
case .savedCities:
addButton.isHidden = true
selectedButton.isHidden = false
UIView.performWithoutAnimation {
self.selectedButton.tintColor = wdtLocation.selectedLocation ? ThemeManager.Colors.citySelected : ThemeManager.Colors.cityNoSelected
}
case .popularCities, .searchResults:
addButton.isHidden = false
selectedButton.isHidden = true
}
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@objc private func handleAddButton() {
onAdd?()
}
@objc private func handleSelectButton() {
onSelect?()
}
} }
//MARK: Prepare //MARK: Prepare
private extension CityCell { private extension CityCell {
func prepareCell() { func prepareCell() {
backgroundColor = ThemeManager.currentTheme.navigationBarBackgroundColor
contentView.backgroundColor = ThemeManager.currentTheme.navigationBarBackgroundColor contentView.backgroundColor = ThemeManager.currentTheme.navigationBarBackgroundColor
selectionStyle = .none selectionStyle = .none
} }
...@@ -50,7 +72,7 @@ private extension CityCell { ...@@ -50,7 +72,7 @@ private extension CityCell {
cityLabel.numberOfLines = 1 cityLabel.numberOfLines = 1
cityLabel.lineBreakMode = .byTruncatingTail cityLabel.lineBreakMode = .byTruncatingTail
cityLabel.textColor = ThemeManager.currentTheme.primaryTextColor cityLabel.textColor = ThemeManager.currentTheme.primaryTextColor
cityLabel.setContentHuggingPriority(.init(1000), for: .horizontal) cityLabel.setContentHuggingPriority(.init(900), for: .horizontal)
contentView.addSubview(cityLabel) contentView.addSubview(cityLabel)
cityLabel.snp.makeConstraints { (make) in cityLabel.snp.makeConstraints { (make) in
...@@ -70,6 +92,7 @@ private extension CityCell { ...@@ -70,6 +92,7 @@ private extension CityCell {
temperatureLabel.font = AppFont.SFPro.semibold(size: 16) temperatureLabel.font = AppFont.SFPro.semibold(size: 16)
temperatureLabel.textColor = ThemeManager.currentTheme.primaryTextColor temperatureLabel.textColor = ThemeManager.currentTheme.primaryTextColor
temperatureLabel.setContentHuggingPriority(.init(1000), for: .horizontal) temperatureLabel.setContentHuggingPriority(.init(1000), for: .horizontal)
temperatureLabel.setContentCompressionResistancePriority(.init(1000), for: .horizontal)
container.addSubview(temperatureLabel) container.addSubview(temperatureLabel)
temperatureLabel.snp.makeConstraints { (make) in temperatureLabel.snp.makeConstraints { (make) in
...@@ -94,6 +117,7 @@ private extension CityCell { ...@@ -94,6 +117,7 @@ private extension CityCell {
addButton.setTitleColor(ThemeManager.Colors.locationBlue, for: .normal) addButton.setTitleColor(ThemeManager.Colors.locationBlue, for: .normal)
addButton.backgroundColor = ThemeManager.Colors.cityAddButtonBG addButton.backgroundColor = ThemeManager.Colors.cityAddButtonBG
addButton.layer.cornerRadius = 12 addButton.layer.cornerRadius = 12
addButton.addTarget(self, action: #selector(handleAddButton), for: .touchUpInside)
addButton.layer.shadowOffset = .init(width: 0, height: 2) addButton.layer.shadowOffset = .init(width: 0, height: 2)
addButton.layer.shadowColor = UIColor.black.cgColor addButton.layer.shadowColor = UIColor.black.cgColor
...@@ -115,6 +139,7 @@ private extension CityCell { ...@@ -115,6 +139,7 @@ private extension CityCell {
selectedButton.imageView?.contentMode = .scaleAspectFit selectedButton.imageView?.contentMode = .scaleAspectFit
selectedButton.setImage(UIImage(named: "city_checkmark"), for: .normal) selectedButton.setImage(UIImage(named: "city_checkmark"), for: .normal)
selectedButton.tintColor = ThemeManager.Colors.cityNoSelected selectedButton.tintColor = ThemeManager.Colors.cityNoSelected
selectedButton.addTarget(self, action: #selector(handleAddButton), for: .touchUpInside)
contentView.addSubview(selectedButton) contentView.addSubview(selectedButton)
selectedButton.snp.makeConstraints { (make) in selectedButton.snp.makeConstraints { (make) in
......
...@@ -11,55 +11,74 @@ import AlgoliaSearchClient ...@@ -11,55 +11,74 @@ import AlgoliaSearchClient
protocol LocationsViewModelDelegate:class { protocol LocationsViewModelDelegate:class {
func viewModelDidChange(model:LocationsViewModel) func viewModelDidChange(model:LocationsViewModel)
func viewModelDisplayModeDidChange(model: LocationsViewModel) func viewModelDisplayModeDidChange(model: LocationsViewModel)
func viewModel(model:LocationsViewModel, errorHasOccured error:Error) func viewModel(model:LocationsViewModel, errorHasOccured error: String?)
} }
enum LocationsViewModelDisplayMode { enum LocationsViewModelDisplayMode {
case savedCities case savedCities
case popularCities case popularCities
case searchResult case searchResults
} }
class LocationsViewModel { class LocationsViewModel {
//Public //Public
weak var delegate:LocationsViewModelDelegate? weak var delegate:LocationsViewModelDelegate?
private(set) var cities = [GeoNamesPlace]() { var cities:[WdtLocation] {
switch self.displayMode {
case .savedCities:
return WeatherUpdateManager.shared.allWdtLocations ?? [WdtLocation]()
case .popularCities:
return self.popularCities
case .searchResults:
return self.fetchedCities
}
}
var displayMode:LocationsViewModelDisplayMode = .savedCities {
didSet {
if oldValue == .searchResults {
clean()
}
self.delegate?.viewModelDisplayModeDidChange(model: self)
}
}
//Private
private let popularCitiesManager = PopularCitiesManager()
private var popularCities = [WdtLocation]() {
didSet {
assert(Thread.isMainThread)
self.delegate?.viewModelDidChange(model: self)
}
}
private var fetchedCities = [WdtLocation]() {
didSet { didSet {
assert(Thread.isMainThread) assert(Thread.isMainThread)
self.delegate?.viewModelDidChange(model: self) self.delegate?.viewModelDidChange(model: self)
} }
} }
private(set) var displayMode:LocationsViewModelDisplayMode = .savedCities
init() { //MARK:- ViewModel life cycle
testGeo() func clean() {
fetchedCities.removeAll()
} }
private func testGeo() { func fetchPopularCities() {
let perm = GeoNamesPlace() self.popularCitiesManager.fetchPopularCities {[weak self] result in
perm.city = "Perm asfaskdf aslojkraijasijaowierhopaiwr" guard let strongSelf = self else { return }
perm.stateCode = "614000"
perm.country = "Russia" switch result {
case .success(let popularCities):
let moscow = GeoNamesPlace() DispatchQueue.main.async {
moscow.city = "Moscow" strongSelf.popularCities = popularCities.map{return WdtLocation(place: $0)}
moscow.stateCode = "000000" }
moscow.country = "Russia" case .failure(let error):
strongSelf.delegate?.viewModel(model: strongSelf, errorHasOccured: error.localizedDescription)
let sp = GeoNamesPlace() }
sp.city = "Saint-Petersburg" }
sp.stateCode = "000000"
sp.country = "Russia"
let kazan = GeoNamesPlace()
kazan.city = "Kazan"
kazan.stateCode = "000000"
kazan.country = "Russia"
cities = [perm, moscow, sp, kazan]
} }
func fetchCities(query:String) { func fetchCities(query:String) {
// This is a test location that can be interpreted on the server to return all alerts // This is a test location that can be interpreted on the server to return all alerts
guard query != "1wville" else { guard query != "1wville" else {
let fakePlace = GeoNamesPlace() let fakePlace = GeoNamesPlace()
...@@ -74,7 +93,7 @@ class LocationsViewModel { ...@@ -74,7 +93,7 @@ class LocationsViewModel {
fakePlace.toponymName = "1WVille" fakePlace.toponymName = "1WVille"
DispatchQueue.main.async { DispatchQueue.main.async {
self.cities = [] self.fetchedCities = []
} }
return return
} }
...@@ -90,7 +109,9 @@ class LocationsViewModel { ...@@ -90,7 +109,9 @@ class LocationsViewModel {
var filteredPlaces = [GeoNamesPlace]() var filteredPlaces = [GeoNamesPlace]()
placesClient.search(query: algoliaQuery, language: language, requestOptions: nil) { (result: Result<PlacesClient.SingleLanguageResponse, Error>) in placesClient.search(query: algoliaQuery, language: language, requestOptions: nil) {[weak self] (result: Result<PlacesClient.SingleLanguageResponse, Error>) in
guard let strongSelf = self else { return }
switch (result) { switch (result) {
case .success(let response): case .success(let response):
print("Search: got \(response.nbHits) results") print("Search: got \(response.nbHits) results")
...@@ -117,30 +138,51 @@ class LocationsViewModel { ...@@ -117,30 +138,51 @@ class LocationsViewModel {
filteredPlaces.append(place) filteredPlaces.append(place)
} }
DispatchQueue.main.async { DispatchQueue.main.async {
self.cities = filteredPlaces strongSelf.fetchedCities = filteredPlaces.map{return WdtLocation(place: $0)}
} }
break break
case .failure(let error): case .failure(let error):
DispatchQueue.main.async { DispatchQueue.main.async {
self.delegate?.viewModel(model: self, errorHasOccured: error) strongSelf.delegate?.viewModel(model: strongSelf, errorHasOccured: error.localizedDescription)
} }
break break
} }
} }
} }
func add(city:GeoNamesPlace) { //MARK:- City CUD methods
func add(city:WdtLocation) {
// TODO: Just update self.cities, it will trigger a viewModelDidChange call // TODO: Just update self.cities, it will trigger a viewModelDidChange call
// let newCity = WdtLocation(zip: nil, city: "New City", region: "NS", countryCode: "US", country: "USA", lat: nil, lng: nil)
if WeatherUpdateManager.shared.addLocation(city) {
self.delegate?.viewModelDidChange(model: self)
}
else {
self.delegate?.viewModel(model: self, errorHasOccured: "Failed to add location")
}
} }
func delete(city:GeoNamesPlace) { func delete(city:WdtLocation) {
// TODO: Just update self.cities, it will trigger a viewModelDidChange call // TODO: Just update self.cities, it will trigger a viewModelDidChange call
if WeatherUpdateManager.shared.deleteLocation(city) {
self.delegate?.viewModelDidChange(model: self)
}
else {
self.delegate?.viewModel(model: self, errorHasOccured: "Failed to delete location")
}
} }
func select(city:GeoNamesPlace) { func select(city:WdtLocation) {
// TODO: Tell delegate to refresh UI // TODO: Tell delegate to refresh UI
self.delegate?.viewModelDidChange(model: self)
if WeatherUpdateManager.shared.addLocation(city) {
self.delegate?.viewModelDidChange(model: self)
}
else {
self.delegate?.viewModel(model: self, errorHasOccured: "Failed to add location")
}
} }
} }
No preview for this file type
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1100" LastUpgradeVersion = "1220"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
<BuildActionEntries> <BuildActionEntries>
<BuildActionEntry <BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES" buildForTesting = "YES"
buildForRunning = "YES" buildForRunning = "YES"
buildForProfiling = "YES" buildForProfiling = "YES"
buildForArchiving = "YES"> buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "501CD213CC527E89056B36384FE73683" BlueprintIdentifier = "501CD213CC527E89056B36384FE73683"
...@@ -23,14 +23,15 @@ ...@@ -23,14 +23,15 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES">
buildConfiguration = "Debug"> <Testables>
<AdditionalOptions> </Testables>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"
...@@ -38,17 +39,14 @@ ...@@ -38,17 +39,14 @@
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES">
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction> </ProfileAction>
<AnalyzeAction <AnalyzeAction
buildConfiguration = "Debug"> buildConfiguration = "Debug">
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1100" LastUpgradeVersion = "1220"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
<BuildActionEntries> <BuildActionEntries>
<BuildActionEntry <BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES" buildForTesting = "YES"
buildForRunning = "YES" buildForRunning = "YES"
buildForProfiling = "YES" buildForProfiling = "YES"
buildForArchiving = "YES"> buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "2ABF3F8EC6CE525E1E02C51D72C64E94" BlueprintIdentifier = "2ABF3F8EC6CE525E1E02C51D72C64E94"
...@@ -23,14 +23,15 @@ ...@@ -23,14 +23,15 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES">
buildConfiguration = "Debug"> <Testables>
<AdditionalOptions> </Testables>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"
...@@ -38,17 +39,14 @@ ...@@ -38,17 +39,14 @@
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES">
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction> </ProfileAction>
<AnalyzeAction <AnalyzeAction
buildConfiguration = "Debug"> buildConfiguration = "Debug">
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1100" LastUpgradeVersion = "1220"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1100" LastUpgradeVersion = "1220"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
<BuildActionEntries> <BuildActionEntries>
<BuildActionEntry <BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES" buildForTesting = "YES"
buildForRunning = "YES" buildForRunning = "YES"
buildForProfiling = "YES" buildForProfiling = "YES"
buildForArchiving = "YES"> buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "19622742EBA51E823D6DAE3F8CDBFAD4" BlueprintIdentifier = "19622742EBA51E823D6DAE3F8CDBFAD4"
...@@ -23,14 +23,15 @@ ...@@ -23,14 +23,15 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES">
buildConfiguration = "Debug"> <Testables>
<AdditionalOptions> </Testables>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"
...@@ -38,17 +39,14 @@ ...@@ -38,17 +39,14 @@
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES">
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction> </ProfileAction>
<AnalyzeAction <AnalyzeAction
buildConfiguration = "Debug"> buildConfiguration = "Debug">
......
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