├── Cartfile ├── Cartfile.resolved ├── .gitignore ├── ReswiftAppCoordinatorDemo ├── fonts.swift ├── colors.swift ├── LoadingActions.swift ├── ErrorMessageActions.swift ├── StringUtil.swift ├── SearchResultsCoordinator.swift ├── AppState.swift ├── AppCoordinator.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── PropertyDetailSceneViewController.swift ├── SearchView.swift ├── SearchResultViewController.swift ├── PropertyDetailView.swift ├── SearchSceneCoordinator.swift ├── SearchResultView.swift ├── Info.plist ├── SearchSceneViewController.swift ├── PropertyApi.swift ├── LocationTracker.swift ├── BaseViewController.swift ├── XibBaseView.swift ├── SearchResultView.xib ├── AppDelegate.swift ├── PropertyActions.swift ├── AppReducer.swift ├── Base.lproj │ └── LaunchScreen.storyboard ├── SearchView.xib └── PropertyDetailView.xib ├── ReswiftAppCoordinatorDemo.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcuserdata │ └── xnliu.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── ReswiftAppCoordinatorDemo.xcscheme └── project.pbxproj └── ReswiftAppCoordinatorDemoTests ├── StringUtilSpec.swift └── Info.plist /Cartfile: -------------------------------------------------------------------------------- 1 | github "ReSwift/ReSwift" 2 | github "Alamofire/Alamofire" ~> 4.0 3 | github "Quick/Quick" 4 | github "Quick/Nimble" 5 | 6 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "Alamofire/Alamofire" "4.4.0" 2 | github "Quick/Nimble" "v7.0.0" 3 | github "Quick/Quick" "v1.1.0" 4 | github "ReSwift/ReSwift" "4.0.0" 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | *.DS_Store 3 | 4 | # Xcode 5 | *.pbxuser 6 | *.mode1v3 7 | *.mode2v3 8 | *.perspectivev3 9 | *.xcuserstate 10 | project.xcworkspace/ 11 | xcuserdata/ 12 | 13 | #Carthage 14 | Carthage/ 15 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/fonts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // fonts.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/colors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Colors.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | struct Colors { 10 | static let blue = "#656565" 11 | } 12 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/LoadingActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoadingActions.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import ReSwift 9 | 10 | struct StartLoading: Action {} 11 | struct EndLoading: Action {} 12 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/ErrorMessageActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ErrorMessageReducer.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import ReSwift 10 | 11 | struct SaveErrorMessage: Action { 12 | let errorMessage:String 13 | } 14 | 15 | struct CleanErrorMessage: Action {} 16 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemoTests/StringUtilSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringUtilTests.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 09/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import Quick 9 | import Nimble 10 | 11 | class StringUtilSpec: QuickSpec { 12 | override func spec() { 13 | describe("formatForPound") { 14 | it("format double to string in pound format") { 15 | expect(StringUtil.formatForPound(59500.0)).to(equal("£59,500")) 16 | } 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/StringUtil.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringUtility.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 09/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import Foundation 9 | 10 | struct StringUtil { 11 | static func formatForPound(_ number: Double) -> String{ 12 | let numberFormatter = NumberFormatter() 13 | numberFormatter.numberStyle = NumberFormatter.Style.decimal 14 | let numberString = numberFormatter.string(from: NSNumber(value: number))! 15 | return "£\(numberString)" 16 | }} 17 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo.xcodeproj/xcuserdata/xnliu.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ReswiftAppCoordinatorDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | DF3072681E1BA625005AA130 16 | 17 | primary 18 | 19 | 20 | DF30727C1E1BA625005AA130 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/SearchResultsCoordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultsCoordinator.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 09/03/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol SearchResultsSceneCoordinatorProtocol { 12 | func showPropertyDetail(index:Int) 13 | } 14 | 15 | class SearchResultsSceneCoordinator:AppCoordinator,SearchResultsSceneCoordinatorProtocol { 16 | let propertyActionCreater = PropertyActionCreater() 17 | 18 | func showPropertyDetail(index:Int) { 19 | mainStore.dispatch(UpdateSelectedProperty(selectedPropertyIndex: index)) 20 | let propertyDetailVC = PropertyDetailSceneViewController(); 21 | self.rootVC.pushViewController(propertyDetailVC, animated: true) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/AppState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppState.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import ReSwift 9 | 10 | struct AppState: StateType { 11 | var isLoading:Bool = false 12 | var errorMessage:String? 13 | var property:PropertyState 14 | } 15 | 16 | struct PropertyState { 17 | var searchCriteria:SearchCriteria? 18 | var properties:[PropertyDetail]? 19 | var selectedProperty:Int = -1 20 | } 21 | 22 | struct SearchCriteria { 23 | let placeName:String? 24 | let centerPoint:String? 25 | } 26 | 27 | struct PropertyDetail { 28 | var title:String 29 | var price:Double 30 | var imgUrl:String 31 | var bedroomNumber:Int = -1 32 | var propertyType:String 33 | var bathroomNumber:Int = -1 34 | var description:String 35 | } 36 | 37 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/AppCoordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppCoordinator.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 03/01/2017. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | class AppCoordinator { 12 | var rootVC: UINavigationController 13 | 14 | init(_ rootVC: UINavigationController){ 15 | self.rootVC = rootVC 16 | } 17 | 18 | func start() { 19 | let searchVC = SearchSceneViewController(); 20 | let searchSceneCoordinator = SearchSceneCoordinator(self.rootVC) 21 | searchVC.searchSceneCoordinator = searchSceneCoordinator 22 | self.rootVC.pushViewController(searchVC, animated: true) 23 | } 24 | 25 | func showAlert(errorMessage:String) { 26 | let alert = UIAlertController(title: "Oops!", message:errorMessage, preferredStyle: .alert) 27 | alert.addAction(UIAlertAction(title: "OK", style: .default)) 28 | self.rootVC.topViewController?.present(alert, animated: true) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/PropertyDetailSceneViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PropertyDetailSceneViewController.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 09/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | class PropertyDetailSceneViewController: BaseViewController { 10 | var propertyDetailView:PropertyDetailView? 11 | 12 | 13 | //MARK: update state 14 | override func newState(state: AppState) { 15 | if let property = state.property.properties?[state.property.selectedProperty] { 16 | print("start updating...") 17 | self.propertyDetailView?.update(property: property) 18 | } 19 | 20 | super.newState(state: state) 21 | } 22 | 23 | //MARK: lifecycle 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | propertyDetailView = PropertyDetailView(frame: self.view.bounds) 27 | self.view.addSubview(propertyDetailView!) 28 | } 29 | 30 | override func didReceiveMemoryWarning() { 31 | super.didReceiveMemoryWarning() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/SearchView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchView.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 06/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SearchView:XibBaseView { 12 | 13 | @IBOutlet var placeNameField:UITextField! 14 | 15 | var goButtonOnClick:((_ searchCriteria:SearchCriteria) -> Void)? 16 | var locationButtonOnClick: (() -> Void)? 17 | 18 | @IBAction func goButtonTapped() { 19 | if self.placeNameField.text == "" { 20 | self.placeNameField.text = self.placeNameField.placeholder 21 | } 22 | 23 | let searchCriteria = SearchCriteria( 24 | placeName: self.placeNameField.text, 25 | centerPoint:nil 26 | ) 27 | 28 | if let goButtonCallback = self.goButtonOnClick{ 29 | goButtonCallback(searchCriteria) 30 | } 31 | } 32 | 33 | @IBAction func locationButtonTapped() { 34 | 35 | if let locationButtonCallback = self.locationButtonOnClick { 36 | locationButtonCallback() 37 | } 38 | } 39 | 40 | func update(searchCriteria:SearchCriteria) { 41 | self.placeNameField.text = searchCriteria.placeName 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/SearchResultViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultViewController.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 08/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SearchResultSceneViewController: BaseViewController { 12 | 13 | var searchResultCoordinator: SearchResultsSceneCoordinatorProtocol? 14 | var searchResultView:SearchResultView? 15 | 16 | //MARK: update state 17 | override func newState(state: AppState) { 18 | if let properties = state.property.properties{ 19 | self.searchResultView?.update(properties: properties) 20 | } 21 | super.newState(state: state) 22 | } 23 | 24 | //MARK: user action 25 | func showPropertyDetail(index:Int) { 26 | self.searchResultCoordinator?.showPropertyDetail(index: index) 27 | } 28 | 29 | //MARK: lifecycle 30 | override func viewDidLoad() { 31 | super.viewDidLoad() 32 | searchResultView = SearchResultView(frame: self.view.bounds) 33 | searchResultView?.selectPropertyAt = self.showPropertyDetail 34 | self.view.addSubview(searchResultView!) 35 | } 36 | 37 | override func didReceiveMemoryWarning() { 38 | super.didReceiveMemoryWarning() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/PropertyDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PropertyDetailView.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 09/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import UIKit 9 | 10 | class PropertyDetailView:XibBaseView{ 11 | 12 | @IBOutlet var imageView:UIImageView? 13 | @IBOutlet var nameLabel:UILabel? 14 | @IBOutlet var priceLabel:UILabel? 15 | @IBOutlet var highlightLabel:UILabel? 16 | @IBOutlet var descriptionLabel:UILabel? 17 | 18 | func update(property:PropertyDetail) { 19 | if let url = URL(string: property.imgUrl), let data = NSData(contentsOf: url) 20 | { 21 | self.imageView?.image = UIImage(data: data as Data) 22 | } 23 | self.nameLabel?.text = property.title 24 | self.priceLabel?.text = StringUtil.formatForPound(property.price) 25 | self.highlightLabel?.text = self.combine(property: property) 26 | self.highlightLabel?.sizeToFit() 27 | self.descriptionLabel?.text = property.description 28 | self.descriptionLabel?.sizeToFit() 29 | } 30 | 31 | private func combine(property:PropertyDetail) -> String { 32 | var result = "\(property.bedroomNumber) bed \(property.propertyType)" 33 | 34 | if(property.bathroomNumber != -1) { 35 | result += "," + String(property.bathroomNumber) + " " 36 | result += property.bathroomNumber > 1 ? "bathrooms" : "bathroom" 37 | } 38 | return result 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/SearchSceneCoordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchSceneCoordinator.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 09/03/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol SearchSceneCoordinatorProtocol { 12 | func searchByCity(searchCriteria:SearchCriteria) 13 | func searchByCurrentLocation() 14 | } 15 | 16 | class SearchSceneCoordinator: AppCoordinator, SearchSceneCoordinatorProtocol { 17 | let propertyActionCreater = PropertyActionCreater() 18 | 19 | func searchByCity(searchCriteria:SearchCriteria) { 20 | mainStore.dispatch(SaveErrorMessage(errorMessage: "")) 21 | mainStore.dispatch( 22 | propertyActionCreater.searchProperties(searchCriteria: searchCriteria){ 23 | self.pushSearchResultViewController() 24 | } 25 | ) 26 | } 27 | 28 | func searchByCurrentLocation() { 29 | mainStore.dispatch(SaveErrorMessage(errorMessage: "")) 30 | mainStore.dispatch(propertyActionCreater.searchPropertiesByCurrentLocation(){ 31 | self.pushSearchResultViewController() 32 | }) 33 | } 34 | 35 | private func pushSearchResultViewController() { 36 | let searchResultVC = SearchResultSceneViewController(); 37 | let searchResultCoordinator = SearchResultsSceneCoordinator(self.rootVC) 38 | searchResultVC.searchResultCoordinator = searchResultCoordinator 39 | self.rootVC.pushViewController(searchResultVC, animated: true) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/SearchResultView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultView.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 08/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import UIKit 9 | 10 | class SearchResultView:XibBaseView{ 11 | 12 | @IBOutlet var resultTableView:UITableView? 13 | var properties:[PropertyDetail]? 14 | var selectPropertyAt:((_ index:Int) -> Void)? 15 | 16 | func update(properties:[PropertyDetail]) { 17 | self.properties = properties 18 | } 19 | } 20 | 21 | extension SearchResultView: UITableViewDelegate, UITableViewDataSource { 22 | 23 | func numberOfSections(in tableView: UITableView) -> Int { 24 | return 1 25 | } 26 | 27 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 28 | return self.properties?.count ?? 0 29 | } 30 | 31 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 32 | var cell = tableView.dequeueReusableCell(withIdentifier: "property") 33 | 34 | if cell == nil { 35 | cell = UITableViewCell(style: .subtitle, reuseIdentifier: "property") 36 | } 37 | 38 | if let property = self.properties?[indexPath.row] { 39 | cell?.textLabel?.text = property.title 40 | cell?.detailTextLabel?.text = StringUtil.formatForPound(property.price) 41 | } 42 | 43 | return cell! 44 | } 45 | 46 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 47 | self.selectPropertyAt?(indexPath.row) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSLocationWhenInUseUsageDescription 6 | track current location for better service 7 | NSLocationAlwaysUsageDescription 8 | track current location for better service 9 | NSAppTransportSecurity 10 | 11 | NSAllowsArbitraryLoads 12 | 13 | 14 | CFBundleDevelopmentRegion 15 | en 16 | CFBundleDisplayName 17 | ReApp 18 | CFBundleExecutable 19 | $(EXECUTABLE_NAME) 20 | CFBundleIdentifier 21 | $(PRODUCT_BUNDLE_IDENTIFIER) 22 | CFBundleInfoDictionaryVersion 23 | 6.0 24 | CFBundleName 25 | $(PRODUCT_NAME) 26 | CFBundlePackageType 27 | APPL 28 | CFBundleShortVersionString 29 | 1.0 30 | CFBundleVersion 31 | 1 32 | LSRequiresIPhoneOS 33 | 34 | UILaunchStoryboardName 35 | LaunchScreen 36 | UIRequiredDeviceCapabilities 37 | 38 | armv7 39 | 40 | UISupportedInterfaceOrientations 41 | 42 | UIInterfaceOrientationPortrait 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/SearchSceneViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 03/01/2017. 6 | // 7 | 8 | import UIKit 9 | import ReSwift 10 | 11 | class SearchSceneViewController: BaseViewController { 12 | 13 | var searchSceneCoordinator:SearchSceneCoordinatorProtocol? 14 | var searchView:SearchView? 15 | 16 | //MARK: update state 17 | override func newState(state: AppState) { 18 | self.update(state: state) 19 | super.newState(state: state) 20 | } 21 | 22 | private func update(state: AppState) { 23 | if let searchCriteria = state.property.searchCriteria { 24 | searchView?.update(searchCriteria: searchCriteria) 25 | } 26 | if let errorMessage = state.errorMessage, !errorMessage.isEmpty { 27 | self.showAlert(errorMessage: errorMessage) 28 | } 29 | } 30 | 31 | //MARK: user action 32 | func searchByCity(searchCriteria:SearchCriteria) { 33 | searchSceneCoordinator?.searchByCity(searchCriteria: searchCriteria) 34 | } 35 | 36 | func searchByCurrentLocation() { 37 | searchSceneCoordinator?.searchByCurrentLocation() 38 | } 39 | 40 | //MARK: lifecycle 41 | override func viewDidLoad() { 42 | super.viewDidLoad() 43 | searchView = SearchView(frame: self.view.bounds) 44 | searchView?.goButtonOnClick = self.searchByCity 45 | searchView?.locationButtonOnClick = self.searchByCurrentLocation 46 | self.view.addSubview(searchView!) 47 | } 48 | 49 | override func didReceiveMemoryWarning() { 50 | super.didReceiveMemoryWarning() 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/PropertyApi.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PropertyApi.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import Alamofire 9 | 10 | struct PropertyApi { 11 | func findProperties(searchCriteria:SearchCriteria, success: @escaping (_ response: Any) -> Void, failure: @escaping (_ error: Error?) -> Void ) { 12 | 13 | let parameters = parametersForQuery(searchCriteria: searchCriteria) 14 | 15 | Alamofire.request("http://api.nestoria.co.uk/api", parameters:parameters).responseJSON( 16 | completionHandler: { response in 17 | switch response.result { 18 | case .success(let JSON): 19 | print("Validation Successful") 20 | print(response.data ?? "Data is empty") 21 | success(JSON) 22 | case .failure(let error): 23 | print(error) 24 | failure(error) 25 | } 26 | }) 27 | } 28 | 29 | private func parametersForQuery(searchCriteria:SearchCriteria) -> [String : Any]{ 30 | var queryParameters = [ 31 | "country": "uk", 32 | "pretty": "1", 33 | "encoding": "json", 34 | "listing_type": "buy", 35 | "action": "search_listings", 36 | "page": 1 37 | ] as [String : Any] 38 | if (searchCriteria.placeName != nil) { 39 | queryParameters["place_name"] = searchCriteria.placeName 40 | } 41 | if(searchCriteria.centerPoint != nil) { 42 | queryParameters["centre_point"] = searchCriteria.centerPoint 43 | } 44 | 45 | return queryParameters 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/LocationTracker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationTracker.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 06/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | class LocationTracker :NSObject, CLLocationManagerDelegate { 12 | var locationManager:CLLocationManager? 13 | var onSuccess: ((String) -> Void)? 14 | var onFailure: ((String) -> Void)? 15 | 16 | func getCurrentLocation(success: ((String) -> Void)?, fail: ((String) -> Void)?){ 17 | self.locationManager = CLLocationManager() 18 | self.onSuccess = success 19 | self.onFailure = fail 20 | 21 | // Ask for Authorisation from the User. 22 | self.locationManager?.requestAlwaysAuthorization() 23 | 24 | // For use in foreground 25 | self.locationManager?.requestWhenInUseAuthorization() 26 | 27 | if CLLocationManager.locationServicesEnabled() { 28 | locationManager?.delegate = self 29 | locationManager?.desiredAccuracy = kCLLocationAccuracyNearestTenMeters 30 | locationManager?.startUpdatingLocation() 31 | } 32 | } 33 | 34 | func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 35 | let locValue:CLLocationCoordinate2D = manager.location!.coordinate 36 | self.onSuccess?("\(locValue.latitude),\(locValue.longitude)") 37 | self.locationManager?.stopUpdatingLocation() 38 | self.locationManager = nil 39 | } 40 | 41 | func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { 42 | self.onFailure?(error.localizedDescription) 43 | self.locationManager?.stopUpdatingLocation() 44 | self.locationManager = nil 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/BaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 06/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ReSwift 11 | 12 | class BaseViewController: UIViewController, StoreSubscriber { 13 | typealias StoreSubscriberStateType = AppState 14 | let activityInd = UIActivityIndicatorView(activityIndicatorStyle:.gray) 15 | var appCoordinator:AppCoordinator? 16 | 17 | //MARK: update state 18 | func newState(state: AppState) { 19 | if state.isLoading { 20 | self.view.addSubview(self.activityInd) 21 | self.activityInd.startAnimating() 22 | } else { 23 | self.activityInd.stopAnimating() 24 | } 25 | } 26 | 27 | func showAlert(errorMessage:String) { 28 | let alert = UIAlertController(title: "Oops!", message:errorMessage, preferredStyle: .alert) 29 | alert.addAction(UIAlertAction(title: "OK", style: .default)) 30 | self.navigationController?.topViewController?.present(alert, animated: true) 31 | } 32 | 33 | //MARK: lifecycle 34 | override func viewWillAppear(_ animated: Bool) { 35 | super.viewWillAppear(animated) 36 | mainStore.subscribe(self) { state in state } 37 | } 38 | 39 | override func viewWillDisappear(_ animated: Bool) { 40 | super.viewWillDisappear(animated) 41 | mainStore.unsubscribe(self) 42 | } 43 | 44 | override func viewDidLoad() { 45 | super.viewDidLoad() 46 | configActivityIndicator() 47 | } 48 | 49 | func configActivityIndicator() { 50 | self.activityInd.frame = CGRect(x:0.0, y:0.0, width:40.0, height:40.0); 51 | self.activityInd.hidesWhenStopped = true 52 | self.activityInd.center = self.view.center 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/XibBaseView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchView.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import UIKit 9 | 10 | class XibBaseView:UIView { 11 | 12 | var nibView: UIView? 13 | 14 | override init(frame: CGRect) { 15 | super.init(frame: frame) 16 | 17 | initialize() 18 | } 19 | 20 | required init?(coder aDecoder: NSCoder) { 21 | super.init(coder: aDecoder) 22 | 23 | initialize() 24 | } 25 | 26 | func initialize() { 27 | if let nibName = self.nibName { 28 | nibView = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)?[0] as? UIView 29 | 30 | if let actualNibView = nibView { 31 | actualNibView.frame = self.bounds 32 | super.addSubview(actualNibView) 33 | actualNibView.translatesAutoresizingMaskIntoConstraints = false 34 | self.addConstraint(format: "H:|[view]|", views: ["view": actualNibView]) 35 | self.addConstraint(format: "V:|[view]|", views: ["view": actualNibView]) 36 | } 37 | } 38 | } 39 | func addConstraint(format: String, views: [String : UIView]) { 40 | let constraints = NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: views) 41 | self.addConstraints(constraints) 42 | } 43 | 44 | override func addSubview(_ view: UIView) { 45 | if let actualNibView = nibView { 46 | actualNibView.addSubview(view) 47 | } else { 48 | super.addSubview(view) 49 | } 50 | } 51 | 52 | var nibName: String? { 53 | let typeLongName = type(of: self).description() 54 | let tokens = typeLongName.characters.split {$0 == "."}.map(String.init) 55 | return tokens.last! 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/SearchResultView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 03/01/2017. 6 | // 7 | 8 | import UIKit 9 | import ReSwift 10 | 11 | let mainStore = Store( 12 | reducer: AppReducer, 13 | state: nil 14 | ) 15 | 16 | @UIApplicationMain 17 | class AppDelegate: UIResponder, UIApplicationDelegate { 18 | 19 | var window: UIWindow? 20 | var appCoordinator: AppCoordinator! 21 | 22 | 23 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 24 | window = UIWindow() 25 | let rootVC = UINavigationController() 26 | window?.rootViewController = rootVC 27 | appCoordinator = AppCoordinator(rootVC) 28 | appCoordinator.start() 29 | window?.makeKeyAndVisible() 30 | return true 31 | } 32 | 33 | func applicationWillResignActive(_ application: UIApplication) { 34 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 35 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 36 | } 37 | 38 | func applicationDidEnterBackground(_ application: UIApplication) { 39 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 40 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 41 | } 42 | 43 | func applicationWillEnterForeground(_ application: UIApplication) { 44 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 45 | } 46 | 47 | func applicationDidBecomeActive(_ application: UIApplication) { 48 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 49 | } 50 | 51 | func applicationWillTerminate(_ application: UIApplication) { 52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 53 | } 54 | 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/PropertyActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PropertyActions.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | 9 | import ReSwift 10 | 11 | struct UpdateSearchCriteria: Action { 12 | let searchCriteria:SearchCriteria 13 | } 14 | 15 | struct UpdateProperties: Action { 16 | let response:Any 17 | } 18 | 19 | struct UpdateSelectedProperty: Action { 20 | let selectedPropertyIndex:Int 21 | } 22 | 23 | struct PropertyActionCreater { 24 | typealias ActionCreator = (_ state: AppState, _ store: Store) -> Action? 25 | typealias AsyncActionCreator = (_ state: AppState, _ store: Store, _ callback: @escaping (_ actionCreator: ActionCreator) -> Void ) -> Void 26 | let propertyApi = PropertyApi() 27 | let locationTracker = LocationTracker() 28 | 29 | func searchProperties(searchCriteria: SearchCriteria, _ callback:(() -> Void)?) -> ActionCreator { 30 | return { state, store in 31 | store.dispatch(UpdateSearchCriteria(searchCriteria: searchCriteria)) 32 | 33 | self.propertyApi.findProperties( 34 | searchCriteria: searchCriteria, 35 | success: { (response) in 36 | store.dispatch(UpdateProperties(response: response)) 37 | store.dispatch(EndLoading()) 38 | callback?() 39 | }, 40 | failure: { (error) in 41 | store.dispatch(EndLoading()) 42 | store.dispatch(SaveErrorMessage(errorMessage: (error?.localizedDescription)!)) 43 | } 44 | ) 45 | return StartLoading() 46 | } 47 | } 48 | 49 | 50 | func searchPropertiesByCurrentLocation(_ nextStep:(() -> Void)?) -> AsyncActionCreator { 51 | 52 | return { maybeState, store, callback in 53 | store.dispatch(StartLoading()) 54 | self.locationTracker.getCurrentLocation( 55 | success: { currentLocation in 56 | let searchCriteria = SearchCriteria( 57 | placeName:nil, 58 | centerPoint: currentLocation 59 | ) 60 | callback(self.searchProperties(searchCriteria: searchCriteria, nextStep)) 61 | }, 62 | fail: { errorMessage in 63 | store.dispatch(SaveErrorMessage(errorMessage: errorMessage)) 64 | store.dispatch(EndLoading()) 65 | } 66 | ) 67 | } 68 | } 69 | 70 | } 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/AppReducer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppReducer.swift 3 | // ReswiftAppCoordinatorDemo 4 | // 5 | // Created by Xianning Liu on 04/01/2017. 6 | // Copyright © 2017 xianlinbox. All rights reserved. 7 | // 8 | import ReSwift 9 | 10 | func AppReducer(action: Action, state: AppState?) -> AppState { 11 | return AppState( 12 | isLoading:loadingReducer(state?.isLoading, action: action), 13 | errorMessage:errorMessageReducer(state?.errorMessage, action: action), 14 | property:propertyReducer(state?.property, action: action) 15 | ) 16 | } 17 | 18 | func loadingReducer(_ state: Bool?, action: Action) -> Bool { 19 | var state = state ?? false 20 | 21 | switch action { 22 | case _ as StartLoading: 23 | state = true 24 | case _ as EndLoading: 25 | state = false 26 | default: 27 | break 28 | } 29 | 30 | return state 31 | } 32 | 33 | func errorMessageReducer(_ state: String?, action: Action) -> String { 34 | var state = state ?? "" 35 | 36 | switch action { 37 | case let action as SaveErrorMessage: 38 | state = action.errorMessage 39 | case _ as CleanErrorMessage: 40 | state = "" 41 | default: 42 | break 43 | } 44 | 45 | return state 46 | } 47 | 48 | func propertyReducer(_ state: PropertyState?, action: Action) -> PropertyState { 49 | var state = state ?? PropertyState() 50 | 51 | switch action { 52 | case let action as UpdateSearchCriteria: 53 | state.searchCriteria = action.searchCriteria 54 | case let action as UpdateProperties: 55 | let responseData = action.response as! NSDictionary 56 | let response = responseData.object(forKey: "response") as! NSDictionary 57 | let propertyList = response.object(forKey: "listings") as! NSArray 58 | 59 | state.properties = propertyList.map({ (property) -> PropertyDetail in 60 | let props = property as! NSDictionary 61 | 62 | return PropertyDetail( 63 | title:props.object(forKey: "title") as! String, 64 | price:props.object(forKey: "price") as! Double, 65 | imgUrl:props.object(forKey: "img_url") as! String, 66 | bedroomNumber: Int((props.object(forKey: "bedroom_number") as? Int64) ?? -1), 67 | propertyType: props.object(forKey: "property_type") as! String, 68 | bathroomNumber: Int((props.object(forKey: "bathroom_number") as? Int64) ?? -1), 69 | description:props.object(forKey: "summary") as! String 70 | ) 71 | }) 72 | case let action as UpdateSelectedProperty: 73 | state.selectedProperty = action.selectedPropertyIndex 74 | default: 75 | break 76 | } 77 | 78 | return state 79 | } 80 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo.xcodeproj/xcuserdata/xnliu.xcuserdatad/xcschemes/ReswiftAppCoordinatorDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/SearchView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 53 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo/PropertyDetailView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 62 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /ReswiftAppCoordinatorDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DF0E3FB01E2369BA00D00586 /* PropertyDetailSceneViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF0E3FAF1E2369BA00D00586 /* PropertyDetailSceneViewController.swift */; }; 11 | DF0E3FB21E236C0400D00586 /* PropertyDetailView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF0E3FB11E236C0400D00586 /* PropertyDetailView.xib */; }; 12 | DF0E3FB41E236C1900D00586 /* PropertyDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF0E3FB31E236C1900D00586 /* PropertyDetailView.swift */; }; 13 | DF0E3FB71E2378AF00D00586 /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF0E3FB61E2378AF00D00586 /* StringUtil.swift */; }; 14 | DF0E3FBA1E237C9F00D00586 /* StringUtilSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF0E3FB91E237C9F00D00586 /* StringUtilSpec.swift */; }; 15 | DF0E3FBB1E237E5900D00586 /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF0E3FB61E2378AF00D00586 /* StringUtil.swift */; }; 16 | DF23DFCF1E220EDB0032641D /* Alamofire.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = DF23DFCE1E220EDB0032641D /* Alamofire.framework */; }; 17 | DF23DFD61E220F250032641D /* Nimble.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = DF23DFD41E220F250032641D /* Nimble.framework */; }; 18 | DF23DFD71E220F250032641D /* Quick.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = DF23DFD51E220F250032641D /* Quick.framework */; }; 19 | DF23DFD91E2211A70032641D /* SearchResultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF23DFD81E2211A70032641D /* SearchResultViewController.swift */; }; 20 | DF23DFDB1E2218990032641D /* SearchResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF23DFDA1E2218990032641D /* SearchResultView.swift */; }; 21 | DF23DFDD1E2219B10032641D /* SearchResultView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF23DFDC1E2219B10032641D /* SearchResultView.xib */; }; 22 | DF30726D1E1BA625005AA130 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF30726C1E1BA625005AA130 /* AppDelegate.swift */; }; 23 | DF30726F1E1BA625005AA130 /* SearchSceneViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF30726E1E1BA625005AA130 /* SearchSceneViewController.swift */; }; 24 | DF3072741E1BA625005AA130 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DF3072731E1BA625005AA130 /* Assets.xcassets */; }; 25 | DF3072771E1BA625005AA130 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DF3072751E1BA625005AA130 /* LaunchScreen.storyboard */; }; 26 | DF3072901E1BE7D5005AA130 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF30728F1E1BE7D5005AA130 /* AppCoordinator.swift */; }; 27 | DF31C0531E1F27360053DB38 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF31C0521E1F27360053DB38 /* BaseViewController.swift */; }; 28 | DF74B9B21E1C8EAB0028246C /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF30728D1E1BB2EA005AA130 /* ReSwift.framework */; }; 29 | DF74B9B41E1C8F130028246C /* ReSwift.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = DF30728D1E1BB2EA005AA130 /* ReSwift.framework */; }; 30 | DF74B9B71E1C906A0028246C /* SearchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF74B9B61E1C906A0028246C /* SearchView.xib */; }; 31 | DF74B9B81E1C906A0028246C /* SearchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF74B9B61E1C906A0028246C /* SearchView.xib */; }; 32 | DF74B9BD1E1C91F00028246C /* XibBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9BC1E1C91F00028246C /* XibBaseView.swift */; }; 33 | DF74B9BE1E1C91F00028246C /* XibBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9BC1E1C91F00028246C /* XibBaseView.swift */; }; 34 | DF74B9C11E1C92230028246C /* colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9C01E1C92230028246C /* colors.swift */; }; 35 | DF74B9C21E1C92230028246C /* colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9C01E1C92230028246C /* colors.swift */; }; 36 | DF74B9C41E1C92310028246C /* fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9C31E1C92310028246C /* fonts.swift */; }; 37 | DF74B9C51E1C92310028246C /* fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9C31E1C92310028246C /* fonts.swift */; }; 38 | DF74B9C91E1CAF660028246C /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9C81E1CAF660028246C /* AppState.swift */; }; 39 | DF74B9CA1E1CAF660028246C /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9C81E1CAF660028246C /* AppState.swift */; }; 40 | DF74B9D21E1CCB590028246C /* PropertyActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9D11E1CCB590028246C /* PropertyActions.swift */; }; 41 | DF74B9D31E1CCB590028246C /* PropertyActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9D11E1CCB590028246C /* PropertyActions.swift */; }; 42 | DF74B9D81E1CDF680028246C /* AppReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9D71E1CDF680028246C /* AppReducer.swift */; }; 43 | DF74B9D91E1CDF680028246C /* AppReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9D71E1CDF680028246C /* AppReducer.swift */; }; 44 | DF74B9DB1E1CE2F70028246C /* LoadingActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9DA1E1CE2F70028246C /* LoadingActions.swift */; }; 45 | DF74B9DC1E1CE2F70028246C /* LoadingActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9DA1E1CE2F70028246C /* LoadingActions.swift */; }; 46 | DF74B9DE1E1CE3630028246C /* ErrorMessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9DD1E1CE3630028246C /* ErrorMessageActions.swift */; }; 47 | DF74B9DF1E1CE3630028246C /* ErrorMessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9DD1E1CE3630028246C /* ErrorMessageActions.swift */; }; 48 | DF74B9E21E1CF3EB0028246C /* PropertyApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9E11E1CF3EB0028246C /* PropertyApi.swift */; }; 49 | DF74B9E31E1CF3EB0028246C /* PropertyApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74B9E11E1CF3EB0028246C /* PropertyApi.swift */; }; 50 | DF74B9E51E1CF7420028246C /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF74B9E41E1CF7420028246C /* Alamofire.framework */; }; 51 | DFC1E6A11E714CFF00AB419F /* SearchSceneCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC1E6A01E714CFF00AB419F /* SearchSceneCoordinator.swift */; }; 52 | DFC1E6A31E714EA200AB419F /* SearchResultsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC1E6A21E714EA200AB419F /* SearchResultsCoordinator.swift */; }; 53 | DFC26C221E1F404700148AB5 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC26C211E1F404700148AB5 /* SearchView.swift */; }; 54 | DFC26C271E1F6F8A00148AB5 /* LocationTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC26C261E1F6F8A00148AB5 /* LocationTracker.swift */; }; 55 | DFF15E401E212BDC0072DACF /* LocationTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC26C261E1F6F8A00148AB5 /* LocationTracker.swift */; }; 56 | /* End PBXBuildFile section */ 57 | 58 | /* Begin PBXContainerItemProxy section */ 59 | DF30727E1E1BA625005AA130 /* PBXContainerItemProxy */ = { 60 | isa = PBXContainerItemProxy; 61 | containerPortal = DF3072611E1BA625005AA130 /* Project object */; 62 | proxyType = 1; 63 | remoteGlobalIDString = DF3072681E1BA625005AA130; 64 | remoteInfo = ReswiftAppCoordinatorDemo; 65 | }; 66 | /* End PBXContainerItemProxy section */ 67 | 68 | /* Begin PBXCopyFilesBuildPhase section */ 69 | DF74B9B31E1C8EF30028246C /* CopyFiles */ = { 70 | isa = PBXCopyFilesBuildPhase; 71 | buildActionMask = 12; 72 | dstPath = ""; 73 | dstSubfolderSpec = 16; 74 | files = ( 75 | DF23DFD61E220F250032641D /* Nimble.framework in CopyFiles */, 76 | DF23DFD71E220F250032641D /* Quick.framework in CopyFiles */, 77 | DF23DFCF1E220EDB0032641D /* Alamofire.framework in CopyFiles */, 78 | DF74B9B41E1C8F130028246C /* ReSwift.framework in CopyFiles */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXCopyFilesBuildPhase section */ 83 | 84 | /* Begin PBXFileReference section */ 85 | DF0E3FAF1E2369BA00D00586 /* PropertyDetailSceneViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertyDetailSceneViewController.swift; sourceTree = ""; }; 86 | DF0E3FB11E236C0400D00586 /* PropertyDetailView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PropertyDetailView.xib; sourceTree = ""; }; 87 | DF0E3FB31E236C1900D00586 /* PropertyDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertyDetailView.swift; sourceTree = ""; }; 88 | DF0E3FB61E2378AF00D00586 /* StringUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringUtil.swift; sourceTree = ""; }; 89 | DF0E3FB91E237C9F00D00586 /* StringUtilSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringUtilSpec.swift; sourceTree = ""; }; 90 | DF23DFCE1E220EDB0032641D /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = ""; }; 91 | DF23DFD41E220F250032641D /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/iOS/Nimble.framework; sourceTree = ""; }; 92 | DF23DFD51E220F250032641D /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/iOS/Quick.framework; sourceTree = ""; }; 93 | DF23DFD81E2211A70032641D /* SearchResultViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchResultViewController.swift; sourceTree = ""; }; 94 | DF23DFDA1E2218990032641D /* SearchResultView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchResultView.swift; sourceTree = ""; }; 95 | DF23DFDC1E2219B10032641D /* SearchResultView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SearchResultView.xib; sourceTree = ""; }; 96 | DF3072691E1BA625005AA130 /* ReswiftAppCoordinatorDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReswiftAppCoordinatorDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | DF30726C1E1BA625005AA130 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 98 | DF30726E1E1BA625005AA130 /* SearchSceneViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSceneViewController.swift; sourceTree = ""; }; 99 | DF3072731E1BA625005AA130 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 100 | DF3072761E1BA625005AA130 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 101 | DF3072781E1BA625005AA130 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 102 | DF30727D1E1BA625005AA130 /* ReswiftAppCoordinatorDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReswiftAppCoordinatorDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 103 | DF3072831E1BA625005AA130 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 104 | DF30728D1E1BB2EA005AA130 /* ReSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReSwift.framework; path = Carthage/Build/iOS/ReSwift.framework; sourceTree = ""; }; 105 | DF30728F1E1BE7D5005AA130 /* AppCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = ""; }; 106 | DF31C0521E1F27360053DB38 /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; 107 | DF74B9B61E1C906A0028246C /* SearchView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SearchView.xib; sourceTree = ""; }; 108 | DF74B9BC1E1C91F00028246C /* XibBaseView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XibBaseView.swift; sourceTree = ""; }; 109 | DF74B9C01E1C92230028246C /* colors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = colors.swift; sourceTree = ""; }; 110 | DF74B9C31E1C92310028246C /* fonts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = fonts.swift; sourceTree = ""; }; 111 | DF74B9C81E1CAF660028246C /* AppState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; 112 | DF74B9D11E1CCB590028246C /* PropertyActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertyActions.swift; sourceTree = ""; }; 113 | DF74B9D71E1CDF680028246C /* AppReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppReducer.swift; sourceTree = ""; }; 114 | DF74B9DA1E1CE2F70028246C /* LoadingActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingActions.swift; sourceTree = ""; }; 115 | DF74B9DD1E1CE3630028246C /* ErrorMessageActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorMessageActions.swift; sourceTree = ""; }; 116 | DF74B9E11E1CF3EB0028246C /* PropertyApi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertyApi.swift; sourceTree = ""; }; 117 | DF74B9E41E1CF7420028246C /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = ""; }; 118 | DFC1E6A01E714CFF00AB419F /* SearchSceneCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchSceneCoordinator.swift; sourceTree = ""; }; 119 | DFC1E6A21E714EA200AB419F /* SearchResultsCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchResultsCoordinator.swift; sourceTree = ""; }; 120 | DFC26C211E1F404700148AB5 /* SearchView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; 121 | DFC26C261E1F6F8A00148AB5 /* LocationTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationTracker.swift; sourceTree = ""; }; 122 | /* End PBXFileReference section */ 123 | 124 | /* Begin PBXFrameworksBuildPhase section */ 125 | DF3072661E1BA625005AA130 /* Frameworks */ = { 126 | isa = PBXFrameworksBuildPhase; 127 | buildActionMask = 2147483647; 128 | files = ( 129 | DF74B9E51E1CF7420028246C /* Alamofire.framework in Frameworks */, 130 | DF74B9B21E1C8EAB0028246C /* ReSwift.framework in Frameworks */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | DF30727A1E1BA625005AA130 /* Frameworks */ = { 135 | isa = PBXFrameworksBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | ); 139 | runOnlyForDeploymentPostprocessing = 0; 140 | }; 141 | /* End PBXFrameworksBuildPhase section */ 142 | 143 | /* Begin PBXGroup section */ 144 | DF0E3FB51E23789F00D00586 /* Utilities */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | DF0E3FB61E2378AF00D00586 /* StringUtil.swift */, 148 | ); 149 | name = Utilities; 150 | sourceTree = ""; 151 | }; 152 | DF0E3FB81E237C8400D00586 /* Utilities */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | DF0E3FB91E237C9F00D00586 /* StringUtilSpec.swift */, 156 | ); 157 | name = Utilities; 158 | sourceTree = ""; 159 | }; 160 | DF3072601E1BA625005AA130 = { 161 | isa = PBXGroup; 162 | children = ( 163 | DF23DFD41E220F250032641D /* Nimble.framework */, 164 | DF23DFD51E220F250032641D /* Quick.framework */, 165 | DF23DFCE1E220EDB0032641D /* Alamofire.framework */, 166 | DF30726B1E1BA625005AA130 /* ReswiftAppCoordinatorDemo */, 167 | DF3072801E1BA625005AA130 /* ReswiftAppCoordinatorDemoTests */, 168 | DF30726A1E1BA625005AA130 /* Products */, 169 | DF30728C1E1BB2EA005AA130 /* Frameworks */, 170 | ); 171 | sourceTree = ""; 172 | }; 173 | DF30726A1E1BA625005AA130 /* Products */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | DF3072691E1BA625005AA130 /* ReswiftAppCoordinatorDemo.app */, 177 | DF30727D1E1BA625005AA130 /* ReswiftAppCoordinatorDemoTests.xctest */, 178 | ); 179 | name = Products; 180 | sourceTree = ""; 181 | }; 182 | DF30726B1E1BA625005AA130 /* ReswiftAppCoordinatorDemo */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | DFC1E69F1E714CE000AB419F /* Coordinators */, 186 | DF0E3FB51E23789F00D00586 /* Utilities */, 187 | DFC26C251E1F6F3500148AB5 /* Sensor */, 188 | DF74B9BF1E1C92120028246C /* Themes */, 189 | DF74B9C71E1CADE10028246C /* Reducers */, 190 | DF74B9C61E1CADBE0028246C /* Actions */, 191 | DF74B9E01E1CF3BF0028246C /* API */, 192 | DF74B9B51E1C90210028246C /* Views */, 193 | DF30726C1E1BA625005AA130 /* AppDelegate.swift */, 194 | DF30728F1E1BE7D5005AA130 /* AppCoordinator.swift */, 195 | DF74B9C81E1CAF660028246C /* AppState.swift */, 196 | DF3072731E1BA625005AA130 /* Assets.xcassets */, 197 | DF3072751E1BA625005AA130 /* LaunchScreen.storyboard */, 198 | DF3072781E1BA625005AA130 /* Info.plist */, 199 | ); 200 | path = ReswiftAppCoordinatorDemo; 201 | sourceTree = ""; 202 | }; 203 | DF3072801E1BA625005AA130 /* ReswiftAppCoordinatorDemoTests */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | DF0E3FB81E237C8400D00586 /* Utilities */, 207 | DF3072831E1BA625005AA130 /* Info.plist */, 208 | ); 209 | path = ReswiftAppCoordinatorDemoTests; 210 | sourceTree = ""; 211 | }; 212 | DF30728C1E1BB2EA005AA130 /* Frameworks */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | DF74B9E41E1CF7420028246C /* Alamofire.framework */, 216 | DF30728D1E1BB2EA005AA130 /* ReSwift.framework */, 217 | ); 218 | name = Frameworks; 219 | sourceTree = ""; 220 | }; 221 | DF74B9B51E1C90210028246C /* Views */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | DFC26C241E1F406400148AB5 /* BaseViews */, 225 | DF30726E1E1BA625005AA130 /* SearchSceneViewController.swift */, 226 | DFC26C211E1F404700148AB5 /* SearchView.swift */, 227 | DF74B9B61E1C906A0028246C /* SearchView.xib */, 228 | DF23DFD81E2211A70032641D /* SearchResultViewController.swift */, 229 | DF23DFDA1E2218990032641D /* SearchResultView.swift */, 230 | DF23DFDC1E2219B10032641D /* SearchResultView.xib */, 231 | DF0E3FAF1E2369BA00D00586 /* PropertyDetailSceneViewController.swift */, 232 | DF0E3FB31E236C1900D00586 /* PropertyDetailView.swift */, 233 | DF0E3FB11E236C0400D00586 /* PropertyDetailView.xib */, 234 | ); 235 | name = Views; 236 | sourceTree = ""; 237 | }; 238 | DF74B9BF1E1C92120028246C /* Themes */ = { 239 | isa = PBXGroup; 240 | children = ( 241 | DF74B9C01E1C92230028246C /* colors.swift */, 242 | DF74B9C31E1C92310028246C /* fonts.swift */, 243 | ); 244 | name = Themes; 245 | sourceTree = ""; 246 | }; 247 | DF74B9C61E1CADBE0028246C /* Actions */ = { 248 | isa = PBXGroup; 249 | children = ( 250 | DF74B9D11E1CCB590028246C /* PropertyActions.swift */, 251 | DF74B9DA1E1CE2F70028246C /* LoadingActions.swift */, 252 | DF74B9DD1E1CE3630028246C /* ErrorMessageActions.swift */, 253 | ); 254 | name = Actions; 255 | sourceTree = ""; 256 | }; 257 | DF74B9C71E1CADE10028246C /* Reducers */ = { 258 | isa = PBXGroup; 259 | children = ( 260 | DF74B9D71E1CDF680028246C /* AppReducer.swift */, 261 | ); 262 | name = Reducers; 263 | sourceTree = ""; 264 | }; 265 | DF74B9E01E1CF3BF0028246C /* API */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | DF74B9E11E1CF3EB0028246C /* PropertyApi.swift */, 269 | ); 270 | name = API; 271 | sourceTree = ""; 272 | }; 273 | DFC1E69F1E714CE000AB419F /* Coordinators */ = { 274 | isa = PBXGroup; 275 | children = ( 276 | DFC1E6A01E714CFF00AB419F /* SearchSceneCoordinator.swift */, 277 | DFC1E6A21E714EA200AB419F /* SearchResultsCoordinator.swift */, 278 | ); 279 | name = Coordinators; 280 | sourceTree = ""; 281 | }; 282 | DFC26C241E1F406400148AB5 /* BaseViews */ = { 283 | isa = PBXGroup; 284 | children = ( 285 | DF74B9BC1E1C91F00028246C /* XibBaseView.swift */, 286 | DF31C0521E1F27360053DB38 /* BaseViewController.swift */, 287 | ); 288 | name = BaseViews; 289 | sourceTree = ""; 290 | }; 291 | DFC26C251E1F6F3500148AB5 /* Sensor */ = { 292 | isa = PBXGroup; 293 | children = ( 294 | DFC26C261E1F6F8A00148AB5 /* LocationTracker.swift */, 295 | ); 296 | name = Sensor; 297 | sourceTree = ""; 298 | }; 299 | /* End PBXGroup section */ 300 | 301 | /* Begin PBXNativeTarget section */ 302 | DF3072681E1BA625005AA130 /* ReswiftAppCoordinatorDemo */ = { 303 | isa = PBXNativeTarget; 304 | buildConfigurationList = DF3072861E1BA625005AA130 /* Build configuration list for PBXNativeTarget "ReswiftAppCoordinatorDemo" */; 305 | buildPhases = ( 306 | DF3072651E1BA625005AA130 /* Sources */, 307 | DF3072661E1BA625005AA130 /* Frameworks */, 308 | DF3072671E1BA625005AA130 /* Resources */, 309 | DF74B9B31E1C8EF30028246C /* CopyFiles */, 310 | ); 311 | buildRules = ( 312 | ); 313 | dependencies = ( 314 | ); 315 | name = ReswiftAppCoordinatorDemo; 316 | productName = ReswiftAppCoordinatorDemo; 317 | productReference = DF3072691E1BA625005AA130 /* ReswiftAppCoordinatorDemo.app */; 318 | productType = "com.apple.product-type.application"; 319 | }; 320 | DF30727C1E1BA625005AA130 /* ReswiftAppCoordinatorDemoTests */ = { 321 | isa = PBXNativeTarget; 322 | buildConfigurationList = DF3072891E1BA625005AA130 /* Build configuration list for PBXNativeTarget "ReswiftAppCoordinatorDemoTests" */; 323 | buildPhases = ( 324 | DF3072791E1BA625005AA130 /* Sources */, 325 | DF30727A1E1BA625005AA130 /* Frameworks */, 326 | DF30727B1E1BA625005AA130 /* Resources */, 327 | ); 328 | buildRules = ( 329 | ); 330 | dependencies = ( 331 | DF30727F1E1BA625005AA130 /* PBXTargetDependency */, 332 | ); 333 | name = ReswiftAppCoordinatorDemoTests; 334 | productName = ReswiftAppCoordinatorDemoTests; 335 | productReference = DF30727D1E1BA625005AA130 /* ReswiftAppCoordinatorDemoTests.xctest */; 336 | productType = "com.apple.product-type.bundle.unit-test"; 337 | }; 338 | /* End PBXNativeTarget section */ 339 | 340 | /* Begin PBXProject section */ 341 | DF3072611E1BA625005AA130 /* Project object */ = { 342 | isa = PBXProject; 343 | attributes = { 344 | LastSwiftUpdateCheck = 0810; 345 | LastUpgradeCheck = 0810; 346 | ORGANIZATIONNAME = xianlinbox; 347 | TargetAttributes = { 348 | DF3072681E1BA625005AA130 = { 349 | CreatedOnToolsVersion = 8.1; 350 | DevelopmentTeam = TX44MTV4A5; 351 | ProvisioningStyle = Automatic; 352 | }; 353 | DF30727C1E1BA625005AA130 = { 354 | CreatedOnToolsVersion = 8.1; 355 | ProvisioningStyle = Automatic; 356 | TestTargetID = DF3072681E1BA625005AA130; 357 | }; 358 | }; 359 | }; 360 | buildConfigurationList = DF3072641E1BA625005AA130 /* Build configuration list for PBXProject "ReswiftAppCoordinatorDemo" */; 361 | compatibilityVersion = "Xcode 3.2"; 362 | developmentRegion = English; 363 | hasScannedForEncodings = 0; 364 | knownRegions = ( 365 | en, 366 | Base, 367 | ); 368 | mainGroup = DF3072601E1BA625005AA130; 369 | productRefGroup = DF30726A1E1BA625005AA130 /* Products */; 370 | projectDirPath = ""; 371 | projectRoot = ""; 372 | targets = ( 373 | DF3072681E1BA625005AA130 /* ReswiftAppCoordinatorDemo */, 374 | DF30727C1E1BA625005AA130 /* ReswiftAppCoordinatorDemoTests */, 375 | ); 376 | }; 377 | /* End PBXProject section */ 378 | 379 | /* Begin PBXResourcesBuildPhase section */ 380 | DF3072671E1BA625005AA130 /* Resources */ = { 381 | isa = PBXResourcesBuildPhase; 382 | buildActionMask = 2147483647; 383 | files = ( 384 | DF0E3FB21E236C0400D00586 /* PropertyDetailView.xib in Resources */, 385 | DF23DFDD1E2219B10032641D /* SearchResultView.xib in Resources */, 386 | DF74B9B71E1C906A0028246C /* SearchView.xib in Resources */, 387 | DF3072771E1BA625005AA130 /* LaunchScreen.storyboard in Resources */, 388 | DF3072741E1BA625005AA130 /* Assets.xcassets in Resources */, 389 | ); 390 | runOnlyForDeploymentPostprocessing = 0; 391 | }; 392 | DF30727B1E1BA625005AA130 /* Resources */ = { 393 | isa = PBXResourcesBuildPhase; 394 | buildActionMask = 2147483647; 395 | files = ( 396 | DF74B9B81E1C906A0028246C /* SearchView.xib in Resources */, 397 | ); 398 | runOnlyForDeploymentPostprocessing = 0; 399 | }; 400 | /* End PBXResourcesBuildPhase section */ 401 | 402 | /* Begin PBXSourcesBuildPhase section */ 403 | DF3072651E1BA625005AA130 /* Sources */ = { 404 | isa = PBXSourcesBuildPhase; 405 | buildActionMask = 2147483647; 406 | files = ( 407 | DF31C0531E1F27360053DB38 /* BaseViewController.swift in Sources */, 408 | DF74B9BD1E1C91F00028246C /* XibBaseView.swift in Sources */, 409 | DF74B9D21E1CCB590028246C /* PropertyActions.swift in Sources */, 410 | DF74B9C11E1C92230028246C /* colors.swift in Sources */, 411 | DF74B9D81E1CDF680028246C /* AppReducer.swift in Sources */, 412 | DF74B9DE1E1CE3630028246C /* ErrorMessageActions.swift in Sources */, 413 | DFC1E6A11E714CFF00AB419F /* SearchSceneCoordinator.swift in Sources */, 414 | DF74B9DB1E1CE2F70028246C /* LoadingActions.swift in Sources */, 415 | DF74B9C91E1CAF660028246C /* AppState.swift in Sources */, 416 | DFC1E6A31E714EA200AB419F /* SearchResultsCoordinator.swift in Sources */, 417 | DF74B9E21E1CF3EB0028246C /* PropertyApi.swift in Sources */, 418 | DF3072901E1BE7D5005AA130 /* AppCoordinator.swift in Sources */, 419 | DFC26C221E1F404700148AB5 /* SearchView.swift in Sources */, 420 | DF30726F1E1BA625005AA130 /* SearchSceneViewController.swift in Sources */, 421 | DF23DFDB1E2218990032641D /* SearchResultView.swift in Sources */, 422 | DF0E3FB41E236C1900D00586 /* PropertyDetailView.swift in Sources */, 423 | DF74B9C41E1C92310028246C /* fonts.swift in Sources */, 424 | DF30726D1E1BA625005AA130 /* AppDelegate.swift in Sources */, 425 | DF23DFD91E2211A70032641D /* SearchResultViewController.swift in Sources */, 426 | DFC26C271E1F6F8A00148AB5 /* LocationTracker.swift in Sources */, 427 | DF0E3FB01E2369BA00D00586 /* PropertyDetailSceneViewController.swift in Sources */, 428 | DF0E3FB71E2378AF00D00586 /* StringUtil.swift in Sources */, 429 | ); 430 | runOnlyForDeploymentPostprocessing = 0; 431 | }; 432 | DF3072791E1BA625005AA130 /* Sources */ = { 433 | isa = PBXSourcesBuildPhase; 434 | buildActionMask = 2147483647; 435 | files = ( 436 | DF0E3FBA1E237C9F00D00586 /* StringUtilSpec.swift in Sources */, 437 | DF74B9C51E1C92310028246C /* fonts.swift in Sources */, 438 | DF74B9E31E1CF3EB0028246C /* PropertyApi.swift in Sources */, 439 | DF74B9CA1E1CAF660028246C /* AppState.swift in Sources */, 440 | DF74B9BE1E1C91F00028246C /* XibBaseView.swift in Sources */, 441 | DF74B9DC1E1CE2F70028246C /* LoadingActions.swift in Sources */, 442 | DF74B9C21E1C92230028246C /* colors.swift in Sources */, 443 | DFF15E401E212BDC0072DACF /* LocationTracker.swift in Sources */, 444 | DF0E3FBB1E237E5900D00586 /* StringUtil.swift in Sources */, 445 | DF74B9D31E1CCB590028246C /* PropertyActions.swift in Sources */, 446 | DF74B9DF1E1CE3630028246C /* ErrorMessageActions.swift in Sources */, 447 | DF74B9D91E1CDF680028246C /* AppReducer.swift in Sources */, 448 | ); 449 | runOnlyForDeploymentPostprocessing = 0; 450 | }; 451 | /* End PBXSourcesBuildPhase section */ 452 | 453 | /* Begin PBXTargetDependency section */ 454 | DF30727F1E1BA625005AA130 /* PBXTargetDependency */ = { 455 | isa = PBXTargetDependency; 456 | target = DF3072681E1BA625005AA130 /* ReswiftAppCoordinatorDemo */; 457 | targetProxy = DF30727E1E1BA625005AA130 /* PBXContainerItemProxy */; 458 | }; 459 | /* End PBXTargetDependency section */ 460 | 461 | /* Begin PBXVariantGroup section */ 462 | DF3072751E1BA625005AA130 /* LaunchScreen.storyboard */ = { 463 | isa = PBXVariantGroup; 464 | children = ( 465 | DF3072761E1BA625005AA130 /* Base */, 466 | ); 467 | name = LaunchScreen.storyboard; 468 | sourceTree = ""; 469 | }; 470 | /* End PBXVariantGroup section */ 471 | 472 | /* Begin XCBuildConfiguration section */ 473 | DF3072841E1BA625005AA130 /* Debug */ = { 474 | isa = XCBuildConfiguration; 475 | buildSettings = { 476 | ALWAYS_SEARCH_USER_PATHS = NO; 477 | CLANG_ANALYZER_NONNULL = YES; 478 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 479 | CLANG_CXX_LIBRARY = "libc++"; 480 | CLANG_ENABLE_MODULES = YES; 481 | CLANG_ENABLE_OBJC_ARC = YES; 482 | CLANG_WARN_BOOL_CONVERSION = YES; 483 | CLANG_WARN_CONSTANT_CONVERSION = YES; 484 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 485 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 486 | CLANG_WARN_EMPTY_BODY = YES; 487 | CLANG_WARN_ENUM_CONVERSION = YES; 488 | CLANG_WARN_INFINITE_RECURSION = YES; 489 | CLANG_WARN_INT_CONVERSION = YES; 490 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 491 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 492 | CLANG_WARN_UNREACHABLE_CODE = YES; 493 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 494 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 495 | COPY_PHASE_STRIP = NO; 496 | DEBUG_INFORMATION_FORMAT = dwarf; 497 | ENABLE_STRICT_OBJC_MSGSEND = YES; 498 | ENABLE_TESTABILITY = YES; 499 | GCC_C_LANGUAGE_STANDARD = gnu99; 500 | GCC_DYNAMIC_NO_PIC = NO; 501 | GCC_NO_COMMON_BLOCKS = YES; 502 | GCC_OPTIMIZATION_LEVEL = 0; 503 | GCC_PREPROCESSOR_DEFINITIONS = ( 504 | "DEBUG=1", 505 | "$(inherited)", 506 | ); 507 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 508 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 509 | GCC_WARN_UNDECLARED_SELECTOR = YES; 510 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 511 | GCC_WARN_UNUSED_FUNCTION = YES; 512 | GCC_WARN_UNUSED_VARIABLE = YES; 513 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 514 | MTL_ENABLE_DEBUG_INFO = YES; 515 | ONLY_ACTIVE_ARCH = YES; 516 | SDKROOT = iphoneos; 517 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 518 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 519 | }; 520 | name = Debug; 521 | }; 522 | DF3072851E1BA625005AA130 /* Release */ = { 523 | isa = XCBuildConfiguration; 524 | buildSettings = { 525 | ALWAYS_SEARCH_USER_PATHS = NO; 526 | CLANG_ANALYZER_NONNULL = YES; 527 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 528 | CLANG_CXX_LIBRARY = "libc++"; 529 | CLANG_ENABLE_MODULES = YES; 530 | CLANG_ENABLE_OBJC_ARC = YES; 531 | CLANG_WARN_BOOL_CONVERSION = YES; 532 | CLANG_WARN_CONSTANT_CONVERSION = YES; 533 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 534 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 535 | CLANG_WARN_EMPTY_BODY = YES; 536 | CLANG_WARN_ENUM_CONVERSION = YES; 537 | CLANG_WARN_INFINITE_RECURSION = YES; 538 | CLANG_WARN_INT_CONVERSION = YES; 539 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 540 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 541 | CLANG_WARN_UNREACHABLE_CODE = YES; 542 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 543 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 544 | COPY_PHASE_STRIP = NO; 545 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 546 | ENABLE_NS_ASSERTIONS = NO; 547 | ENABLE_STRICT_OBJC_MSGSEND = YES; 548 | GCC_C_LANGUAGE_STANDARD = gnu99; 549 | GCC_NO_COMMON_BLOCKS = YES; 550 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 551 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 552 | GCC_WARN_UNDECLARED_SELECTOR = YES; 553 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 554 | GCC_WARN_UNUSED_FUNCTION = YES; 555 | GCC_WARN_UNUSED_VARIABLE = YES; 556 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 557 | MTL_ENABLE_DEBUG_INFO = NO; 558 | SDKROOT = iphoneos; 559 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 560 | VALIDATE_PRODUCT = YES; 561 | }; 562 | name = Release; 563 | }; 564 | DF3072871E1BA625005AA130 /* Debug */ = { 565 | isa = XCBuildConfiguration; 566 | buildSettings = { 567 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 568 | DEVELOPMENT_TEAM = TX44MTV4A5; 569 | FRAMEWORK_SEARCH_PATHS = ( 570 | "$(inherited)", 571 | "$(PROJECT_DIR)/Carthage/Build/iOS", 572 | ); 573 | INFOPLIST_FILE = ReswiftAppCoordinatorDemo/Info.plist; 574 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 575 | PRODUCT_BUNDLE_IDENTIFIER = com.xianlinbox.ReswiftAppCoordinatorDemo; 576 | PRODUCT_NAME = "$(TARGET_NAME)"; 577 | SWIFT_VERSION = 3.0; 578 | }; 579 | name = Debug; 580 | }; 581 | DF3072881E1BA625005AA130 /* Release */ = { 582 | isa = XCBuildConfiguration; 583 | buildSettings = { 584 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 585 | DEVELOPMENT_TEAM = TX44MTV4A5; 586 | FRAMEWORK_SEARCH_PATHS = ( 587 | "$(inherited)", 588 | "$(PROJECT_DIR)/Carthage/Build/iOS", 589 | ); 590 | INFOPLIST_FILE = ReswiftAppCoordinatorDemo/Info.plist; 591 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 592 | PRODUCT_BUNDLE_IDENTIFIER = com.xianlinbox.ReswiftAppCoordinatorDemo; 593 | PRODUCT_NAME = "$(TARGET_NAME)"; 594 | SWIFT_VERSION = 3.0; 595 | }; 596 | name = Release; 597 | }; 598 | DF30728A1E1BA625005AA130 /* Debug */ = { 599 | isa = XCBuildConfiguration; 600 | buildSettings = { 601 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 602 | BUNDLE_LOADER = "$(TEST_HOST)"; 603 | INFOPLIST_FILE = ReswiftAppCoordinatorDemoTests/Info.plist; 604 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 605 | PRODUCT_BUNDLE_IDENTIFIER = com.xianlinbox.ReswiftAppCoordinatorDemoTests; 606 | PRODUCT_NAME = "$(TARGET_NAME)"; 607 | SWIFT_VERSION = 3.0; 608 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReswiftAppCoordinatorDemo.app/ReswiftAppCoordinatorDemo"; 609 | }; 610 | name = Debug; 611 | }; 612 | DF30728B1E1BA625005AA130 /* Release */ = { 613 | isa = XCBuildConfiguration; 614 | buildSettings = { 615 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 616 | BUNDLE_LOADER = "$(TEST_HOST)"; 617 | INFOPLIST_FILE = ReswiftAppCoordinatorDemoTests/Info.plist; 618 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 619 | PRODUCT_BUNDLE_IDENTIFIER = com.xianlinbox.ReswiftAppCoordinatorDemoTests; 620 | PRODUCT_NAME = "$(TARGET_NAME)"; 621 | SWIFT_VERSION = 3.0; 622 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReswiftAppCoordinatorDemo.app/ReswiftAppCoordinatorDemo"; 623 | }; 624 | name = Release; 625 | }; 626 | /* End XCBuildConfiguration section */ 627 | 628 | /* Begin XCConfigurationList section */ 629 | DF3072641E1BA625005AA130 /* Build configuration list for PBXProject "ReswiftAppCoordinatorDemo" */ = { 630 | isa = XCConfigurationList; 631 | buildConfigurations = ( 632 | DF3072841E1BA625005AA130 /* Debug */, 633 | DF3072851E1BA625005AA130 /* Release */, 634 | ); 635 | defaultConfigurationIsVisible = 0; 636 | defaultConfigurationName = Release; 637 | }; 638 | DF3072861E1BA625005AA130 /* Build configuration list for PBXNativeTarget "ReswiftAppCoordinatorDemo" */ = { 639 | isa = XCConfigurationList; 640 | buildConfigurations = ( 641 | DF3072871E1BA625005AA130 /* Debug */, 642 | DF3072881E1BA625005AA130 /* Release */, 643 | ); 644 | defaultConfigurationIsVisible = 0; 645 | defaultConfigurationName = Release; 646 | }; 647 | DF3072891E1BA625005AA130 /* Build configuration list for PBXNativeTarget "ReswiftAppCoordinatorDemoTests" */ = { 648 | isa = XCConfigurationList; 649 | buildConfigurations = ( 650 | DF30728A1E1BA625005AA130 /* Debug */, 651 | DF30728B1E1BA625005AA130 /* Release */, 652 | ); 653 | defaultConfigurationIsVisible = 0; 654 | defaultConfigurationName = Release; 655 | }; 656 | /* End XCConfigurationList section */ 657 | }; 658 | rootObject = DF3072611E1BA625005AA130 /* Project object */; 659 | } 660 | --------------------------------------------------------------------------------