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

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

Related

How to return gms location name from lat long swiftui

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?

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 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

how to parse complex JSON and show it inside and outside of CollectionView

I have been dealing with JSON for a month now , getting better day by day. Here is a complex jigsaw I have been circling around. JSON return I get is like this :
{
"main_content": [
{
"product_title": "product 3",
"description": "",
"regular_price": "320",
"sale_price": "",
"product_currency": "$",
"size": [
{
"size_data": "L"
},
{
"size_data": "S"
}
],
"color": [
{
"color_data": "RED"
},
{
"color_data": "WHITE"
}
],
"gallery": [
{
"guid": "http://xxx/wp-content/uploads/2016/11/catagory1.jpg"
},
{
"guid": "http://xxx/wp-content/uploads/2016/11/catagory3.jpg"
}
]
}
]
}
Now , here product_title , description , regular_price , sale_price and product_currency will be outside of array as you can see. For size & color I need to fetch as array outside of my CollectionView , I dunno how to iterate through the array outside of a collectionView or tableView, coz in those I got an indexpath to iterate but I dunno what to do outside a collectionView or tableView. Finally My Image slider will be inside CollectionView therefore gallery items needs to be inside that. Here is visual image of my respective page.
Now here is the POST call using Alamofire in my view
import Foundation
import Alamofire
import SwiftyJSON
//Error could happen for these reason
enum ProductDetailsManagerError: Error {
case network(error: Error)
case apiProvidedError(reason: String)
case authCouldNot(reason: String)
case authLost(reason: String)
case objectSerialization(reason: String)
}
// APIManager Class
class ProductDetailsManager {
// THE RIGHT WAY A.K.A. "THE ONE LINE SINGLETON (NOW WITH PROOF!")
static let sharedInstance = ProductDetailsManager()
func printPublicGists(parameter: [String:Any]? , completionHandler: #escaping (Result<[ProductDetailsJSON]>) -> Void) {
let url: String = "http://xxx/wp-api/products/get_product_informations/"
Alamofire.request(url, method: .post, parameters: parameter, encoding: URLEncoding.default, headers: nil)
.responseJSON { (response) in
guard response.result.error == nil else {
print(response.result.error!)
return
}
guard let value = response.result.value else {
print("no string received in response when swapping oauth code for token")
return
}
print(value)
}
}
func fetchPublicGists(parameter: [String:Any]? , completionHandler: #escaping (Result<[ProductDetailsJSON]>) -> Void) {
let url: String = "http://xxx/wp-api/products/get_product_informations/"
Alamofire.request(url, method: .post, parameters: parameter, encoding: URLEncoding.default, headers: nil)
.responseJSON { response in
let result = self.gistArrayFromResponse(response: response)
completionHandler(result)
}
}
// Download Image from URL
func imageFrom(urlString: String, completionHandler: #escaping (UIImage?, Error?) -> Void) {
let _ = Alamofire.request(urlString)
.response { dataResponse in
// use the generic response serializer that returns Data
guard let data = dataResponse.data else {
completionHandler(nil, dataResponse.error)
return
}
let image = UIImage(data: data)
completionHandler(image, nil)
}
}
//gistArrayFromResponse function
private func gistArrayFromResponse(response: DataResponse<Any>) -> Result<[ProductDetailsJSON]> {
// For Network Error
guard response.result.error == nil else {
print(response.result.error!)
return .failure(RueDu8APIManagerError.network(error: response.result.error!))
}
// JSON Serialization Error, make sure we got JSON and it's an array
guard let jsonArray = response.result.value else {
print("did not get array of homeFeed object as JSON from API")
return .failure(RueDu8APIManagerError.objectSerialization(reason: "Did not get JSON dictionary in response"))
}
//turn JSON into gists
//let gistss = jsonArray.flatMap { HomeFeedJSON(items: $0) }
var gists = [ProductDetailsJSON]()
let jsonR = JSON(jsonArray)
let main_content = jsonR["main_content"].array
for item in main_content! {
gists.append(ProductDetailsJSON(items: item))
}
return .success(gists)
}//gistArrayFromResponse() function ends here
}
here is my model class
import Foundation
import SwiftyJSON
class ProductDetailsJSON {
var _product_title: String?
var _description: String?
var _regular_price: String?
var _sale_price: String?
var _product_currency: String?
var _size: String?
var _color: String?
var _image: URL?
init(items: JSON){
self._product_title = items["product_title"].stringValue
self._description = items["description"].stringValue
self._regular_price = items["regular_price"].stringValue
self._sale_price = items["sale_price"].stringValue
self._product_currency = items["product_currency"].stringValue
let sizeData = items["size"].arrayValue
for itemsIMG in sizeData {
self._size = itemsIMG["size_data"].stringValue
}
let colorData = items["color"].arrayValue
for itemsColor in colorData {
self._size = itemsColor["color_data"].stringValue
}
let galleryImg = items["gallery"].arrayValue
for image in galleryImg {
self._image = image["guid"].URL
}
}
var product_title: String {
if _product_title == nil {
_product_title = ""
}
return _product_title!
}
var description: String {
if _description == nil {
_description = ""
}
return _description!
}
var regular_price: String {
if _regular_price == nil {
_regular_price = ""
}
return _regular_price!
}
var sale_price: String {
if _sale_price == nil {
_sale_price = ""
}
return _sale_price!
}
var product_currency: String {
if _product_currency == nil {
_product_currency = ""
}
return _product_currency!
}
var product_color: String {
if _color == nil {
_color = ""
}
return _size!
}
var product_image: URL {
if _image == nil {
let myURL = "http://www.clker.com/cliparts/d/L/P/X/z/i/no-image-icon-hi.png"
let noImage: URL = URL(string: myURL)!
_image = noImage
}
return _image!
}
}
and here is my controller class where I am struggling to show the size , color and gallery items from JSON
import UIKit
import DropDown
import Alamofire
import SwiftyJSON
class ShopItemVC: UIViewController , UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var contentView: UIView!
#IBOutlet weak var selectedProductImg: UIImageView!
#IBOutlet weak var backgroundCardView1: UIView!
#IBOutlet weak var backgroundCardView2: UIView!
#IBOutlet weak var backgroundCardView3: UIView!
#IBOutlet weak var sizeBtn: NiceButton!
#IBOutlet weak var colorBtn: NiceButton!
#IBOutlet weak var productPrice: UILabel!
#IBOutlet weak var productTitle: UILabel!
// var Title = [ProductDetailsJSON]()
var product_id:Int? //got value from SpecificCatagoryVC
var product_detail = [ProductDetailsJSON]()
var reloadData = 0
let sizeDropDown = DropDown()
let colorDropDown = DropDown()
lazy var dropDowns: [DropDown] = {
return [
self.sizeDropDown,
self.colorDropDown
]
}()
let CatagoryPic = ["catagory1","catagory2","catagory3","catagory4","catagory5","catagory6","c atagory7"]
// let CatagoryPicture = [ProductDetailsJSON]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
sizeBtn.layer.borderWidth = 1.2
sizeBtn.layer.borderColor = UIColor.black.cgColor
colorBtn.layer.borderWidth = 1.2
colorBtn.layer.borderColor = UIColor.black.cgColor
backgroundCardView1.backgroundColor = UIColor.white
backgroundCardView1.layer.cornerRadius = 5.0
backgroundCardView1.layer.masksToBounds = false
backgroundCardView1.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
backgroundCardView1.layer.shadowOffset = CGSize(width: 0, height: 0)
backgroundCardView1.layer.shadowOpacity = 0.8
backgroundCardView2.backgroundColor = UIColor.white
backgroundCardView2.layer.cornerRadius = 5.0
backgroundCardView2.layer.masksToBounds = false
backgroundCardView2.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
backgroundCardView2.layer.shadowOffset = CGSize(width: 0, height: 0)
backgroundCardView2.layer.shadowOpacity = 0.8
backgroundCardView3.backgroundColor = UIColor.white
backgroundCardView3.layer.cornerRadius = 5.0
backgroundCardView3.layer.masksToBounds = false
backgroundCardView3.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
backgroundCardView3.layer.shadowOffset = CGSize(width: 0, height: 0)
backgroundCardView3.layer.shadowOpacity = 0.8
setupDropDowns()
}
override func viewDidAppear(_ animated: Bool) {
self.scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height + 40)
loadGists(parameter: ["product_id":product_id ?? 0])
}
func setupDropDowns() {
setupSizeDropDown()
setupColorDropDown()
}
func setupSizeDropDown() {
sizeDropDown.anchorView = sizeBtn
sizeDropDown.bottomOffset = CGPoint(x: 0, y: sizeBtn.bounds.height)
// You can also use localizationKeysDataSource instead. Check the docs.
sizeDropDown.dataSource = [
"XXL",
"XL",
"L",
"M",
"S"
]
// Action triggered on selection
sizeDropDown.selectionAction = { [unowned self] (index, item) in
self.sizeBtn.setTitle(item, for: .normal)
print(item)
}
}
func setupColorDropDown() {
colorDropDown.anchorView = colorBtn
colorDropDown.bottomOffset = CGPoint(x: 0, y: colorBtn.bounds.height)
// You can also use localizationKeysDataSource instead. Check the docs.
colorDropDown.dataSource = [
"Red",
"Blue",
"White",
"Purple",
"Pink"
]
// Action triggered on selection
colorDropDown.selectionAction = { [unowned self] (index, item) in
self.colorBtn.setTitle(item, for: .normal)
print(item)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadGists(parameter: [String:Any]?) {
ProductDetailsManager.sharedInstance.fetchPublicGists(parameter: parameter) {
(result) in
guard result.error == nil else {
self.handleLoadGistsError(result.error!)
return
}
if let fetchedGists = result.value {
self.product_detail = fetchedGists
}
self.reloadData = 1
self.collectionView?.reloadData()
}
}
func handleLoadGistsError(_ error: Error) { }
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return CatagoryPic.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ShopItemCell", for: indexPath) as! ShopItemCell
if reloadData == 1 {
let myProduct = self.product_detail[indexPath.row]
self.productTitle.text = myProduct.product_title
}
cell.shopItemPic.image = UIImage(named: CatagoryPic[(indexPath as NSIndexPath).row])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// here you know which item is selected by accessing indexPath.item property, for example:
let selectedImage = UIImage(named: CatagoryPic[(indexPath as NSIndexPath).item])
selectedProductImg.image = selectedImage
}
#IBAction func sizeBtnPressed(_ sender: Any) {
sizeDropDown.show()
//print("size btn pressed")
}
#IBAction func colorBtnPressed(_ sender: Any) {
colorDropDown.show()
}
#IBAction func backBtn(_ sender: AnyObject) {
self.dismiss(animated: true, completion: nil)
}
}
There are some other class where I am facing the same issue. Hope If I get this solution I will be able to solve those. Thanks in advance .
First thing to note is that you are returning the size value and not color in the product_color variable.
Also when you loop through the arrays in your JSON, you're setting the variable to only be the final value. For example here:
let sizeData = items["size"].arrayValue
for itemsIMG in sizeData {
self._size = itemsIMG["size_data"].stringValue
}
The JSON is
"size": [
{
"size_data": "L"
},
{
"size_data": "S"
}
]
So _size is going to be set as "S" and "L" will never be assigned. I'd suggest changing _size, _color and _image to
var _sizes: [String] = []
var _colors: [String] = []
var _images: [String] = []
And then when looping through the JSON array:
let sizeData = items["size"].arrayValue
for itemsIMG in sizeData {
let size = itemsIMG["size_data"].stringValue
_sizes.append(size)
}
If I'm understanding correctly, you then want to update your dropdown data when you get the response with the gist.
sizeDropDown.dataSource = product_detail.product_sizes
Then the same for the other drop downs.
And create product_sizes, product_colors and product_images variables in the model similar sale_price and regular_price.