swift - Populate STPPaymentCardTextField Programmatically - swift

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

Related

NSTouchBar integration not calling

I am integrating TouchBar support to my App. I used the how to from Rey Wenderlich and implemented everything as follows:
If self.touchBarArraygot filled the makeTouchBar() Method returns the NSTouchBar object. If I print out some tests the identifiers object is filled and works.
What not work is that the makeItemForIdentifier method not get triggered. So the items do not get created and the TouchBar is still empty.
Strange behavior: If I add print(touchBar) and a Breakpoint before returning the NSTouchBar object it works and the TouchBar get presented as it should (also the makeItemForIdentifier function gets triggered). Even if it disappears after some seconds... also strange.
#available(OSX 10.12.2, *)
extension ViewController: NSTouchBarDelegate {
override func makeTouchBar() -> NSTouchBar? {
if(self.touchBarArray.count != 0) {
let touchBar = NSTouchBar()
touchBar.delegate = self
touchBar.customizationIdentifier = NSTouchBarCustomizationIdentifier("com.TaskControl.ViewController.WorkspaceBar")
var identifiers: [NSTouchBarItemIdentifier] = []
for (workspaceId, _) in self.touchBarArray {
identifiers.append(NSTouchBarItemIdentifier("com.TaskControl.ViewController.WorkspaceBar.\(workspaceId)"))
}
touchBar.defaultItemIdentifiers = identifiers
touchBar.customizationAllowedItemIdentifiers = identifiers
return touchBar
}
return nil
}
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItemIdentifier) -> NSTouchBarItem? {
if(self.touchBarArray.count != 0) {
for (workspaceId, data) in self.touchBarArray {
if(identifier == NSTouchBarItemIdentifier("com.TaskControl.ViewController.WorkspaceBar.\(workspaceId)")) {
let saveItem = NSCustomTouchBarItem(identifier: identifier)
let button = NSButton(title: data["name"] as! String, target: self, action: #selector(self.touchBarPressed))
button.bezelColor = NSColor(red:0.35, green:0.61, blue:0.35, alpha:1.00)
saveItem.view = button
return saveItem
}
}
}
return nil
}
}
self.view.window?.makeFirstResponder(self) in viewDidLoad() did solve the problem.

Swift Pusher example doing nothing

I am using the starter code Pusher provides, when I put it into a basic swift project and I send it a message nothing happens. I have the cocoa pod package installed as well.
The statement "data received" should print.
There are also no errors.
Are you initialising the Pusher object as a var? You need to maintain a strong reference to the object otherwise it can become deallocated.
As an example it should be something like:
class ViewController: UIViewController {
var pusher: Pusher!
override func viewDidLoad() {
super.viewDidLoad()
let options = PusherClientOptions(
host: .cluster("mycluster")
)
pusher = Pusher(
key: "app_key",
options: options
)
// subscribe to channel and bind to event
let channel = pusher.subscribe("my-channel")
let _ = channel.bind(eventName: "my-event", callback: { (data: Any?) -> Void in
if let data = data as? [String : AnyObject] {
if let message = data["message"] as? String {
print(message)
}
}
})
pusher.connect()
}
}

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! :)

How can I use ASTextNode with TTTAttributedLabel

I have built a ASCellNode and it works perfectly. However when I used a traditional UICollectionViewCell I used an TTTAttributedLabel with links.
I don't know how should I replicate this with AsyncDisplayKit
I can assign the attriubtedText from the TTTAttributedLabel to an ASTextNode but of course it doesn't keep the links. How could I efficiently do this. Bellow the example of my ASCellNode.
protocol EmailSentDelegator : class {
func callSegueFromCell(data object: JSON)
}
class EmailCellNode: ASCellNode, TTTAttributedLabelDelegate {
let cardHeaderNode: ASTextNode
var frameSetOrNil: FrameSet?
init(mailData: JSON) {
// Create Nodes
cardHeaderNode = ASTextNode()
super.init()
// Set Up Nodes
cardHeaderNode.attributedString = createAttributedLabel(mailData, self).attributedText
// Build Hierarchy
addSubnode(cardHeaderNode)
}
override func calculateSizeThatFits(constrainedSize: CGSize) -> CGSize {
var cardSize = CGSizeZero
cardSize.width = UIScreen.mainScreen().bounds.size.width - 16
// Measure subnodes
let cardheaderSize = cardHeaderNode.measure(CGSizeMake(cardSize.width - 56, constrainedSize.height))
cardSize.height = max(cardheaderSize.height,40) + subjectLabelSize.height + timeStampSize.height + emailAbstractSize.height + 30
// Calculate frames
frameSetOrNil = FrameSet(node: self, calculatedSize: cardSize)
return cardSize
}
override func layout() {
if let frames = frameSetOrNil {
cardHeaderNode.frame = frames.cardHeaderFrame
}
}
func attributedLabel(label: TTTAttributedLabel!, didSelectLinkWithTransitInformation components: [NSObject : AnyObject]!) {
self.delegate.callSegueFromCell(data: mailData)
}
func createAttributedLabel(mailData: JSON, cell: EmailCellNode) -> TTTAttributedLabel{
let senderName = mailData["From"]["Name"].string!
var recipients:[String] = []
for (key: String, subJson: JSON) in mailData["To"] {
if let recipientName = subJson["Name"].string {
recipients.append(recipientName)
}
}
var cardHeader = TTTAttributedLabel()
cardHeader.setText("")
cardHeader.delegate = cell
cardHeader.userInteractionEnabled = true
// Add sender to attributed string and save range
var attString = NSMutableAttributedString(string: "\(senderName) to")
let senderDictionary:[String:String] = ["sender": senderName]
let rangeSender : NSRange = (attString.string as NSString).rangeOfString(senderName)
// Check if recipients is nil and add undisclosed recipients
if recipients.count == 0 {
attString.appendAttributedString(NSAttributedString(string: " undisclosed recipients"))
let rangeUndisclosed : NSRange = (attString.string as NSString).rangeOfString("undisclosed recipients")
attString.addAttribute(NSFontAttributeName, value: UIFont(name: "SourceSansPro-Semibold", size: 14)!, range: rangeUndisclosed)
attString.addAttribute(NSForegroundColorAttributeName, value: UIColor.grayColor(), range: rangeUndisclosed)
} else {
// Add recipients (first 5) to attributed string and save ranges for each
var index = 0
for recipient in recipients {
if (index == 0) {
attString.appendAttributedString(NSAttributedString(string: " \(recipient)"))
} else if (index == 5){
attString.appendAttributedString(NSAttributedString(string: ", and \(recipients.count - index) other"))
break
} else {
attString.appendAttributedString(NSAttributedString(string: ", \(recipient)"))
}
index = index + 1
}
}
cardHeader.attributedText = attString
// Adding recipients and sender links with recipient object to TTTAttributedLabel
cardHeader.addLinkToTransitInformation(senderDictionary, withRange: rangeSender)
if recipients.count != 0 {
var index = 0
var position = senderName.length + 2
for recipient in recipients {
let recipientDictionary:[String: AnyObject] = ["recipient": recipient,"index": index ]
let rangeRecipient : NSRange = (attString.string as NSString).rangeOfString(recipient, options: nil, range: NSMakeRange(position, attString.length-position))
cardHeader.addLinkToTransitInformation(recipientDictionary, withRange: rangeRecipient)
index = index + 1
if (index == 5) {
let recipientsDictionary:[String: AnyObject] = ["recipients": recipients]
let rangeRecipients : NSRange = (attString.string as NSString).rangeOfString("and \(recipients.count - index) other")
cardHeader.addLinkToTransitInformation(recipientsDictionary, withRange: rangeRecipients)
}
position = position + rangeRecipient.length
}
}
return cardHeader
}
}
extension EmailCellNode {
class FrameSet {
let cardHeaderFrame: CGRect
init(node: EmailCellNode, calculatedSize: CGSize) {
var calculatedcardHeaderFrame = CGRect(origin: CGPointMake(senderPhotoFrame.maxX + 8, senderPhotoFrame.minY) , size: node.cardHeaderNode.calculatedSize)
cardHeaderFrame = calculatedcardHeaderFrame.integerRect.integerRect
}
}
}
I am not familiar with AsyncDisplayKit, but there are some issues with your use of TTTAttributedLabel:
You are initializing the label with TTTAttributedLabel(), which calls init. You must instead use the designated initializers initWithFrame: or initWithCoder:, as init will not properly initialize the links array and various other internal properties. In the latest release of TTTAttributedLabel, init is marked as unavailable.
You are assigning to the attributedText property. Please see this note in TTTAttributedLabel.h:
#bug Setting attributedText directly is not recommended, as it may cause a crash when attempting to access any links previously set. Instead, call setText:, passing an NSAttributedString.
You should never assign to the attributedText property.
I ended up using solely ASTextNode it doesn't have as many features at TTTAttributedLabel but enough for my need. Further more since it's a heavy ASCollectionView it was better to go fully Async. Bellow the an exemple of how I did this in a ASCellNode with the creation of the complexe ASTextNode.
here is the final result with clickable name passing JSON data through a segue.
here is a simplified version of building the NSAttributedString
func createAttributedLabel(mailData: JSON) -> NSAttributedString{
var recipients:[String] = []
for (key: String, subJson: JSON) in mailData["To"] {
if let recipientName = subJson["Name"].string {
recipients.append(recipientName)
}
}
// Add recipients to attributed string and save ranges for each
var index = 0
var position = senderName.length + 2
for recipient in recipients {
let recipientDictionary:[String: AnyObject] = ["recipient": recipient,"index": index ]
let recipientJSON = mailData["To"][index]
attString.appendAttributedString(NSAttributedString(string: ", \(recipient)"))
let rangeRecipient : NSRange = (attString.string as NSString).rangeOfString(recipient, options: nil, range: NSMakeRange(position, attString.length-position))
attString.addAttributes([
kLinkAttributeName: recipientJSON.rawValue,
NSForegroundColorAttributeName: UIColor.blackColor(),
NSFontAttributeName: UIFont(name: "SourceSansPro-Semibold", size: 14)!,
NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleNone.rawValue],
range: rangeRecipient)
}
index = index + 1
return attString
}
end then to detect link taps. I had to transform my JSON in raw value to pass the data across.
func textNode(textNode: ASTextNode!, tappedLinkAttribute attribute: String!, value: AnyObject!, atPoint point: CGPoint, textRange: NSRange) {
// The node tapped a link; open it if it's a valid URL
if (value.isKindOfClass(NSDictionary)) {
var jsonTransferred = JSON(rawValue: value as! NSDictionary)
self.delegate.callSegueFromCellUser(data: jsonTransferred!)
} else {
var jsonTransferred = JSON(rawValue: value as! NSArray)
self.delegate.callSegueFromCellRecipients(data: jsonTransferred!)
}
}
I'm one of the primary maintainers of ASDK, and would love to help you address any challenges — feel free to open a GitHub issue on the project (even just for questions).
What features is ASTextNode lacking that you love about TTT? It does handle links, complete with centroid-based tap disambiguation between multiple, disjoint & line-wrapping links. There are probably missing features, but since the project is so widely used, I bet other developers would find it useful to add any that you find a need for.
That said, if you don't need the significant performance gains that come with moving text layout and rendering off the main thread, you can wrap TTT in an initWithViewBlock — or simply create & add the view directly, without node wrapping, inside of any node's -didLoad method. Normally with ASDK, wrapping views is not required (which is why I asked about ASTextNode).
Good luck with your work!

Swift IAP localized price

I am trying to add localised prices via labels to my shop section of my game. I am struggling to get it to work.
This is 1 part of the code for the purchase bit, its pretty standard.
I have an enum for all my product identifiers.
enum ProductID: String {
case product1
case product2
}
and the standard payment code.
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
println("add payment")
for transaction in transactions {
switch transaction.transactionState {
case .purchased:
print("buy, ok unlock iap here")
print(p.productIdentifier)
let productIdentifier = transaction.payment.productIdentifier
switch productIdentifier {
case ProductID.product1.rawValue:
print("Product 1 bought")
//do something
case ProductID.product2.rawValue:
print("Product 2 bought")
//do something
default:
print("IAP not setup")
}
}
I use the following extension for fetching the localized price, again pretty boiler plate
extension SKProduct {
var localizedPrice: String {
let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.locale = self.priceLocale
return formatter.stringFromNumber(self.price) ?? "\(price)"
}
}
So in my price labels that are underneath product buttons how do i got about adding each products localised price
priceProduct1Label.text = "\(?.localizedPrice)"
priceProduct2Label.text = "\(?.localizedPrice)"
What do I type for the question marks basically?. The videos and tutorial I read either don't tell you or they don't use a switch statement for the products.
Thank you very much in advance for any replies
I offer a slight variation on crashoverride777's answer above for, rather than a label, a button, and to draw not only the localized price from iTunes Connect but also the other content - the localizedTitle - that makes up the button title:
func loadBuy00ButtonTitle() {
for product in productArray {
let prodID = product.productIdentifier
if(prodID == "com.YourCompanyNameGoesHere.YourAppNameGoesHere.buy00Button") {
let prod = product
buy00Button.setTitle("Buy \(prod.localizedTitle): \(prod.localizedPrice())", for: .normal)
}
}
}
I'm in the USA and thus my button title reads something like: "Buy 100 coins: $0.99" - where for that product (purchase) "100 coins" is the localized title and "$0.99" is the localized price.
And again with minor variations, I, too, use the same extension he provides (in his question), which I place in a separate Swift file:
import StoreKit
extension SKProduct {
func localizedPrice() -> String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = self.priceLocale
return formatter.string(from: self.price)!
}
}
Ben Dodson's SKProduct localized price extension in Swift
I figured it out finally. I basically took the same code that is used to identify a product when one of the buy buttons is pressed. I just replaced the line that loads the buyProduct() function with the label details. Such as this example of one of my price labels.
func loadPriceLabel1() {
for product in products where product.productIdentifier == ProductID.product1.rawValue {
self.titleLabel.text = "\(product.localizedTitle)"
self.priceLabel1.text = "\(product.localizedPrice)"
etc
}
}
I load the label functions after the product request is finished, right after the buy buttons become enabled. Probably a solution slightly on the clunky side but it works great. If anyone has any suggestions for improvements please let me know.
You are looking for an instance of SKProduct, of which you can load using one or more product identifiers through an SKProductsRequest:
import StoreKit
class MyStore: NSObject, SKProductsRequestDelegate {
func loadProductsForProductIdentifiers( productIdentifiers: Set<String ) {
let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers )
productRequest.delegate = self ///< Make sure to set a delegate
productRequest.start()
}
// MARK: - SKProductsRequestDelegate
func productsRequest(request: SKProductsRequest!, didReceiveResponse response: SKProductsResponse!) {
for object in response.products {
if let product = object as? SKProduct {
// Store these products and use their `productIdentifier` property to identify them
}
}
}
}