Commit ce879c83 by Dmitriy Stepanets

Working on Locations UI logic

parent f0f001bc
......@@ -24,6 +24,8 @@
CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */; };
CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303D25726960004B34B3 /* ThemeProtocol.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 */; };
CDA69B30257500E200CB6409 /* GeoNamesPlace.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA69B2F257500E200CB6409 /* GeoNamesPlace.swift */; };
CDA69B3325750D3400CB6409 /* LocationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA69B3225750D3400CB6409 /* LocationsViewModel.swift */; };
......@@ -57,6 +59,8 @@
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>"; };
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>"; };
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>"; };
......@@ -112,6 +116,7 @@
isa = PBXGroup;
children = (
CD1237DA255D5DFA00C98139 /* PG.playground */,
CD8091752578D726003541A4 /* Managers */,
CDD0F1DC2572400200CF5017 /* UI */,
CD1237EF255D838600C98139 /* Extensions */,
CDD0F1E2257240DA00CF5017 /* Resources */,
......@@ -138,6 +143,7 @@
children = (
CD1237F0255D83C500C98139 /* UIColor+Hex.swift */,
CD6B3035257262C2004B34B3 /* UIColor+Highlight.swift */,
CD80917A2578E4A8003541A4 /* UIViewController+Alert.swift */,
);
path = Extensions;
sourceTree = "<group>";
......@@ -167,6 +173,14 @@
path = Themes;
sourceTree = "<group>";
};
CD8091752578D726003541A4 /* Managers */ = {
isa = PBXGroup;
children = (
CD8091762578D73F003541A4 /* PopularCitiesManager.swift */,
);
path = Managers;
sourceTree = "<group>";
};
CDA69B2A2574F3A700CB6409 /* Cells */ = {
isa = PBXGroup;
children = (
......@@ -275,7 +289,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1210;
LastUpgradeCheck = 1210;
LastUpgradeCheck = 1220;
TargetAttributes = {
CD1237BE255D5C5900C98139 = {
CreatedOnToolsVersion = 12.1;
......@@ -379,7 +393,9 @@
870880222578ED190076BFB1 /* WdtHourSummary.swift in Sources */,
CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */,
CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */,
CD8091772578D73F003541A4 /* PopularCitiesManager.swift in Sources */,
CDA69B2C2574F3C800CB6409 /* CityCell.swift in Sources */,
CD80917B2578E4A8003541A4 /* UIViewController+Alert.swift in Sources */,
CD1237DE255D612300C98139 /* CurrentForecastCell.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 {
static let citySelected = UIColor(hex: 0x599A0E)
static let cityNoSelected = UIColor(hex: 0xC5C5C5).withAlphaComponent(0.5)
static let cityAddButtonBG = UIColor(hex: 0x131315)
static let searchBarTint = UIColor(hex: 0xEBEBF5).withAlphaComponent(0.6)
}
static var currentTheme:ThemeProtocol {
......
......@@ -9,8 +9,6 @@
import UIKit
class WdtLocation: NSObject, NSCoding {
static let LOCATION = "location"
static let CONDITIONS = "conditions"
static let DAYSUMMARIES = "daysummaries"
......@@ -33,6 +31,27 @@ class WdtLocation: NSObject, NSCoding {
var zip: String?
fileprivate 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 {
get {
......@@ -125,7 +144,6 @@ class WdtLocation: NSObject, NSCoding {
cityState = ""
uvDesc = ""
detailName = ""
fullName = ""
locationId = "us"
fileName = "us"
simpleFileName = "us"
......@@ -139,7 +157,6 @@ class WdtLocation: NSObject, NSCoding {
cityState = ""
uvDesc = ""
detailName = ""
fullName = ""
locationId = "us"
fileName = "us"
simpleFileName = "us"
......@@ -177,7 +194,6 @@ class WdtLocation: NSObject, NSCoding {
cityState = ""
uvDesc = ""
detailName = ""
fullName = ""
locationId = ""
fileName = ""
simpleFileName = ""
......@@ -242,8 +258,6 @@ class WdtLocation: NSObject, NSCoding {
var detailName: String
var fullName: String
var isDay: Bool = false
......
......@@ -11,6 +11,33 @@ import UserNotifications
class WeatherUpdateManager: NSObject {
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 {
return allWdtLocations?.count ?? 0
......@@ -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
func addLocation(_ location: WdtLocation) -> Bool {
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
}
......@@ -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
func deleteLocation(_ location: WdtLocation) -> Bool {
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
}
......
......@@ -10,6 +10,8 @@ import UIKit
class CityCell: UITableViewCell {
//Public
static let kIdentifier = "cityCell"
var onSelect:(() -> Void)?
var onAdd:(() -> Void)?
//Private
private let cityLabel = UILabel()
......@@ -27,20 +29,40 @@ class CityCell: UITableViewCell {
prepareTemperatureLabel()
}
func configure(geoName:GeoNamesPlace, mode:LocationsViewModelDisplayMode) {
cityLabel.text = geoName.city
addButton.isHidden = mode == .savedCities
selectedButton.isHidden = mode != .savedCities
func configure(wdtLocation:WdtLocation, mode:LocationsViewModelDisplayMode) {
cityLabel.text = wdtLocation.cityStateName
temperatureLabel.text = wdtLocation.currentConditions?.temp ?? "--"
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) {
fatalError("init(coder:) has not been implemented")
}
@objc private func handleAddButton() {
onAdd?()
}
@objc private func handleSelectButton() {
onSelect?()
}
}
//MARK: Prepare
private extension CityCell {
func prepareCell() {
backgroundColor = ThemeManager.currentTheme.navigationBarBackgroundColor
contentView.backgroundColor = ThemeManager.currentTheme.navigationBarBackgroundColor
selectionStyle = .none
}
......@@ -50,7 +72,7 @@ private extension CityCell {
cityLabel.numberOfLines = 1
cityLabel.lineBreakMode = .byTruncatingTail
cityLabel.textColor = ThemeManager.currentTheme.primaryTextColor
cityLabel.setContentHuggingPriority(.init(1000), for: .horizontal)
cityLabel.setContentHuggingPriority(.init(900), for: .horizontal)
contentView.addSubview(cityLabel)
cityLabel.snp.makeConstraints { (make) in
......@@ -70,6 +92,7 @@ private extension CityCell {
temperatureLabel.font = AppFont.SFPro.semibold(size: 16)
temperatureLabel.textColor = ThemeManager.currentTheme.primaryTextColor
temperatureLabel.setContentHuggingPriority(.init(1000), for: .horizontal)
temperatureLabel.setContentCompressionResistancePriority(.init(1000), for: .horizontal)
container.addSubview(temperatureLabel)
temperatureLabel.snp.makeConstraints { (make) in
......@@ -94,6 +117,7 @@ private extension CityCell {
addButton.setTitleColor(ThemeManager.Colors.locationBlue, for: .normal)
addButton.backgroundColor = ThemeManager.Colors.cityAddButtonBG
addButton.layer.cornerRadius = 12
addButton.addTarget(self, action: #selector(handleAddButton), for: .touchUpInside)
addButton.layer.shadowOffset = .init(width: 0, height: 2)
addButton.layer.shadowColor = UIColor.black.cgColor
......@@ -115,6 +139,7 @@ private extension CityCell {
selectedButton.imageView?.contentMode = .scaleAspectFit
selectedButton.setImage(UIImage(named: "city_checkmark"), for: .normal)
selectedButton.tintColor = ThemeManager.Colors.cityNoSelected
selectedButton.addTarget(self, action: #selector(handleAddButton), for: .touchUpInside)
contentView.addSubview(selectedButton)
selectedButton.snp.makeConstraints { (make) in
......
......@@ -10,7 +10,7 @@ import UIKit
//MARK:- Location Navigation View Controller
class LocationViewController: UINavigationController {
init() {
let savedCitiesViewController = SavedCitiesViewController()
let savedCitiesViewController = CitiesViewController()
super.init(rootViewController: savedCitiesViewController)
}
......@@ -31,23 +31,53 @@ class LocationViewController: UINavigationController {
}
}
private class SavedCitiesViewController:UIViewController {
//MARK:- Cities View Controller
private enum EditButtonStyle {
case edit
case done
}
private class CitiesViewController:UIViewController {
//Private
private let searchBar = UISearchBar()
private let locationButton = SelfSizingButton(frame: .zero)
private let tableView = UITableView()
private let editButton = SelfSizingButton()
private let locationsViewModel = LocationsViewModel()
private let searchQueue:OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return queue
}()
override func viewDidLoad() {
super.viewDidLoad()
super.viewDidLoad()
view.backgroundColor = ThemeManager.currentTheme.navigationBarBackgroundColor
edgesForExtendedLayout = []
self.locationsViewModel.delegate = self
prepareNavBar()
prepareSearchBar()
prepareLocationButton()
prepareTableView()
prepareEditButton()
}
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)
}
}
}
@objc private func handleCloseButton() {
......@@ -58,13 +88,14 @@ private class SavedCitiesViewController:UIViewController {
}
@objc private func handleEditButton() {
@objc private func handleEditButton(button:UIButton) {
tableView.setEditing(!tableView.isEditing, animated: true)
self.updateEditButton(style: tableView.isEditing ? .done : .edit)
}
}
//MARK:- Saved cities prepare
private extension SavedCitiesViewController {
private extension CitiesViewController {
func prepareNavBar() {
self.navigationController?.view.backgroundColor = .white
......@@ -93,8 +124,12 @@ private extension SavedCitiesViewController {
}
func prepareSearchBar() {
let searchBarTextField = searchBar.value(forKey: "searchField") as? UITextField
searchBarTextField?.textColor = ThemeManager.currentTheme.navigationTintColor
searchBarTextField?.leftView?.tintColor = ThemeManager.Colors.searchBarTint
searchBar.searchBarStyle = .minimal
searchBar.placeholder = "Search".localized(comment: "Search bar placeholder text.")
searchBar.delegate = self
view.addSubview(searchBar)
searchBar.snp.makeConstraints { (make) in
make.top.equalToSuperview()
......@@ -106,7 +141,7 @@ private extension SavedCitiesViewController {
func prepareLocationButton() {
locationButton.tintColor = ThemeManager.Colors.locationBlue
locationButton.setImage(UIImage(named: "location_arrow"), for: .normal)
locationButton.setTitle("Use Current Location", for: .normal)
locationButton.setTitle("Use Current Location".localized, for: .normal)
locationButton.setTitleColor(ThemeManager.Colors.locationBlue, for: .normal)
locationButton.setTitleColor(ThemeManager.Colors.locationBlue.highlighted, for: .highlighted)
locationButton.addTarget(self, action: #selector(handleLocationButton), for: .touchUpInside)
......@@ -122,7 +157,6 @@ private extension SavedCitiesViewController {
}
func prepareTableView() {
let tableView = UITableView()
tableView.backgroundColor = view.backgroundColor
tableView.register(CityCell.self, forCellReuseIdentifier: CityCell.kIdentifier)
tableView.tableFooterView = UIView()
......@@ -138,50 +172,87 @@ private extension SavedCitiesViewController {
make.bottom.equalToSuperview()
}
}
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)
}
}
//MARK:- LocationsViewModel Delegate
extension CitiesViewController: LocationsViewModelDelegate {
func viewModelDidChange(model: LocationsViewModel) {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
func viewModelDisplayModeDidChange(model: LocationsViewModel) {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
func viewModel(model: LocationsViewModel, errorHasOccured error: String?) {
self.showAlert(withTitle: "Error", message: error)
}
}
//MARK: UItableView Data Source
extension SavedCitiesViewController: UITableViewDataSource {
extension CitiesViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return locationsViewModel.cities.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CityCell.kIdentifier, for: indexPath) as! CityCell
cell.configure(geoName: locationsViewModel.cities[indexPath.row],
cell.configure(wdtLocation: locationsViewModel.cities[indexPath.row],
mode: locationsViewModel.displayMode)
cell.onAdd = { [weak self] in
guard let strongSelf = self else { return }
strongSelf.locationsViewModel.add(city: strongSelf.locationsViewModel.cities[indexPath.row])
}
cell.onSelect = {[weak self] in
guard let strongSelf = self else { return }
strongSelf.locationsViewModel.select(city: strongSelf.locationsViewModel.cities[indexPath.row])
}
return cell
}
}
//MARK: UITableView Delegate
extension SavedCitiesViewController: UITableViewDelegate {
extension CitiesViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let container = UIView()
container.backgroundColor = ThemeManager.currentTheme.navigationBarBackgroundColor
let titleLabel = UILabel()
titleLabel.text = "Saved Cities".localized + "( \(self.locationsViewModel.cities.count))"
titleLabel.font = AppFont.SFPro.bold(size: 24)
titleLabel.textColor = ThemeManager.currentTheme.primaryTextColor
container.addSubview(titleLabel)
if locationsViewModel.displayMode == .savedCities {
let editButton = SelfSizingButton()
editButton.setImage(UIImage(named: "edit_pencil"), for: .normal)
editButton.tintColor = ThemeManager.Colors.locationBlue
editButton.setTitle("EDIT", 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), for: .touchUpInside)
switch self.locationsViewModel.displayMode {
case .savedCities:
titleLabel.text = "Saved Cities".localized + "(\(self.locationsViewModel.cities.count))"
//Add Edit button
container.addSubview(editButton)
editButton.snp.makeConstraints { (make) in
make.right.equalToSuperview().inset(24)
make.bottom.equalTo(titleLabel)
}
case .popularCities:
titleLabel.text = "5 Popular cities".localized
case .searchResults:
titleLabel.text = "Results".localized + "(\(self.locationsViewModel.cities.count))"
}
titleLabel.snp.makeConstraints { (make) in
......@@ -192,4 +263,66 @@ extension SavedCitiesViewController: UITableViewDelegate {
return container
}
func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {
print("Will begin editing")
self.updateEditButton(style: .done)
}
func tableView(_ tableView: UITableView, didEndEditingRowAt indexPath: IndexPath?) {
print("Did end editing")
self.updateEditButton(style: .edit)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let cityToDelete = self.locationsViewModel.cities[indexPath.row]
self.locationsViewModel.delete(city: cityToDelete)
}
}
//MARK:- UISearchBar Delegate
extension CitiesViewController: UISearchBarDelegate {
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(true, animated: true)
self.locationsViewModel.displayMode = .popularCities
self.locationsViewModel.fetchPopularCities()
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
defer {
self.locationsViewModel.displayMode = .searchResults
}
if searchText.count == 0 {
self.locationsViewModel.clean()
return
}
searchQueue.cancelAllOperations()
let operation = BlockOperation()
weak var weakOperation = operation
operation.addExecutionBlock { [weak self] in
Thread.sleep(forTimeInterval: 0.5)
guard weakOperation?.isCancelled == false else {
return
}
self?.locationsViewModel.fetchCities(query: searchText)
}
searchQueue.addOperation(operation)
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: true)
self.searchBar.endEditing(true)
searchBar.text = nil
self.locationsViewModel.displayMode = .savedCities
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: true)
self.searchBar.endEditing(true)
}
}
......@@ -11,55 +11,74 @@ import AlgoliaSearchClient
protocol LocationsViewModelDelegate:class {
func viewModelDidChange(model:LocationsViewModel)
func viewModelDisplayModeDidChange(model: LocationsViewModel)
func viewModel(model:LocationsViewModel, errorHasOccured error:Error)
func viewModel(model:LocationsViewModel, errorHasOccured error: String?)
}
enum LocationsViewModelDisplayMode {
case savedCities
case popularCities
case searchResult
case searchResults
}
class LocationsViewModel {
//Public
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(set) var displayMode:LocationsViewModelDisplayMode = .savedCities
init() {
testGeo()
private var fetchedCities = [WdtLocation]() {
didSet {
assert(Thread.isMainThread)
self.delegate?.viewModelDidChange(model: self)
}
}
private func testGeo() {
let perm = GeoNamesPlace()
perm.city = "Perm asfaskdf aslojkraijasijaowierhopaiwr"
perm.stateCode = "614000"
perm.country = "Russia"
let moscow = GeoNamesPlace()
moscow.city = "Moscow"
moscow.stateCode = "000000"
moscow.country = "Russia"
//MARK:- ViewModel life cycle
func clean() {
fetchedCities.removeAll()
}
let sp = GeoNamesPlace()
sp.city = "Saint-Petersburg"
sp.stateCode = "000000"
sp.country = "Russia"
func fetchPopularCities() {
self.popularCitiesManager.fetchPopularCities {[weak self] result in
guard let strongSelf = self else { return }
let kazan = GeoNamesPlace()
kazan.city = "Kazan"
kazan.stateCode = "000000"
kazan.country = "Russia"
cities = [perm, moscow, sp, kazan]
switch result {
case .success(let popularCities):
DispatchQueue.main.async {
strongSelf.popularCities = popularCities.map{return WdtLocation(place: $0)}
}
case .failure(let error):
strongSelf.delegate?.viewModel(model: strongSelf, errorHasOccured: error.localizedDescription)
}
}
}
func fetchCities(query:String) {
// This is a test location that can be interpreted on the server to return all alerts
guard query != "1wville" else {
let fakePlace = GeoNamesPlace()
......@@ -74,7 +93,7 @@ class LocationsViewModel {
fakePlace.toponymName = "1WVille"
DispatchQueue.main.async {
self.cities = []
self.fetchedCities = []
}
return
}
......@@ -90,7 +109,9 @@ class LocationsViewModel {
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) {
case .success(let response):
print("Search: got \(response.nbHits) results")
......@@ -117,30 +138,51 @@ class LocationsViewModel {
filteredPlaces.append(place)
}
DispatchQueue.main.async {
self.cities = filteredPlaces
strongSelf.fetchedCities = filteredPlaces.map{return WdtLocation(place: $0)}
}
break
case .failure(let error):
DispatchQueue.main.async {
self.delegate?.viewModel(model: self, errorHasOccured: error)
strongSelf.delegate?.viewModel(model: strongSelf, errorHasOccured: error.localizedDescription)
}
break
}
}
}
func add(city:GeoNamesPlace) {
//MARK:- City CUD methods
func add(city:WdtLocation) {
// 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
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
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
......@@ -466,7 +466,7 @@
438C6B748266BEE80EA0A61421AB1DC5 /* Transport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Transport.swift; path = Sources/AlgoliaSearchClient/Transport/Common/Transport.swift; sourceTree = "<group>"; };
43CA5B2AE7B71A765DBF6E7CE8FD0380 /* Hit.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Hit.swift; path = Sources/AlgoliaSearchClient/Models/Search/Hit/Hit.swift; sourceTree = "<group>"; };
43F37669F1A1D739503181E11E936241 /* AnyWaitable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyWaitable.swift; path = Sources/AlgoliaSearchClient/Helpers/Wait/AnyWaitable.swift; sourceTree = "<group>"; };
4418FB4E800DFA4DB13A6252DCF8A266 /* Pods_1Weather.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_1Weather.framework; path = "Pods-1Weather.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
4418FB4E800DFA4DB13A6252DCF8A266 /* Pods_1Weather.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_1Weather.framework; sourceTree = BUILT_PRODUCTS_DIR; };
44314B3A082956F6E67EAAEBEDF20203 /* AsyncOperation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncOperation.swift; path = Sources/AlgoliaSearchClient/Async/AsyncOperation.swift; sourceTree = "<group>"; };
4451CAD26B82503E6C6A9F73392D0259 /* PathComponent.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PathComponent.swift; path = Sources/AlgoliaSearchClient/Models/Internal/Path/PathComponent.swift; sourceTree = "<group>"; };
4717C4D256C32A29F1E5544304FAFF0F /* LayoutConstraintItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LayoutConstraintItem.swift; path = Source/LayoutConstraintItem.swift; sourceTree = "<group>"; };
......@@ -559,7 +559,7 @@
895B3A8A73AEB00123729C2E1C6138B6 /* TaggedString.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TaggedString.swift; path = Sources/AlgoliaSearchClient/Models/Search/Response/SearchResponse/Auxiliary/Highlighting/TaggedString.swift; sourceTree = "<group>"; };
89FAA39CC1F46DECB0200EBD443BDCDE /* Cursor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cursor.swift; path = Sources/AlgoliaSearchClient/Models/Search/Indexing/Cursor.swift; sourceTree = "<group>"; };
8B363907CD28FB366DF6B8CB60A29DB1 /* FacetStats.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FacetStats.swift; path = Sources/AlgoliaSearchClient/Models/Search/Response/SearchResponse/Auxiliary/FacetStats/FacetStats.swift; sourceTree = "<group>"; };
8BC89BBA07ABC039D176A0220D50F6E2 /* AlgoliaSearchClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = AlgoliaSearchClient.framework; path = AlgoliaSearchClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8BC89BBA07ABC039D176A0220D50F6E2 /* AlgoliaSearchClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AlgoliaSearchClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8CA8B75533EC930206B9AC674A8680DB /* ClientDateCodingStrategy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ClientDateCodingStrategy.swift; path = Sources/AlgoliaSearchClient/Helpers/Coding/Date/ClientDateCodingStrategy.swift; sourceTree = "<group>"; };
8D9F168995CEEE7755D8FFCAF33E1197 /* Path.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Path.swift; path = Sources/AlgoliaSearchClient/Models/Internal/Path/Path.swift; sourceTree = "<group>"; };
8DE07A549CBA73BA74BFD3C4554FD15F /* BoolContainer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BoolContainer.swift; path = Sources/AlgoliaSearchClient/Helpers/Coding/Wrappers/BoolContainer.swift; sourceTree = "<group>"; };
......@@ -572,14 +572,14 @@
95583237E77B7F62739559AD33396C0A /* Logging.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Logging.release.xcconfig; sourceTree = "<group>"; };
9730EC6BB0C718FBA03EE62D0C832E89 /* AlgoliaSearchClient-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "AlgoliaSearchClient-Info.plist"; sourceTree = "<group>"; };
97859DC2CD452FEA47EF1A5B35E75B14 /* TimeRange.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TimeRange.swift; path = Sources/AlgoliaSearchClient/Models/Common/TimeRange.swift; sourceTree = "<group>"; };
979486118B3E90C08386079D57962701 /* SnapKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SnapKit.framework; path = SnapKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
979486118B3E90C08386079D57962701 /* SnapKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SnapKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
97978974EBDA3629FAF8F7B484D2CBF6 /* TransportContainer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransportContainer.swift; path = Sources/AlgoliaSearchClient/Transport/Common/TransportContainer.swift; sourceTree = "<group>"; };
97E32C02BFE41CA9E5DB175D8ED61483 /* Transport+CustomRequest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Transport+CustomRequest.swift"; path = "Sources/AlgoliaSearchClient/Transport/Common/Transport+CustomRequest.swift"; sourceTree = "<group>"; };
9BB2FCF94697E5CC72393A20418CB467 /* ConstraintLayoutGuideDSL.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintLayoutGuideDSL.swift; path = Source/ConstraintLayoutGuideDSL.swift; sourceTree = "<group>"; };
9BF5BCCDB63902AD39DAEC7EBBFB7B86 /* ConstraintOffsetTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintOffsetTarget.swift; path = Source/ConstraintOffsetTarget.swift; sourceTree = "<group>"; };
9C27A6306CED6A52F9F42197B318913D /* SearchClient+APIKey.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SearchClient+APIKey.swift"; path = "Sources/AlgoliaSearchClient/Client/Search/SearchClient+APIKey.swift"; sourceTree = "<group>"; };
9D0BCAC1D7172B5D44F0E1B5DE690E2C /* MatchLevel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MatchLevel.swift; path = Sources/AlgoliaSearchClient/Models/Search/Hit/MatchLevel.swift; sourceTree = "<group>"; };
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
9EF3C6A7EBDCBDF83BBA52FD4CDD03D7 /* AnalyticsClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnalyticsClient.swift; path = Sources/AlgoliaSearchClient/Client/AnalyticsClient.swift; sourceTree = "<group>"; };
9F6FEA6785E4A746B66D36B6C6929316 /* TopUserIDResponse.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TopUserIDResponse.swift; path = Sources/AlgoliaSearchClient/Models/MultiCluster/TopUserIDResponse.swift; sourceTree = "<group>"; };
A0408627B86CC1DCD7AB5ED6425A49C0 /* SearchClient+MultiCluster.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SearchClient+MultiCluster.swift"; path = "Sources/AlgoliaSearchClient/Client/Search/SearchClient+MultiCluster.swift"; sourceTree = "<group>"; };
......@@ -591,7 +591,7 @@
A32B6EC0910F6D16360EB7B128939375 /* Pods-1Weather-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-1Weather-dummy.m"; sourceTree = "<group>"; };
A32E9E68F3B2F8221A461CFF3CAC9C20 /* SearchClient+Logs.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SearchClient+Logs.swift"; path = "Sources/AlgoliaSearchClient/Client/Search/SearchClient+Logs.swift"; sourceTree = "<group>"; };
A6103C61FDB009CBF30062E07BEA8E15 /* RecommendationClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecommendationClient.swift; path = Sources/AlgoliaSearchClient/Client/RecommendationClient.swift; sourceTree = "<group>"; };
A6513E0A6CB60623515716E73996F0F5 /* Logging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Logging.framework; path = Logging.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A6513E0A6CB60623515716E73996F0F5 /* Logging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Logging.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A665BA0A5E49A37993662ABFFFE2FEB7 /* FacetsStorage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FacetsStorage.swift; path = Sources/AlgoliaSearchClient/Models/Search/Response/SearchResponse/Auxiliary/Facet/FacetsStorage.swift; sourceTree = "<group>"; };
A73BB1CDB727E0EC318F4E61DB9A8BA5 /* AlgoliaSearchClient-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "AlgoliaSearchClient-dummy.m"; sourceTree = "<group>"; };
A7F13D1A2767DC6B7667EA21883DEF3A /* QueryID.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = QueryID.swift; path = Sources/AlgoliaSearchClient/Models/Search/Query/QueryID.swift; sourceTree = "<group>"; };
......@@ -810,7 +810,6 @@
F72317B4D957B3956CEA8C47AECB20FD /* UILayoutSupport+Extensions.swift */,
53AE55659433C8AD57D5E71785FC5C94 /* Support Files */,
);
name = SnapKit;
path = SnapKit;
sourceTree = "<group>";
};
......@@ -837,7 +836,6 @@
AD64B0F1C0ABD2D396AC70142B7F0B95 /* LogHandler.swift */,
8D67773DDB44F1F8B287710200467BA7 /* Support Files */,
);
name = Logging;
path = Logging;
sourceTree = "<group>";
};
......@@ -1160,7 +1158,6 @@
394D4D791D983A66A90DF27CF3BC36CB /* WaitTask.swift */,
45473BBE74E1139386E8AF33A22B9A54 /* Support Files */,
);
name = AlgoliaSearchClient;
path = AlgoliaSearchClient;
sourceTree = "<group>";
};
......@@ -1333,7 +1330,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1100;
LastUpgradeCheck = 1100;
LastUpgradeCheck = 1220;
};
buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */;
compatibilityVersion = "Xcode 10.0";
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1220"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES">
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "501CD213CC527E89056B36384FE73683"
......@@ -23,14 +23,15 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
......@@ -38,17 +39,14 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1220"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES">
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2ABF3F8EC6CE525E1E02C51D72C64E94"
......@@ -23,14 +23,15 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
......@@ -38,17 +39,14 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1220"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1220"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES">
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "19622742EBA51E823D6DAE3F8CDBFAD4"
......@@ -23,14 +23,15 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
......@@ -38,17 +39,14 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
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