Setting DarkTheme has no effect Braintree iOS v4 SDK - swift

The documentation clearly says it can be done, easy breezy:
https://developers.braintreepayments.com/guides/drop-in/customization/ios/v4#themes
I can indeed customize the primaryTextColor to red.
Here is a screenshot, that demonstrates that red works but not darkTheme:
And is here is my code in my UIViewController:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
showDropIn(clientTokenOrTokenizationKey: clientToken)
}
func showDropIn(clientTokenOrTokenizationKey: String) {
BTUIKAppearance.darkTheme()
BTUIKAppearance.sharedInstance().primaryTextColor = UIColor.red
let request = BTDropInRequest()
request.vaultManager = true
let dropIn = BTDropInController(authorization: clientTokenOrTokenizationKey, request: request)
{ (controller, result, error) in
if (error != nil) {
print("ERROR")
} else if (result?.isCancelled == true) {
print("CANCELLED")
} else if let result = result {
// Use the BTDropInResult properties to update your UI
// result.paymentOptionType
// result.paymentMethod
// result.paymentIcon
// result.paymentDescription
}
controller.dismiss(animated: true, completion: nil)
}
self.present(dropIn!, animated: true, completion: nil)
}

So Braintree's documentation on Theme's is a bit poorly choose wording IMO.
The instruction is what is misleading to me: "To use the Dark theme instead, call this method before initializing Drop-in". Yet you have to initialize or instantiate the drop-in before setting darkTheme.
The instruction might better read: "To use the Dark theme instead, call this method before presenting the Drop-in"
Here is my working code:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
showDropIn(clientTokenOrTokenizationKey: clientToken)
}
func showDropIn(clientTokenOrTokenizationKey: String) {
let request = BTDropInRequest()
request.vaultManager = true
dropIn = BTDropInController(authorization: clientTokenOrTokenizationKey, request: request)
{ (controller, result, error) in
if (error != nil) {
print("ERROR")
} else if (result?.isCancelled == true) {
print("CANCELLED")
} else if let result = result {
// Use the BTDropInResult properties to update your UI
// result.paymentOptionType
// result.paymentMethod
// result.paymentIcon
// result.paymentDescription
}
controller.dismiss(animated: true, completion: nil)
}
BTUIKAppearance.darkTheme()
BTUIKAppearance.sharedInstance()?.primaryTextColor = UIColor.lightGray
self.present(dropIn!, animated: true, completion: nil)
}

Related

Siri Intent Suggested Invocation Phrase not displaying in ShortcutViewController

I'm trying to enable a simple Siri Intent for my iOS app, with a TableView cell functioning to invoke INUIAddVoiceShortcutViewController, with the TableView as its delegate. However, the suggested invocation phrase that is supposed to display on the controller view, does not.
I'm extremely new to Swift, and so I haven't tried much else as I do not know what to try
The invoking function is:
getSiriView() {
intent.suggestedInvocationPhrase = "Get a joke"
let siriView = INUIAddVoiceShortcutViewController(shortcut: INShortcut(intent: intent)!)
siriView.delegate = self;
self.present(siriView, animated: true, completion: nil)
}
and its delegate extensions are as follows:
//
// ViewControllerSiriExtensions.swift
// Helium
//
// Created by Richard Robinson on 2019-04-26.
// Copyright © 2019 Richard Robinson. All rights reserved.
//
import Foundation
import IntentsUI
extension TableViewController: INUIAddVoiceShortcutButtonDelegate {
func present(_ addVoiceShortcutViewController: INUIAddVoiceShortcutViewController, for addVoiceShortcutButton: INUIAddVoiceShortcutButton) {
addVoiceShortcutViewController.delegate = self
addVoiceShortcutViewController.modalPresentationStyle = .formSheet
present(addVoiceShortcutViewController, animated: true, completion: nil)
}
func present(_ editVoiceShortcutViewController: INUIEditVoiceShortcutViewController, for addVoiceShortcutButton: INUIAddVoiceShortcutButton) {
editVoiceShortcutViewController.delegate = self
editVoiceShortcutViewController.modalPresentationStyle = .formSheet
present(editVoiceShortcutViewController, animated: true, completion: nil)
}
}
extension TableViewController: INUIAddVoiceShortcutViewControllerDelegate {
public func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
public func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) {
controller.dismiss(animated: true, completion: nil)
}
}
extension TableViewController: INUIEditVoiceShortcutViewControllerDelegate {
public func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didUpdate voiceShortcut: INVoiceShortcut?, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
public func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didDeleteVoiceShortcutWithIdentifier deletedVoiceShortcutIdentifier: UUID) {
controller.dismiss(animated: true, completion: nil)
}
public func editVoiceShortcutViewControllerDidCancel(_ controller: INUIEditVoiceShortcutViewController) {
controller.dismiss(animated: true, completion: nil)
}
}
extension TableViewController {
public var intent: JokeIntent {
return JokeIntent()
}
}
Currently, the controller appears and works properly, except it does not display the suggested phrase.

Dismiss alert after task on MainViewController swift

I need to download some content from API when users login for the first time at my app and show them I'm doing that. I do this at my MainViewController:
override func viewDidAppear(_ animated: Bool) {
let alert = UIAlertController(title: nil, message: "Wait please...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.style = UIActivityIndicatorView.Style.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: true, completion: nil)
let parceiroId = self.defaults.getParceiroId()
if !self.defaults.getDownloadInicialTipoEntrega() {
TipoEntregaAPI().loadTiposEntrega(parceiroId){ (dados) in
if dados != nil {
for tipoEntrega in dados!{
// Do some stuff, no errors
}
}
}
}
if !self.defaults.getDownloadInicialPedido() {
PedidoAPI().loadOrders(parceiroId){ (dados) in
if dados != nil {
for pedidos in dados!{
// Do some stuff, no errors
}
}
}
}
self.dismiss(animated: false, completion: { () in print("Done") })
}
The problem is that my alert with the loading never gets dismissed. It never prints "Done". Can anyone help me please?
I dont know if it is useful, but I always get this warning:
Warning: Attempt to dismiss from view controller <MyApp.MainViewController: 0x0000000> while a presentation or dismiss is in progress!
The problem is exactly what the error says. Your presentation call isn't completed at the moment you're calling self.dismiss(...). For further explanation, you're calling present(alert, animated: true, completion: nil) with animated: true parameter so it's not going to finish the presentation instantly. On the other hand, you are calling self.dismiss(animated: false, completion: { () in print("Done") }) on the same thread in the relatively short instruction block, so it gets executed before the iOS finishes the animated presentation of the dialog and that's why you get the error.
But furthermore, before actually fixing the issue you should ask yourself do you really want to dismiss the dialog as soon as it's presented. Judging from the code you posted, I'd assume you want it to be dismissed after either or both of the API calls are finished. If that's the case you need to move the dismiss method call within the completion block (closures) of your API calls.
Solution for me (Working fine and printing "Done"):
override func viewDidAppear(_ animated: Bool) {
if !self.defaults.getDownloadInicialTipoEntrega() || !self.defaults.getDownloadInicialPedido() || !self.defaults.getDownloadInicialVitrine() {
Functions.showAlertWaiting("Wait please...", self)
}
loadDeliveryTypesNOrders { (completed) in
if completed {
self.dismiss(animated: false, completion: { () in print("Done") })
}
}
}
func loadDeliveryTypesNOrders (completion: #escaping (Bool) -> ()) {
let parceiroId = self.defaults.getParceiroId()
if !self.defaults.getDownloadInicialTipoEntrega() {
TipoEntregaAPI().loadTiposEntrega(parceiroId){ (dados) in
if dados != nil {
for tipoEntrega in dados!{
// Do some stuff, no errors
}
}
}
}
if !self.defaults.getDownloadInicialPedido() {
PedidoAPI().loadOrders(parceiroId){ (dados) in
if dados != nil {
for pedidos in dados!{
// Do some stuff, no errors
}
}
}
}
completion(true)
}

Firebase UI delegate method is not called after phone verification is complete

I am trying to implement FIrebase UI phone number authentication, but the delegate method is not called after the phone number is verified. Any reason why?
class Login: UIViewController, FUIAuthDelegate {
let authUI = FUIAuth.defaultAuthUI()
override func viewDidAppear(_ animated: Bool) {
let phoneProvider = FUIPhoneAuth(authUI: authUI!)
authUI!.isSignInWithEmailHidden = true
authUI!.providers = [phoneProvider]
phoneProvider.signIn(withPresenting: self, phoneNumber: nil)
}
//this method does not work either... it is not called
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
print("user is \(authDataResult!.user.email)")
print("err is \(error?.localizedDescription)")
guard error == nil else {
print(error)
return
}
}
}
I had forgotten to assign self as the delegate to authUI
override func viewDidAppear(_ animated: Bool) {
authUI?.delegate = self
let phoneProvider = FUIPhoneAuth(authUI: authUI!)
authUI!.isSignInWithEmailHidden = true
authUI!.providers = [phoneProvider]
phoneProvider.signIn(withPresenting: self, phoneNumber: nil)
}

How to launch a view controller over another view controller?

I have a quiz app that asks questions in triviaviewcontroller, after 10 questions it segues to the videoviewcontroller, plays the video then segues back to the triviaviewcontroller. The problem is that it restarts the questions from the start, not question 11. Do I need to launch the video from the triviaviewcontroller or what approach do I need to change?
#IBAction func submitButton(_ sender: AnyObject) {
if noWhitespaceUserAnswer == answers[currentQuestionIndex]
{
self.currentQuestionTimerLabel.text = ""
answerField.text = ""
currentQuestionIndex = currentQuestionIndex + 1 < questions.count ? currentQuestionIndex + 1 : 0
if (currentQuestionIndex == 4){
performSegue(withIdentifier: "videoview", sender: self)
}
nextQuestionLabel.text = questions[currentQuestionIndex]
animateLabelTransitions()
}
else {
incorrectAnswerHoldLabel.isHidden = false
submitbuttonwronganswer.isHidden = true
let time = DispatchTime(uptimeNanoseconds:UInt64(0.1) ) + Double(4 * Int64(NSEC_PER_SEC)) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: time) {
self.submitbuttonwronganswer.isHidden = false
self.incorrectAnswerHoldLabel.isHidden = true
}
answerField.text = ""
}
}
Here is my videoviewcontroller.
class VideoViewController: AVPlayerViewController, AVPlayerViewControllerDelegate {
fileprivate var firstAppear = true
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if firstAppear {
do {
try playVideo()
firstAppear = false
} catch AppError.invalidResource(let name, let type) {
debugPrint("Could not find resource \(name).\(type)")
} catch {
debugPrint("Generic error")
}
}
}
fileprivate func playVideo() throws {
guard let path = Bundle.main.path(forResource: "RossCliffJumping", ofType:"m4v") else {
throw AppError.invalidResource("RossCliffJumping", "m4v")
}
let player = AVPlayer(url: URL(fileURLWithPath: path))
let playerController = AVPlayerViewController()
playerController.player = player
playerController.showsPlaybackControls = false
NotificationCenter.default.addObserver(self, selector: #selector(VideoViewController.itemDidFinishPlaying(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
self.present(playerController, animated: true) {
player.play()
}
}
func itemDidFinishPlaying(_ notification:Notification) {
dismiss(animated: true, completion: nil)
performSegue(withIdentifier: "videofinished", sender: self)
print("finished")
}
deinit{
NotificationCenter.default.removeObserver(self)
}
}
enum AppError : Error { case invalidResource(String, String)
}
You are already launching another view controller. From the sound of your question, it seems you want to call self.dismiss(animated: true, completion: nil) instead of performing another segue, to get back to the first controller. By calling performSegue you are creating a new controller, which of course is going to go back to question 1.

Calling achievement screen in Swift

I am having some extreme difficulties calling the achievements screen in game center. I have already set up the achievements in iTunes connect and it pops up fine if I access the achievements screen through the leaderboard first. However; I would like to be able to press a specific achievement button and be directed directly to the achievements screen. Can any one help? I have searched high and low on the internet ( and read through all of the documentation). I have found many resources for implementing leaderboards, but not many resources for implementing achievements in swift. My code is below. Any suggestions for my last two functions?
override func viewDidLoad() {
super.viewDidLoad()
login()
}
func login() {
println("Game Center Login Called")
let localPlayer = GKLocalPlayer.localPlayer()
// Handle the authentication
localPlayer.authenticateHandler = {(Home: UIViewController!, error: NSError!) -> Void in
if Home != nil {
println("Authentication is being processed.")
self.presentViewController(Home, animated: true, completion: nil)
} else {
println("Player has been successfully authenticated.")
}
}
}
func showLeaderboard() {
let gkScore = GKScore(leaderboardIdentifier: "high_Score_Leader_Board")
gkScore.value = Int64(highscore)
GKScore.reportScores([gkScore], withCompletionHandler: ( { (error: NSError!) -> Void in
if (error != nil) {
// handle error
println("Error: " + error.localizedDescription);
} else {
println("Score reported: \(gkScore.value)")
}
}))
var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
gcViewController.gameCenterDelegate = self
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
gcViewController.leaderboardIdentifier = "high_Score_Leader_Board"
self.showViewController(gcViewController, sender: self)
self.presentViewController(gcViewController, animated: true, completion: nil)
}
#IBAction func gameCenterButtoPressed(sender: AnyObject) {
showLeaderboard()
}
func gameCenterViewControllerDidFinish(gcViewController: GKGameCenterViewController!)
{
self.dismissViewControllerAnimated(true, completion: nil)
}
func showAchievements() {
// show Achievements screen
}
#IBAction func achievementButtonPressed(sender: AnyObject) {
// Call show achievements function when button pressed
}
Instead of:
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
I think what you'll want is:
gcViewController.viewState = GKGameCenterViewControllerState.Achievements
And I found this information in this related tutorial.