Commit e6583de2 by Demid Merzlyakov

Search implementation and a bit of refactoring.

parent d761faf9
......@@ -94,7 +94,7 @@ private extension SavedCitiesViewController {
func prepareSearchBar() {
searchBar.searchBarStyle = .minimal
searchBar.placeholder = "Search"
searchBar.placeholder = "Search".localized(comment: "Search bar placeholder text.")
view.addSubview(searchBar)
searchBar.snp.makeConstraints { (make) in
make.top.equalToSuperview()
......@@ -143,12 +143,12 @@ private extension SavedCitiesViewController {
//MARK: UItableView Data Source
extension SavedCitiesViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return locationsViewModel.savedCities.count
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.savedCities[indexPath.row],
cell.configure(geoName: locationsViewModel.cities[indexPath.row],
mode: locationsViewModel.displayMode)
return cell
}
......@@ -161,7 +161,7 @@ extension SavedCitiesViewController: UITableViewDelegate {
container.backgroundColor = ThemeManager.currentTheme.navigationBarBackgroundColor
let titleLabel = UILabel()
titleLabel.text = "Saved Cities (\(self.locationsViewModel.savedCities.count))"
titleLabel.text = "Saved Cities".localized + "( \(self.locationsViewModel.cities.count))"
titleLabel.font = AppFont.SFPro.bold(size: 24)
titleLabel.textColor = ThemeManager.currentTheme.primaryTextColor
container.addSubview(titleLabel)
......
......@@ -6,6 +6,7 @@
//
import UIKit
import AlgoliaSearchClient
protocol LocationsViewModelDelegate:class {
func viewModelDidChange(model:LocationsViewModel)
......@@ -22,7 +23,12 @@ enum LocationsViewModelDisplayMode {
class LocationsViewModel {
//Public
weak var delegate:LocationsViewModelDelegate?
private(set) var savedCities = [GeoNamesPlace]()
private(set) var cities = [GeoNamesPlace]() {
didSet {
assert(Thread.isMainThread)
self.delegate?.viewModelDidChange(model: self)
}
}
private(set) var displayMode:LocationsViewModelDisplayMode = .savedCities
init() {
......@@ -49,28 +55,93 @@ class LocationsViewModel {
kazan.city = "Kazan"
kazan.stateCode = "000000"
kazan.country = "Russia"
savedCities = [perm, moscow, sp, kazan]
cities = [perm, moscow, sp, kazan]
}
func fetchCities(query:String) {
//Some fetching method
//Tell delegate to refresh UI
self.delegate?.viewModelDidChange(model: self)
// This is a test location that can be interpreted on the server to return all alerts
guard query != "1wville" else {
let fakePlace = GeoNamesPlace()
fakePlace.latitude = "67.25639"
fakePlace.longitude = "-150.18417"
fakePlace.city = "1WVille"
fakePlace.state = "Alaska"
fakePlace.stateCode = "AK"
fakePlace.country = "United States"
fakePlace.countryCode = "US"
fakePlace.fcodeName = "populated place"
fakePlace.toponymName = "1WVille"
fakePlace.isMyLocation = false
DispatchQueue.main.async {
self.cities = []
}
return
}
Logger.minSeverityLevel = .warning
var algoliaQuery = PlacesQuery(query)
algoliaQuery.aroundLatLngViaIP = true
algoliaQuery.type = .city
let placesClient: PlacesClient = PlacesClient(appID: ApplicationID (rawValue: kAlgoliaAppId),
apiKey: APIKey(rawValue: kAlgoliaAPIKey))
let language: Language = Language(rawValue: NSLocale.preferredLanguages.first?.components(separatedBy: "-").first ?? "en")
print("Search: using language \(language.rawValue)")
var filteredPlaces = [GeoNamesPlace]()
placesClient.search(query: algoliaQuery, language: language, requestOptions: nil) { (result: Result<PlacesClient.SingleLanguageResponse, Error>) in
switch (result) {
case .success(let response):
print("Search: got \(response.nbHits) results")
for hit: Hit<Place> in response.hits {
let place = GeoNamesPlace()
if hit.object.localeNames?.first == nil {
print("Search: skip 1 object.");
continue
}
place.city = hit.object.localeNames?.first
place.state = hit.object.administrative?.first
place.country = hit.object.country ?? "" // ?? "" part is from the Android code, may be not needed on iOS
place.countryCode = hit.object.countryCode?.rawValue.uppercased() ?? "" // ?? "" part is from the Android code, may be not needed on iOS
if let geolocation = hit.geolocation {
place.latitude = "\(geolocation.latitude)"
place.longitude = "\(geolocation.longitude)"
}
else {
place.latitude = ""
place.longitude = ""
}
filteredPlaces.append(place)
}
DispatchQueue.main.async {
self.cities = filteredPlaces
}
break
case .failure(let error):
DispatchQueue.main.async {
self.delegate?.viewModel(model: self, errorHasOccured: error)
}
break
}
}
}
func add(city:GeoNamesPlace) {
//Tell delegate to refresh UI
self.delegate?.viewModelDidChange(model: self)
// TODO: Just update self.cities, it will trigger a viewModelDidChange call
}
func delete(city:GeoNamesPlace) {
//Tell delegate to refresh UI
self.delegate?.viewModelDidChange(model: self)
// TODO: Just update self.cities, it will trigger a viewModelDidChange call
}
func select(city:GeoNamesPlace) {
//Tell delegate to refresh UI
// TODO: Tell delegate to refresh UI
self.delegate?.viewModelDidChange(model: self)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment