How Can I Change a String Using Remote Config? - swift

I'm creating an app that plays a sound when a button is clicked. It consists of UIButton to play the sound, UIImageView to display the associated image, and another UIButton which I'm using like a label to describe the button. I want to be able to configure all three parameters so I can change them remotely from Firebase. So far I figured out how to change the label, but I want to be able to change the URL that the sound and image load from. Here is my code:
import UIKit
import Firebase
import AVKit
class FirebaseViewController: UIViewController, AVAudioPlayerDelegate {
//These variables are for my sound when I click a button
var firesound1 = AVPlayer()
var firesound2 = AVPlayer()
var firesound3 = AVPlayer()
//These outlets reference the labels(UIButton) and UIImageView in the storyboard
#IBOutlet weak var firelabel1: UIButton!
#IBOutlet weak var firelabel2: UIButton!
#IBOutlet weak var firelabel3: UIButton!
#IBOutlet weak var fireimage1: UIImageView!
#IBOutlet weak var fireimage2: UIImageView!
#IBOutlet weak var fireimage3: UIImageView!
func updateViewWithRCValues() {
//These remote config options allow me to change the text of the UIButton, which here I'm using like a UILabel
firelabel1.setTitle(buttonLabel1, for: .normal)
let buttonLabel2 = RemoteConfig.remoteConfig().configValue(forKey: "label2").stringValue ?? ""
firelabel2.setTitle(buttonLabel2, for: .normal)
let buttonLabel3 = RemoteConfig.remoteConfig().configValue(forKey: "label3").stringValue ?? ""
firelabel3.setTitle(buttonLabel3, for: .normal)
let url = RemoteConfig.remoteConfig().configValue(forKey: "url1").stringValue ?? ""
firelabel3.setTitle(buttonLabel3, for: .normal)
}
func setupRemoteConfigDefaults() {
let defaultValues = [
"label1": "" as NSObject,
"label2": "" as NSObject,
"label3": "" as NSObject
]
RemoteConfig.remoteConfig().setDefaults(defaultValues)
}
func fetchRemoteConfig() {
// Remove this before production!!
let debugSettings = RemoteConfigSettings(developerModeEnabled: true)
RemoteConfig.remoteConfig().configSettings = debugSettings!
RemoteConfig.remoteConfig().fetch(withExpirationDuration: 0) { [unowned self] (status, error) in guard error == nil else {
print ("Error fetching remote values: \(String(describing: error))")
return
}
print("Retrieved values from the cloud")
RemoteConfig.remoteConfig().activateFetched()
self.updateViewWithRCValues()
}
}
override func viewDidLoad() {
super.viewDidLoad()
setupRemoteConfigDefaults()
fetchRemoteConfig()
//This code loads an image from a url into a UIImageView. I want to be able to configure the url like a parameter so I can change the url from the firebase website.
let url = URL(string: "https://ichef-1.bbci.co.uk/news/976/media/images/83351000/jpg/_83351965_explorer273lincolnshirewoldssouthpicturebynicholassilkstone.jpg")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if (error != nil)
{
print("ERROR")
}
else
{
var documentsDirectory: String?
var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
if paths.count > 0
{
documentsDirectory = paths [0]
let savePath = documentsDirectory! + "/ImageOne"
FileManager.default.createFile(atPath: savePath, contents: data, attributes: nil)
DispatchQueue.main.async
{
self.fireimage1.image = UIImage(named: savePath)
}
}
}
}
task.resume()
}
//This code plays the sounds. I also want to be able to configure the url like a parameter.
#IBAction func soundpressed1(_ sender: Any) {
let sound1 = AVPlayerItem(url: URL(string: "https://firebasestorage.googleapis.com/v0/b/mlg-soundboard-2018-edition.appspot.com/o/hitmarker.mp3?alt=media&token=e5d342d6-4074-4c50-ad9d-f1e41662d9e9")!)
firesound1 = AVPlayer(playerItem: sound1)
firesound1.play()
}
override func didReceiveMemoryWarning() {
}
}
Basically I want to be able to swap out the URLs with Remote Config.

You can either create separate keys in Remote config for Text, Sound URL and Image URL.
Or you can create a key called button_config and supply all the three params in a JSON
button_config = {"text" : "My button label", "sound_url" : "https://foo.com/sound.mp3", "image_url" : "https://foo.com/image.png"}

Related

When I tap the image I want to go to the URL

I am trying that when I press the image it takes me to the link
I have this:
class CoverPillCell: TableViewCell {
#IBOutlet weak var imagePill: UIImageView!
#IBOutlet weak var imagenButton: UIButton!
this contains variables that later in the load function call the remoteconfig
height = CGFloat(promoPill?.image_height ?? 0)
width = CGFloat(promoPill?.image_width ?? 0)
target_url = promoPill?.target_url ?? ""
position = promoPill?.position ?? 0
if enabled == true {
enabled = ((promoPill?.enabled) != nil)
}
//This is what I'm trying to when tap go to the target url which is configured on the remote config
if imagenButton.isUserInteractionEnabled == true {
self.imagenButton.addTarget(self, action: #selector(tapPill(_:)), for: .touchUpInside)
}
And in the IBAction I'm trying this:
#IBAction func tapPill(_ sender: UIButton) {
let promoPill = getPromoPill()
target_url = promoPill?.target_url ?? ""
}
Maybe this link can help you
You have to do something like this ->
let myURL = URL(string:"https://www.apple.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)

Presenting view controller from detached view controller is discouraged. Keeping User logged in issue

I'm trying to have the user move to automatically go to the Home Screen and not have to log in again. Basically, to remember the user. I used User Defaults to save the user login info and put the listener for the key in the viewDidLoad of the first login page. I used an if statement to switch the view controllers but it doesn't work and prints (Presenting view controller from detached view controller is discouraged).
LoginViewController:
import UIKit
import FirebaseAuth
import AVKit
class LoginViewController: UIViewController {
var videoPlayer:AVPlayer?
var videoPlayerLayer:AVPlayerLayer?
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var Back: UIButton!
#IBOutlet weak var passwordtextField: UITextField!
#IBOutlet weak var loginButton: UIButton!
#IBOutlet weak var errorLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
setupElements()
}
func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
func setupElements(){
errorLabel.alpha = 0
Utilities.styleTextField(emailTextField)
Utilities.styleTextField(passwordtextField)
Utilities.styleFilledButton(loginButton)
}
func validateFields() -> String?
{
//make sure fields are filled
if emailTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || passwordtextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == ""
{
return "Please fill all fields"
}
return nil
}
#IBAction func loginTapped(_ sender: Any) {
//creates a clean version of the text field
let email = emailTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let password = passwordtextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let error = validateFields()
//sign in user
Auth.auth().signIn(withEmail: email, password: password) { (result, error) in
UserDefaults.standard.set(Auth.auth().currentUser!.uid, forKey: "user_uid_key")
UserDefaults.standard.synchronize()
if error != nil{
self.errorLabel.text = "Invalid Username/Password try again."
self.errorLabel.alpha = 1
}
else{
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constants.StoryBoard.homeViewController) as?
HomeViewController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
}
}
//make sure all fields are filled
}
override func viewWillAppear(_ animated: Bool) {
setUpVideo()
}
func setUpVideo(){
//Get path to resource bundle
let bundlePath = Bundle.main.path(forResource: "IMG_7211 2", ofType: "mov")
guard bundlePath != nil else{
return
}
//create the url from it
let url = URL(fileURLWithPath: bundlePath!)
//Create The video Player item
let item = AVPlayerItem(url: url)
//create the player
videoPlayer = AVPlayer(playerItem: item)
//create the layer
videoPlayerLayer = AVPlayerLayer(player: videoPlayer!)
//adjust the size and frame
videoPlayerLayer?.frame = CGRect(x: -self.view.frame.size.width*1.5, y:0, width: self.view.frame.size.width*4, height: self.view.frame.size.height)
view.layer.insertSublayer(videoPlayerLayer!, at: 0)
//add and play
videoPlayer?.playImmediately(atRate: 0.8)
}
}
ViewController:
import UIKit
import AVKit
import Firebase
import FirebaseAuth
class ViewController: UIViewController {
var videoPlayer:AVPlayer?
var videoPlayerLayer:AVPlayerLayer?
#IBOutlet weak var signUpButton: UIButton!
#IBOutlet weak var logInButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
if UserDefaults.standard.object(forKey: "user_uid_key") != nil {
print("i see u")
let navController = UINavigationController(rootViewController: HomeViewController())
navController.navigationBar.barStyle = .black
self.present(navController, animated: false, completion: nil)
}
else {
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constants.StoryBoard.homeViewController) as?
ViewController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
}
// Do any additional setup after loading the view.
setupElements()
}
func showhomepage() {
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constants.StoryBoard.homeViewController) as?
HomeViewController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
}
override func viewWillAppear(_ animated: Bool) {
//Set up video in background
setUpVideo()
}
func setUpVideo(){
//Get path to resource bundle
let bundlePath = Bundle.main.path(forResource: "Project", ofType: "mp4")
guard bundlePath != nil else{
return
}
//create the url from it
let url = URL(fileURLWithPath: bundlePath!)
//Create The video Player item
let item = AVPlayerItem(url: url)
//create the player
videoPlayer = AVPlayer(playerItem: item)
//create the layer
videoPlayerLayer = AVPlayerLayer(player: videoPlayer!)
//adjust the size and frame
videoPlayerLayer?.frame = CGRect(x: -self.view.frame.size.width*1.5, y:0, width: self.view.frame.size.width*4, height: self.view.frame.size.height)
view.layer.insertSublayer(videoPlayerLayer!, at: 0)
//add and play
videoPlayer?.playImmediately(atRate: 1)
}
func setupElements(){
Utilities.styleFilledButton(signUpButton)
Utilities.styleHollowButton(logInButton)
}
}
Looks like you're using Firebase. Do not store any login information in the User defaults. What you should do is create a blank view controller that will check if the user is signed in. If the user is signed it, it will present your HomeViewController; if the user is not signed in, it will present the login screen. You can also choose to perform these checks in your AppDelegate/SceneDelegate if you want to avoid the extra view controller.
The empty ViewController should be the initial/root ViewController.
You cannot present view controllers from inside viewDidLoad, use viewDidAppear.
Here is a basic example for the view controller way:
// in the new empty view controller, import FirebaseAuth
var handle: AuthStateDidChangeListenerHandle!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(false)
handle = Auth.auth().addStateDidChangeListener { auth, user in
if user != nil {
// Go to Home Screen/ switch root
} else {
// Go to sign in screen/ switch root
}
}
}

Not Retriveing Output Predictions from Remote Firebase Automl custom model

I am currently trying to build an app that uses google's autoML feature. I have trained a model and published it on google firebase and have integrated the necessary code into my app following the documentation:
https://firebase.google.com/docs/ml-kit/ios/label-images-with-automl
I am using a remote model instead of making it local. However when I try running the code, then choose an image in the simulator, an empty list of predictions is output in the console.
I have also turned on the debugging feature, but this has not helped me fix my error. This is the code I am running in ViewController:
import UIKit
import CoreML
import Vision
import Firebase
import FirebaseMLCommon
var serverImage: UIImage? = nil
var topResult = ""
class ViewController: UIViewController {
#IBOutlet var skinDiseaseImageView: UIImageView!
#IBOutlet var result1Label: UILabel!
#IBOutlet var result1Confidence: UILabel!
#IBOutlet var result2Label: UILabel!
#IBOutlet var result2Confidence: UILabel!
#IBOutlet var result3Label: UILabel!
#IBOutlet var result3Confidence: UILabel!
override func viewDidLoad() {
let initialConditions = ModelDownloadConditions(allowsCellularAccess: true,
allowsBackgroundDownloading: true)
let updateConditions = ModelDownloadConditions(allowsCellularAccess: false,
allowsBackgroundDownloading: true)
let remoteModel = RemoteModel(
name: "skinDiseaseModel", // The name you assigned in the console.
allowsModelUpdates: true,
initialConditions: initialConditions,
updateConditions: updateConditions
)
ModelManager.modelManager().register(remoteModel)
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension ViewController {
#IBAction func selectImage(_ sender: Any) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = .savedPhotosAlbum
present(pickerController, animated: true)
}
}
extension ViewController: UIImagePickerControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
dismiss(animated: true)
guard let skinImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
fatalError("Error Retrieving Image Line 95")
}
var skinImageToDiagnose = VisionImage(image: skinImage)
serverImage = skinImage
skinDiseaseImageView.image = skinImage
let labelerOptions = VisionOnDeviceAutoMLImageLabelerOptions(
remoteModelName: "skinDiseaseModel", // Or nil to not use a remote model
localModelName: nil // Or nil to not use a bundled model
)
labelerOptions.confidenceThreshold = 0 // Evaluate your model in the Firebase console
// to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: labelerOptions)
var topThreeResults = [String]()
var topThreeConfidences = [String]()
labeler.process(skinImageToDiagnose) { labels, error in
guard error == nil, let labels = labels
else {
print(error)
return
}
//task succeeded
print("1")
print(labels)
var counter = 0
for label in labels {
topThreeResults.append(String(describing: label))
topThreeConfidences.append(String(describing: label.confidence))
counter = counter + 1
print("counter")
if counter == 3 {
break
}
}
}
result1Label.text = topThreeResults[0]
result1Confidence.text = (topThreeConfidences[0] + "%")
result2Label.text = topThreeResults[1]
result2Confidence.text = (topThreeConfidences[1] + "%")
result3Label.text = topThreeResults[2]
result3Confidence.text = (topThreeConfidences[2] + "%")
}
}
This is the error I recieved:
Fatal error: Index out of range
2019-08-31 19:50:19.763469-0700 medicalAppFinal[13776:2281569] Fatal error: Index out of range
(lldb)
I reasoned that the index out of range problem is due to the list of labels(output predictions) being empty after having printed it. Thus I understand why it is index out of range, but I do not know why I am recieving an empty list after passing in the image into labeler.process() How do I solve this error? Tell me if you need more information
This seems to be duplicate of the following question (which was answered by the author):
Not Retriveing Output Prediction List from Remote Firebase Automl custom model

How to grab the value of a WebView in Swift

Suppose I have a label that is a NSTextField. I know I can access the value of that label by:
#IBOutlet weak var label: NSTextField!
let labelValue = label.stringValue
And then I can use that variable accordingly.
The same is easily said for an NSImage:
#IBOutlet weak var productImageView: NSImageView!
let img = productImageView.image
My question is how do I grab the value of a WebView. I am unsure which property allows me to use a WebView.
#IBOutlet weak var videoTemp: WebView!
let videoPassed = videoTemp //how do I access this videoTemp's value much like .stringValue and .image
I am trying to load dynamic video URL's to Youtube videos when I click on a collection view item. The line that I have commented in my setupAppVideo method is where my fatal error occurs:
"fatal error: unexpectedly found nil while unwrapping an Optional value"
but when I print out the url and request variables their are no nil values and all of them are the correct links in the console.
import Cocoa
import WebKit
class test1: NSCollectionViewItem {
#IBOutlet weak var label: NSTextField!
#IBOutlet weak var label2: NSTextField!
#IBOutlet weak var productImageView: NSImageView!
#IBOutlet weak var videoTemp: WKWebView!
var buildProduct: ProductModel? {
didSet{
label.stringValue = (buildProduct?.product_name)!
label2.stringValue = (buildProduct?.product_price)!
setupAppIconImage()
setupAppVideo()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
func setupAppIconImage() {
if let appIconImageURL = buildProduct?.product_image {
let url = NSURL(string: appIconImageURL)
URLSession.shared.dataTask(with: url! as URL,completionHandler:{(data, response, error) in
if error != nil {
print(error)
return
}
DispatchQueue.main.async(){
self.productImageView.image = NSImage(data: data!)
}
}).resume()
}
}
func setupAppVideo(){
if let appVideoURL = buildProduct?.product_video{
let url = NSURL(string: appVideoURL)
print(url)
let request = NSURLRequest(url: url as! URL)
print(request)
//self.videoTemp.load(request as URLRequest)
}
}
}

Changing the view color when comparing values

I created a view to use as background and I would like to change its color when label text is greater or less than variable number. The script is okay but the color is not changing.
Thanks in advance.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var localName: UITextField!
#IBOutlet weak var localNameLabel: UILabel!
#IBOutlet weak var localTemp: UILabel!
#IBAction func getData(sender: AnyObject) {
getWeatherData("http://api.openweathermap.org/data/2.5/weather?q=" + localName.text! + "")
}
#IBOutlet weak var fundo: UIView!
override func viewDidLoad() {
super.viewDidLoad()
getWeatherData("http://api.openweathermap.org/data/2.5/weather?q=London")
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getWeatherData(urlString: String){
let url = NSURL (string: urlString)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) in
dispatch_async(dispatch_get_main_queue(), {
self.setLabels(data!)
})
}
task.resume()
}
func setLabels(weatherData: NSData) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(weatherData, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
print(json)
//localNameLabel.text = json[("name")] as? String
if let name = json[("name")] as? String {
localNameLabel.text = name
}
if let main = json[("main")] as? NSDictionary {
if let temp = main[("temp")] as? Double {
//convert kelvin to celsius
let ft = (temp - 273.15)
let myString = ft.description
localTemp.text = myString
self.changeColor()
}
}
} catch let error as NSError {
print(error)
}
var number : Float
func changeColor(){
number = 19.0
if(Float(localTemp.text!) < number){
fundo.backgroundColor = .blueColor()
}else{
fundo.backgroundColor = .orangeColor()
}
}
}
}
Edited to post the entire script
In your view controller you need to add UITextFieldDelegate which will allow you to access methods related to your text field. The top of your view controller should look like this:
class ViewController: UIViewController,UITextFieldDelegate //set delegate to class
You then need to set the delegate of your text field to self in viewDidLoad and add a target for when the text field changes:
override func viewDidLoad() {
super.viewDidLoad()
localTemp.delegate = self //set delegate to this vc
localTemp.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
}
You can then implement this method which will run on every key press and you need to call your changeColor() method as above:
func textFieldDidChange(textField: UITextField) {
self.changeColor()
}