How to reflect select result of UISegmentedControl in Firebase'S Database - swift

Hello I'm newbie in programming (Swift/Firebase) and developing application. Now is trying to make a user profile to be connected to database. I could do it for TextFields data, but cannot do the same with UISegmentedControl for Male/Female switch.
#IBAction func saveProfileButton(_ sender: Any) {
if nameTextField.text! == "" {
print("enter something")
} else {
addUser()
}
}
#objc func valuChange() {
switch genderSegControl.selectedSegmentIndex {
case 0:
let zero = String("Male")
case 1:
let one = String("Female")
default:
return
}
}
func addUser() {
let genderChanged = genderSegControl?.addTarget(self, action: #selector(MainViewController.valuChange), for: UIControlEvents.valueChanged)
let userGender = String(describing: genderChanged!)
let uidUser = Auth.auth().currentUser?.uid
let user = ["...": ..., "userGender": userGender as! String]
refUsers.child(uidUser!).setValue(user)
}
but when I check Firebase's Database nodes it shows "userGender: Optional(())" and only. I tried in many different ways but couldn't get it to be shown like "userGender: Male" or "userGender: Female".
Would appreciate any advice.

Create outlet for UISegementControl in your ViewController, say genderControl.
In addUser() function, use the selectedIndex of the UISegementControl to determine the value as follows, say index 0 is for MALE & 1 is for FEMALE then:
let gender = genderControl.selectedIndex == 0 ? "Male" : "Female"
Now set this value gender in user dictionary, i.e.
let user = ["...": ..., "userGender": gender]

Related

How to set UISwitch state when receiving data from API

I have a screen with Two UISwitch buttons.
I am receiving a data in API:
"CustomerSubscribed": [
{
"Customer_ID": "100132",
"Mobile": "3213103428",
"Subscription": "Bill Payment",
"Mnemonic": "BILL",
"IsActive": 0
},
{
"Customer_ID": "100132",
"Mobile": "3213103428",
"Subscription": "Funds Transfer",
"Mnemonic": "IBFT",
"IsActive": 1
}
]
These are my two switches:
private var fundSwitch: UISwitch = {
let switchView = UISwitch()
switchView.isOn = false
switchView.onImage = UIImage(named: "switchOn")
switchView.offImage = UIImage(named: "switchOff")
switchView.onTintColor = UIColor.purple
switchView.tag = 1
switchView.addTarget(self, action: #selector(switchStateDidChange), for: .valueChanged)
switchView.translatesAutoresizingMaskIntoConstraints = false
return switchView
}()
private var billSwitch: UISwitch = {
let switchView = UISwitch()
switchView.isOn = false
switchView.onImage = UIImage(named: "switchOn")
switchView.offImage = UIImage(named: "switchOff")
switchView.onTintColor = UIColor.purple
switchView.tag = 2
switchView.addTarget(self, action: #selector(switchStateDidChange), for: .valueChanged)
switchView.translatesAutoresizingMaskIntoConstraints = false
return switchView
}()
On the basis of isActive, I have to set the values of UISWitch. If it is true, then switch must be on, otherwise if it is false then it must be Off.
This is what im trying right now:
#objc func switchStateDidChange(_ sender: UISwitch) {
if sender.tag == Switch.fundTrasnfer.rawValue {
print( sender.isOn ? customerSubscribe?[0].isActive ?? false: "Fund Transfer Switch is Off" )
} else {
print( sender.isOn ? customerSubscribe?[1].isActive ?? false: "Bill Payment Fund Transfer Switch is Off" )
}
}
and another what I tried:
#objc func switchStateDidChange(_ sender: UISwitch) {
for customer in self.customerSubscribe! {
if customer.isActive == true {
print(sender.isOn ? "Switch is ON": "Switch is Off")
} else {
print(sender.isOn ? "Switch is ON": "Switch is Off")
}
}
}
these are two approaches I have tried. I am using VIP Architecture, and I received response here:
extension SubscriptionViewController: SubscribeViewProtocol {
func saveSuccessCustomerData(response: CustomerSubscribeEntity.CustomerServiceResponse) {
}
func successSetupSubscription(response: SubscriptionEntity.SubscriptionServicesResponse) {
DispatchQueue.main.async {
print("Id \(response.customerSubscribed?[0].customerID)")
self.customerSubscribe = response.customerSubscribed
self.fundTransferLbl.text = self.customerSubscribe?[0].subscription
self.billPaymentLbl.text = self.customerSubscribe?[1].subscription
}
}
}
Then I created customerSubscribe to have the response in it:
var customerSubscribe: [SubscriptionEntity.CustomerSubscribed]?
My screen:
UI Is is programmatically, and i have both fund and bill switch defined.
Can I make a loop and check too instead of comparing taking index?
You are still hiding a lot of implementation detail that would be neccassary to give a definitive answer. So I have to make some assumptions.
isActive is of type boolean
successSetupSubscription lives in the same place as your switch vars
you create your switches programaticly and add them to your view.
Your function switchStateDidChange will react to changes done by the user. If you want to change the state of the switch programmaticly you need to set it to the switch itself.
func successSetupSubscription(response: SubscriptionEntity.SubscriptionServicesResponse) {
DispatchQueue.main.async {
print("Id \(response.customerSubscribed?[0].customerID)")
self.customerSubscribe = response.customerSubscribed
self.fundTransferLbl.text = self.customerSubscribe?[0].subscription
self.billPaymentLbl.text = self.customerSubscribe?[1].subscription
//add this
self.fundSwitch.isOn = response.customerSubscribed[0].isActive
self.billSwitch.isOn = response.customerSubscribed[1].isActive
}
}
You can try
switchOne.isOn = customerSubscribe?.first?.isActive == 1
switchTwo.isOn = customerSubscribe?.last?.isActive == 1

Locking buttons until next day

Is there anyway to lock buttons until the following day? For example, my app has coupons in the form of buttons and when you click the button "Coupon 1" it toggles to say "USED + the current date". I want the user to be able to only use 2 coupons per ViewController/page per dag, and am wondering if its possible to lock the other coupons once two are pressed by the user, and the coupons unlock the following day. I don't want the buttons to disappear, just want them to be locked. Below is the code for one of my buttons/coupons. It would be ideal if a lock actually appeared in the corner of the remaining buttons after 2 are pressed.
var didClick : Bool = false
#IBAction func special1BTNpressed(_ sender: UIButton) {
if !didClick {
didClick = true
let date = Date()
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"
let result = formatter.string(from: date)
sender.setTitle("USED " + result, for: .normal)
You can store the value of the date of which you did the action and then later compare it with today
func canPerformActionForSpecialBTN() -> Bool {
let timeInterval = UserDefaults.standard.double(forKey: "ActionDateForSpecialBTN")
guard timeInterval.isNormal else { return true }
let date = Date(timeIntervalSince1970: timeInterval)
guard Calendar.current.isDateInToday(date) else { return true }
return false
}
func performSpecialBTNAction() {
guard canPerformActionForSpecialBTN() else { return }
defer { UserDefaults.standard.set(Date().timeIntervalSince1970, forKey: "ActionDateForSpecialBTN") }
//implement action here
}
and maybe in the viewDidAppear you can enable or disable the button
button.isEnabled = !canPerformActionForSpecialBTN()

Segue to certain ViewController with correct information in UITextField SWIFT

I have already implemented an UITextField that segues to two different ViewControllers based on information inserted into the UITextField if the information entered matches my array {bdArray} then when my button (bedButton) is pressed the view controller segues to viewControllerA if it does not match the correct information in my bdArray it segues to viewControllerB. My problem is i want to allow Segue to ViewControllerA if the first word or one off the words in the UITextField matches my bdArray, then segue to viewControllerA will happen. How will i implement this method?
#IBAction func bYo(sender: AnyObject) {
let pText = pTextField.text?.uppercaseString ?? ""
let pDestination = activeP.map { $0.uppercaseString }.contains(pText) ? "mM" : "nDy"
performSegueWithIdentifier(pDestination, sender: sender) }
this is my code i have already for making the text in the UItextField not case sensitive, which is needed. Any way to add any code to do the part search?
First you need to split the textField's text into an array of String, then check if bdArray contains one or more elements in the String array.
let numOfMatches = textField.text?.characters.split { $0 == " " }.filter { bdArray.contains(String($0)) }.count
if numOfMatches > 0 {
// segue to view controller A
} else {
// segue to view controller B
}
According to the code you posted, you might want to rewrite it like so:
#IBAction func bYo(sender: AnyObject) {
let pText = pTextField.text?.uppercaseString ?? ""
activeP = activeP.map { $0.uppercaseString }
let pTextArray = pText.characters.split { $0 == " " }
var numOfMatches = 0
var pDestination = ""
if pTextArray.count == 1 {
numOfMatches = activeP.filter { pText.containsString($0) }.count
} else {
numOfMatches = pTextArray.filter { activeP.contains(String($0)) }.count
}
numOfMatches > 0 ? (pDestination = "mM") : (pDestination = "nDy")
performSegueWithIdentifier(pDestination, sender: sender)
}

Can't see the messages I'm posting in Parse

I'm creating a yik yak clone and I can't seem to see the messages I post in the textField(string) on Parse. Is there something wrong I'm doing in my code that's not letting it show up on Parse?
#IBAction func postPressed(sender: AnyObject) {
if(currLocation != nil){
let testObj = PFObject(className: "BubbleTest")
testObj["userName"] = PFUser.currentUser()?.username
//testObj["profileName"] = PFUser.valueForKey("profileName") as! String
//testObj["photo"] = PFUser.currentUser()?.valueForKey("photo") as! PFFile
testObj["textField"] = self.textField.text
testObj["location"] = PFGeoPoint(latitude: currLocation!.latitude , longitude: currLocation!.longitude)
testObj["count"] = 0
testObj["replies"] = 0
testObj.saveInBackground()
self.dismissViewControllerAnimated(true, completion: nil)
}
else {
alert()
}
The reason you are not seeing anything because you post it into the wrong class. According to the picture BubbleTest is the name of the class not YikYakTest
replace this line
let testObj = PFObject(className: "YikYakTest")
by
let testObj = PFObject(className: "BubbleTest")
your code should look like :
Note use saveInBackgroundWithBlock method so you could check if there is an error while saving
let testObj = PFObject(className: "BubbleTest")
let username = PFUser.currentUser()?.username
testObj["userName"] = username
testObj["textField"] = self.textField.text
testObj["Location"] = PFGeoPoint(latitude:currLocation.latitude , longitude: currLocation.longitude)
testObj["count"] = 0
testObj["replies"] = 0
testObj.saveInBackgroundWithBlock { (success:Bool, error :NSError?) -> Void in
if error == nil
{
print("detail is saved")
self.dismissViewControllerAnimated(true, completion: nil)
}
else
{
print("error")
}
}
when you are saving PFGeopoint coordinates save it into Location column not location
I know many developer friends of mine who ran into a similar issue. I myself had this problem as well, now resolved. So hopefully I can provide some insight from what I learned querying data from Parse:
Try changing the numberOfSectionsInTableView method to return 1 instead of 0 like so:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
You may need to also have some data structure to hold the users' posts (messages):
var userPosts:NSMutableArray! = NSMutableArray()
Also, your table view could then have as many rows as you will have posts stored in userPosts:
override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
return userPosts.count
}
In cellForRowAtIndexPath, replace this:
let object = PFObject(className: "BubbleTest")
WITH THIS:
let userPost : PFObject = self.posts.objectAtIndex(indexPath!.row) as! PFObject
...
cell.message.text = userPost.objectForKey("message") as! String
return cell
}
This will set the text of your custom cell's message property to whatever the user's message is (i.e.: "Testing 1 2").
Note: These steps aren't intended to be the only steps needed to solve your problem. It is meant to guide you in the right direction with some basic steps.
Hope that helps! :)

swift - Populate STPPaymentCardTextField Programmatically

I'm developing an app and using Stripe SDK and Card.io SDK. What i want to happen is populate the STPPaymentCardTextField Card Number,Expiry Month and Year with Card.io scanned credit card value. I Tried:
var paymentField = STPPaymentCardTextField()
func userDidProvideCreditCardInfo(cardInfo: CardIOCreditCardInfo!, inPaymentViewController paymentViewController: CardIOPaymentViewController!) {
var scanViewController: CardIOPaymentViewController = CardIOPaymentViewController(paymentDelegate: self)
paymentField.cardNumber = cardInfo.cardNumber
paymentField.expirationMonth = cardInfo.expiryMonth
paymentField.expirationYear = cardInfo.expiryYear
paymentViewController.dismissViewControllerAnimated(true, completion: nil)
}
I'm having an error Cannot assign to the result of this expression for each paymentField append.
What do you think i can do with this? Thanks!
STPPaymentCardTextField fields are read-only and you can only "get" from those properties.
STPPaymentCardTextField is used to collect credit card details. In your case you are already doing that using CardIOCreditCardInfo. Once you have the credit card details you can assemble the data into an STPCardParams object.
Once you've collected the card number, expiration, and CVC, package them up in an STPCardParams object and invoke the createTokenWithCard: method on the STPAPIClient class.
Now your method may look like this...
func userDidProvideCreditCardInfo(cardInfo: CardIOCreditCardInfo!, inPaymentViewController paymentViewController: CardIOPaymentViewController!) {
let card: STPCardParams = STPCardParams()
card.number = info.cardNumber
card.expMonth = info.expiryMonth
card.expYear = info.expiryYear
card.cvc = info.cvv
STPAPIClient.sharedClient().createTokenWithCard(card, completion: {(result, error) -> Void in
if error == nil {
// Either save the card token with your customer data or charge them right away
//createBackendChargeWithToken(token)
}
else {
//handleError(error)
}
})
}
paymentViewController?.dismissViewControllerAnimated(true, completion: nil)
}
Update May be the right answer to your question.
import Stripe
class PaymentCardEditorField: STPPaymentCardTextField {
func setExistingCard(card: STPCardParams) {
replaceField("numberField", withValue: card.number!)
replaceField("expirationField", withValue: String(format: "%02d/%02d", card.expMonth, (card.expYear % 100)))
replaceField("cvcField", withValue: card.cvc!)
}
func replaceField(memberName: String, withValue value: String) {
let field = self.valueForKey(memberName) as! UITextField
let delegate = self as! UITextFieldDelegate
let len = field.text?.characters.count
if delegate.textField?(field, shouldChangeCharactersInRange: NSMakeRange(0, len!), replacementString: value) ?? false {
field.text = value
}
}
}
And then call the setExistingCard
func userDidProvideCreditCardInfo(cardInfo: CardIOCreditCardInfo!, inPaymentViewController paymentViewController: CardIOPaymentViewController!) {
let card: STPCardParams = STPCardParams()
card.number = info.cardNumber
card.expMonth = info.expiryMonth
card.expYear = info.expiryYear
card.cvc = info.cvv
paymentTextField.setExistingCard(card)
}
Works like a charm.
Follow this thread for potential update to Stripe SDK for in built support in the future.
https://github.com/stripe/stripe-ios/issues/127
I got a much cleaner answer from here
let cardParams = STPCardParams()
cardParams.number = "4242424242424242"
cardParams.expMonth = 07 // this data type is UInt and *not* Int
cardParams.expYear = 19 // this data type is UInt and *not* Int
cardParams.cvc = "123"
let paymentField = STPPaymentCardTextField()
paymentField.cardParams = cardParams //the paymentTextField will now show the cc #, exp, and cvc from above
You can get other test cards numbers like Mastercard, Amex, and Discover from here from Stripe