How to return gms location name from lat long swiftui - google-maps

I have a place picker that gives me the location by searching the street name.
How I can retrieve the location name with this same class Placepicker just giving the lat long coordinates?
struct PlacePicker: UIViewControllerRepresentable {
func makeCoordinator() -> GooglePlacesCoordinator {
GooglePlacesCoordinator(self)
}
#Environment(\.presentationMode) var presentationMode
#Binding var address: String
#Binding var latitude: Double
#Binding var longitude: Double
func makeUIViewController(context: UIViewControllerRepresentableContext<PlacePicker>) -> GMSAutocompleteViewController {
GMSPlacesClient.provideAPIKey("xxxx")
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.delegate = context.coordinator
let fields: GMSPlaceField = GMSPlaceField(rawValue:UInt(GMSPlaceField.name.rawValue) |
UInt(GMSPlaceField.placeID.rawValue) |
UInt(GMSPlaceField.coordinate.rawValue) |
GMSPlaceField.addressComponents.rawValue |
GMSPlaceField.formattedAddress.rawValue)
autocompleteController.placeFields = fields
let filter = GMSAutocompleteFilter()
filter.type = .address
autocompleteController.autocompleteFilter = filter
return autocompleteController
}
func updateUIViewController(_ uiViewController: GMSAutocompleteViewController, context: UIViewControllerRepresentableContext<PlacePicker>) {
}
class GooglePlacesCoordinator: NSObject, UINavigationControllerDelegate, GMSAutocompleteViewControllerDelegate {
var parent: PlacePicker
init(_ parent: PlacePicker) {
self.parent = parent
}
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
DispatchQueue.main.async {
print(place.description.description as Any)
self.parent.address = place.formattedAddress ?? "adresa gresita"
self.parent.presentationMode.wrappedValue.dismiss()
self.parent.latitude=place.coordinate.latitude
self.parent.longitude=place.coordinate.longitude
}
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
print("Error: ", error.localizedDescription)
}
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
parent.presentationMode.wrappedValue.dismiss()
}
}
}
How can I add a function like, giveLocationByLatLong(lat: Double, long: Double)?
Or can I use some stuff from the place picker class?

Related

add 'Current location' button at the top of the autocomplete places list

I have a autocomplete that works fine, but I want to add "set current location" to the autocompleter controller.
I ve searched in multiple places but there are none implementation for swiftui,
This is my Place picker for autocompleter:
struct PlacePicker: UIViewControllerRepresentable {
func makeCoordinator() -> GooglePlacesCoordinator {
GooglePlacesCoordinator(self)
}
#Environment(\.presentationMode) var presentationMode
#Binding var address: String
#Binding var latitude: Double
#Binding var longitude: Double
func makeUIViewController(context: UIViewControllerRepresentableContext<PlacePicker>) -> GMSAutocompleteViewController {
GMSPlacesClient.provideAPIKey("xxxxxxxxxxxxxxxxxxxxx")
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.delegate = context.coordinator
let fields: GMSPlaceField = GMSPlaceField(rawValue:UInt(GMSPlaceField.name.rawValue) |
UInt(GMSPlaceField.placeID.rawValue) |
UInt(GMSPlaceField.coordinate.rawValue) |
GMSPlaceField.addressComponents.rawValue |
GMSPlaceField.formattedAddress.rawValue)
autocompleteController.placeFields = fields
let filter = GMSAutocompleteFilter()
filter.type = .address
autocompleteController.autocompleteFilter = filter
return autocompleteController
}
func updateUIViewController(_ uiViewController: GMSAutocompleteViewController, context: UIViewControllerRepresentableContext<PlacePicker>) {
}
class GooglePlacesCoordinator: NSObject, UINavigationControllerDelegate, GMSAutocompleteViewControllerDelegate {
var parent: PlacePicker
init(_ parent: PlacePicker) {
self.parent = parent
}
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
DispatchQueue.main.async {
print(place.description.description as Any)
self.parent.address = place.name!
self.parent.presentationMode.wrappedValue.dismiss()
print("latitude: \(place.coordinate.latitude)")
print("longitude: \(place.coordinate.longitude)")
self.parent.latitude=place.coordinate.latitude
self.parent.longitude=place.coordinate.longitude
}
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
print("Error: ", error.localizedDescription)
}
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
parent.presentationMode.wrappedValue.dismiss()
}
}
}
Any way to add a button/label with "use current location" at the top of this list?
enter image description here

How to get latitude and longitude from API and show it on MKMapKit

I'm trying to show latitude and longitude for planes on the map. I have a model for the API request. So the main think is, how to get the latitude and longitude on the ViewController and show it on the map. How to append this data to location model or create maybe dictionary or smth else. Here is my APICaller file:
func fetchFlightData(completion: #escaping(DataResponse) -> Void) {
guard let url = URL(string: "https://app.goflightlabs.com/advanced-real-time-flights?access_key=My_KEY") else { return }
let dataTask = URLSession.shared.dataTask(with: url) { (data, _, error) in
if let error = error {
print("ERROR FETCHING")
}
guard let jsonData = data else { return }
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(DataResponse.self, from: jsonData)
completion(decodedData)
} catch {
print("SOME ERROR")
}
}
dataTask.resume()
}
Model file:
import Foundation
struct DataResponse: Decodable {
var data: [Data]
}
struct Data: Decodable {
var geography: Geography
}
struct Geography: Decodable {
var latitude: Double?
var longitude: Double?
}
Here we can see geography, which contains latitude and longitude, which I need. Example API Response:
{
"success": true,
"data": [
{
"aircraft": {
"iataCode":"B789",
"icao24":"C01040",
"icaoCode":"B789",
"regNumber":"C-FGDZ"
},
"airline": {
"iataCode":"AC",
"icaoCode":"ACA"
},
"arrival" : {
"iataCode":"GRU",
"icaoCode":"SBGR"
},
"departure" : {
"iataCode":"EZE",
"icaoCode":"SAEZ"
},
"flight" : {
"iataNumber":"AC91",
"icaoNumber":"ACA091",
"number":"91"
},
"geography" : {
"altitude":12496.8,
"direction":31.15,
"latitude":-26.98,
"longitude":-49.95
},
"speed" : {
"horizontal":880.74,
"isGround":0,
"vspeed":-1.188
},
"status":"en-route",
"system" : {
"squawk":null,
"updated":1665523076
}
},
{ ... },
]
}
Here is the file with the location model:
struct Location {
let latitude: Double
let longitude: Double
}
I'm calling the function of the API in viewdidload and getting the data:
var locations = [Location]()
override func viewDidLoad() {
super.viewDidLoad()
annotation.coordinate = coordinate
myMap.delegate = self
fetchFlightData { (result) in
"How to append here the data from Geography to Location"
print("SUCCESS")
}
}
Here is methods of MAPKit:
func annotationsOnMap() {
for location in locations {
let annotations = MKPointAnnotation()
print("LOCATION IS \(location)")
//annotations.title = location.title
annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
myMap.addAnnotation(annotations)
let locationCoordinate2d = annotations.coordinate
let span = MKCoordinateSpan(latitudeDelta: 30, longitudeDelta: 30)
let region = MKCoordinateRegion(center: locationCoordinate2d, span: span)
myMap.setRegion(region, animated: true)
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else {
return nil
}
var annotationView = myMap.dequeueReusableAnnotationView(withIdentifier: "custom")
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "custom")
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
let image = UIImage(named: "airPlane")
let size = CGSize(width: 20, height: 20)
UIGraphicsBeginImageContext(size)
image!.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
annotationView?.image = resizedImage
return annotationView
}
I've tried to get data from result in viewdidload, but here I'm getting "Data" only, not the Geography, that I need to show

How to make cell delete itself based upon json value firebase realtime database

So I am retrieving data from firebase realtime database and I am pulling it all, and I need every cell to show the parent club only if its child "Promoted" has a value of "Yes" and if it does not I need the cell to delete itself and only 3 clubs ever have promoted being equal to "Yes"
it pulls it all, and displayed it all on the screen, but I am stuck on how to delete the cells where the children do not have promoted being equal to "Yes"
//tempViewController.swift
import Foundation
import UIKit
import FirebaseDatabase
class tempViewController: UIViewController , UITableViewDelegate , UITableViewDataSource {
#IBOutlet weak var tempTableView: UITableView!
var finalBar = [NightClubs]()
override func viewDidLoad() {
super.viewDidLoad()
tempTableView.dataSource = self
tempTableView.delegate = self
DataService.ds.REF_BARS.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.value as Any)
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshot {
print(snap)
if let barData = snap.value as? Dictionary<String, AnyObject> {
let bar = NightClubs(barData: barData)
self.finalBar.append(bar)
print(self.finalBar)
self.tempTableView.reloadData()
}
self.tempTableView.reloadData()
}
self.tempTableView.reloadData()
}
self.tempTableView.reloadData()
})
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView( _ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return finalBar.count
}
func tableView( _ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tempTableView.dequeueReusableCell(withIdentifier: "newCell") as! newCell
let barz = finalBar[indexPath.row]
if barz.promoted == "Yes" {
cell.setData(data: barz)
// this sends the nightclubs that have .promoted == "Yes"
} else {
// need to remove the cell from the user view
// as only 3 NightClubs will have promoted == "Yes"
// so i only want to see 3 cells
}
return cell
}
}
//newCell.swift
import Foundation
import UIKit
class newCell: UITableViewCell {
#IBOutlet weak var nameTextLabel: UILabel!
#IBOutlet weak var locationTextLabel: UILabel!
func setData(data: NightClubs) {
nameTextLabel.text = data.name
locationTextLabel.text = data.location
}
}
//NightClubs.swift
import Foundation
import UIKit
class NightClubs {
private var _name: String!
private var _location: String!
private var _address: String!
private var _latitude: String!
private var _longitude: String!
private var _promoted: String!
private var _type: String!
private var _liveCount: String!
private var _goingCount: String!
private var _description: String!
var name: String! {
return _name
}
var location: String! {
return _location
}
var address: String! {
return _address
}
var latitude: String! {
return _latitude
}
var longitude: String! {
return _longitude
}
var promoted: String! {
return _promoted
}
var type: String! {
return _type
}
var liveCount: String! {
return _liveCount
}
var goingCount: String! {
return _goingCount
}
var description: String! {
return _description
}
init(name: String, location: String, address: String, latitude: String, longitude: String, promoted: String, type: String, liveCount: String, goingCount: String, description: String) {
self._name = name
self._location = location
self._address = address
self._latitude = latitude
self._longitude = longitude
self._promoted = promoted
self._type = type
self._liveCount = liveCount
self._goingCount = goingCount
self._description = description
}
init(barData: Dictionary<String, AnyObject>) {
if let name = barData["Name"] as? String {
self._name = name
}
if let location = barData["Location"] as? String {
self._location = location
}
if let address = barData["Address"] as? String {
self._address = address
}
if let latitude = barData["Latitude"] as? String {
self._latitude = latitude
}
if let longitude = barData["Longitude"] as? String {
self._longitude = longitude
}
if let promoted = barData["Promoted"] as? String {
self._promoted = promoted
}
if let type = barData["Type"] as? String {
self._type = type
}
if let liveCount = barData["LiveCount"] as? String {
self._liveCount = liveCount
}
if let goingCount = barData["GoingCount"] as? String {
self._goingCount = goingCount
}
if let description = barData["Description"] as? String {
self._description = description
}
}
}
I expected it to basically just show 3 children where its children equals "Yes" and there is no error as I am not doing anything at all to change it
You could do 1 of the following:
1) Either add the only bars in the finalBar array which has the promoted value as "Yes". For this update your data fetching code should be like.
DataService.ds.REF_BARS.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.value as Any)
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshot {
print(snap)
if let barData = snap.value as? Dictionary<String, AnyObject>
{
let bar = NightClubs(barData: barData)
// Add this check here
if bar.promoted == "Yes" {
self.finalBar.append(bar)
}
print(self.finalBar)
}
}
}
self.tempTableView.reloadData()
})
2) Or Create an other array and filter the finalBar array so it gives the only the bars with promoted as "Yes" and store it in different array. Then use this new array in showing up your cells.
e.g. filteredFinalBars = finalBar.filter { $0.promoted == "Yes"}
DataService.ds.REF_BARS.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.value as Any)
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshot {
print(snap)
if let barData = snap.value as? Dictionary<String, AnyObject>
{
let bar = NightClubs(barData: barData)
self.finalBar.append(bar)
print(self.finalBar)
}
}
//Add this to filter the bars with promoted as "yes".
//Then use this array in tableView delegate and datasource methods
filteredFinalBars = finalBar.filter { $0.promoted == "Yes"}
}
self.tempTableView.reloadData()
})

how I can call variable in mappable class from main view

I have three class one is the main view and here is the code of it
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
getJSONS().getLowerJSON()
setupUI()
}
func setupUI(){
print(lowerData.companyName)
}
}
getsJSONS call an function that call almofire to handle json as in this code
class getJSONS {
func getLowerJSON(){
let URL = "http://tickerchart.com/interview/company-details.json"
Alamofire.request(URL).responseObject { (response: DataResponse<lowereViewResponse>) in
let lowereViewResponse = response.result.value
}
}
}
lowereViewResponse call the mappable class as in this code
class lowereViewResponse: NSObject, Mappable {
var companyName : String?
var symbol : String?
var tradesCount : Int?
var high : Int?
var low : Int?
var volume : Int?
var amount : Int?
override init() {
super.init()
}
convenience required init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
companyName <- map["company-name"]
symbol <- map["symbol"]
tradesCount <- map["trades-count"]
high <- map["high"]
low <- map["low"]
volume <- map["volume"]
}
required init?(map: Map){
companyName = ""
symbol = ""
tradesCount = 0
high = 0
low = 0
volume = 0
amount = 0
price = 0
}
}
all imports are done
I am trying to call class lowereViewResponse to access the variable but I get null when this is exited "print(lowerData.companyName)"
You can use like following:
let lowereViewObject: lowereViewResponse = Mapper< lowereViewResponse >().map(JSON: result)

How to map different type using ObjectMapper?

I'm using ObjectMapper to map my JSON to Swift object.
I have the following Swift object:
class User: Mappable {
var name: String?
var val: Int?
required init?(map: Map) { }
func mapping(map: Map) {
name <- map["name"]
val <- map["userId"]
}
}
I have this JSON structure:
{
"name": "first",
"userId": "1" // here is `String` type.
},
{
"name": "second",
"userId": 1 // here is `Int` type.
}
After mapping the JSON, the userId of User which name is "first" is null.
How can I map Int/String to Int?
After reading the code of ObjectMapper, I found an easier way to solve the problem, it's to custom the transform.
public class IntTransform: TransformType {
public typealias Object = Int
public typealias JSON = Any?
public init() {}
public func transformFromJSON(_ value: Any?) -> Int? {
var result: Int?
guard let json = value else {
return result
}
if json is Int {
result = (json as! Int)
}
if json is String {
result = Int(json as! String)
}
return result
}
public func transformToJSON(_ value: Int?) -> Any?? {
guard let object = value else {
return nil
}
return String(object)
}
}
then, use the custom transform to the mapping function.
class User: Mappable {
var name: String?
var userId: Int?
required init?(map: Map) { }
func mapping(map: Map) {
name <- map["name"]
userId <- (map["userId"], IntTransform()) // here use the custom transform.
}
}
Hope it can help others who have the same problem. :)
If your API is like this - it is very bad API. What you could do is have two variables instead of one:
class User: Mappable {
var name: String?
var valInt: Int?
var valString: String?
required init?(map: Map) { }
func mapping(map: Map) {
name <- map["name"]
valInt <- map["val"]
valString <- map["val"]
}
}
You can even add function that will get you value like:
// bellow func mapping(map: Map){
func getUserId() -> String {
if(self.valInt != nil) {
return "\(valInt!)"
}
else {
return valString!
}
}
Or, using if let:
func getUserId() -> String {
if let userId = self.valInt {
return "\(userId)"
}
if let userId = valString {
return userId
}
return ""
}
Or using optionals so later on you can use if let userId = object.getUserId()
func getUserId() -> String? {
if(self.valInt != nil) {
return String(valInt)
}
else {
return valString
}
}
You should improve your API. However, if you can't do that, then try this code:
class User: Mappable {
var name: String?
var val: Int?
required init?(map: Map) { }
func mapping(map: Map) {
name <- map["name"]
// 1: Get the value of JSON and store it in a variable of type Any?
var userIdData: Any?
userIdData <- map["userId"]
// 2: Check the value type of the value and convert to Int type
if userIdData is Int {
val = (userIdData as! Int)
} else if userIdData is String {
val = Int(userIdData as! String)
}
}
}
You can refer to this document: Type Casting