Upload Empty Strings to Firebase Realtime Database - ios

I'm trying to upload a child nod to a reference to my Firebase Realtime Database, however I'm running into an issue. I'm trying to have my secondDateAndTimes and thirdDateAndTimes upload as empty strings if they are not filled out, but my handleConfirm() will only work if the two are filled out. What do I need to do so the child node uploads even if the two UILabels are empty/not showing? Thank you!
JobRequest Model
struct JobRequest {
let uid: String
let fullname: String
let username: String
let address: String
let firstDateAndTimes: String
let secondDateAndTimes: String
let thirdDateAndTimes: String
let timeConstraints: String
let jobDescription: String
init(dictionary: [String : Any]) {
self.uid = dictionary["uid"] as? String ?? ""
self.fullname = dictionary["fullname"] as? String ?? ""
self.username = dictionary["username"] as? String ?? ""
self.address = dictionary["address"] as? String ?? ""
self.firstDateAndTimes = dictionary["firstDateAndTimes"] as? String ?? ""
self.secondDateAndTimes = dictionary["secondDateAndTimes"] as? String ?? ""
self.thirdDateAndTimes = dictionary["thirdDateAndTimes"] as? String ?? ""
self.timeConstraints = dictionary["timeConstraints"] as? String ?? ""
self.jobDescription = dictionary["jobDescription"] as? String ?? ""
}
}
API Service
struct JobDetailCredentials {
var uid: String
var fullname: String
var username: String
var address: String
var firstDateAndTimes: String
var secondDateAndTimes: String
var thirdDateAndTimes: String
var timeConstraints: String
var jobDescription: String
}
// MARK: - CustomerService
struct CustomerService {
static func uploadCustomerAndJobRequest(jobDetails: JobDetailCredentials, completion: #escaping(DatabaseCompletion)) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let values = ["uid" : jobDetails.uid,
"fullname" : jobDetails.fullname,
"username" : jobDetails.username,
"address" : jobDetails.address,
"firstDateAndTimes" : jobDetails.firstDateAndTimes,
"secondDateAndTimes" : jobDetails.secondDateAndTimes,
"thirdDateAndTimes" : jobDetails.thirdDateAndTimes,
"timeConstraints" : jobDetails.timeConstraints,
"jobDescription" : jobDetails.jobDescription] as [String : Any]
REF_CUSTOMERS.child(uid).child("job-request-details").childByAutoId().updateChildValues(values, withCompletionBlock: completion)
}
}
RequestJobConfirmationController
lazy var secondDateAndTimeDetailsLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
label.font = UIFont(name: "AvenirNext-MediumItalic", size: 14)
label.numberOfLines = 0
return label
}()
lazy var thirdDateAndTimeDetailsLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
label.font = UIFont(name: "AvenirNext-MediumItalic", size: 14)
label.numberOfLines = 0
return label
}()
#objc func handleConfirm() {
guard let uid = Auth.auth().currentUser?.uid ,
let fullname = fullnameDetailsLabel.text ,
let username = customer?.username ,
let address = addressDetailsLabel.text ,
let firstDateAndTimes = firstDateAndTimeDetailsLabel.text ,
let secondDateAndTimes = secondDateAndTimeDetailsLabel.text ,
let thirdDateAndTimes = thirdDateAndTimeDetailsLabel.text ,
let timeConstraints = timeConstraintsDetailsLabel.text ,
let jobDescription = jobDescriptionDetailsLabel.text else { return }
let jobDetails = JobDetailCredentials(uid: uid, fullname: fullname, username: username, address: address,
firstDateAndTimes: firstDateAndTimes, secondDateAndTimes: secondDateAndTimes,
thirdDateAndTimes: thirdDateAndTimes, timeConstraints: timeConstraints,
jobDescription: jobDescription)
CustomerService.uploadCustomerAndJobRequest(jobDetails: jobDetails) { error, ref in
if let _ = error {
self.simpleAlert(title: "Error", msg: "Unable to upload job details, please try again later.")
return
}
let controller = FindEmployeeJobRequestController()
controller.modalPresentationStyle = .fullScreen
self.present(controller, animated: true, completion: nil)
}
}

Instead of putting your secondDateAndTimes and thirdDateAndTimes inside the guard, which will guarantee that the function returns if they're nil, move them outside of that guard and optionally bind them:
guard let uid = Auth.auth().currentUser?.uid ,
let fullname = fullnameDetailsLabel.text ,
let username = customer?.username ,
let address = addressDetailsLabel.text ,
let firstDateAndTimes = firstDateAndTimeDetailsLabel.text ,
let timeConstraints = timeConstraintsDetailsLabel.text ,
let jobDescription = jobDescriptionDetailsLabel.text else { return }
let secondDateAndTimes = secondDateAndTimeDetailsLabel.text ?? "",
let thirdDateAndTimes = thirdDateAndTimeDetailsLabel.text ?? "",
//...

I figured what my problem was, I wasn't setting empty strings as the texts for my UILabels.
RequestJobConfirmationController
lazy var secondDateAndTimeDetailsLabel: UILabel = {
let label = UILabel()
label.text = ""
label.textColor = .black
label.textAlignment = .center
label.font = UIFont(name: "AvenirNext-MediumItalic", size: 14)
label.numberOfLines = 0
return label
}()
lazy var thirdDateAndTimeDetailsLabel: UILabel = {
let label = UILabel()
label.text = ""
label.textColor = .black
label.textAlignment = .center
label.font = UIFont(name: "AvenirNext-MediumItalic", size: 14)
label.numberOfLines = 0
return label
}()

Related

Format data content in Tableviewcell in Swift

How it should look like.
How it currently look like.
I'm trying to display information on my tableview cell.
The first cell information on the image above looks good, but only when the table view is on edit mode - and I only want the same display in normal mode for all my cells.
Here is my code below
//cellForRow method
var cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: celliD)
cell?.textLabel?.numberOfLines = 0
cell?.detailTextLabel?.numberOfLines = 0
cell?.accessoryView = nil
cell?.tintColor = UIColor.cmoOrangeColor
cell?.textLabel?.textColor = UIColor.darkGray
cell?.detailTextLabel?.textColor = UIColor.lightGray
let animalEntity = self.newSaleSelectedAnimalsManagedObject[indexPath.row] as? AnimalEntity
cell?.textLabel?.attributedText = AnimalFacade.animalTitleAttributedText(animalEntity: animalEntity!, withHolding: false)
cell?.detailTextLabel?.attributedText = AnimalFacade.animalDetails()
return cell!
//textLabel formating data
class func animalTitleAttributedText(animalEntity: AnimalEntity, withHolding: Bool) -> NSMutableAttributedString {
//AttributedText
let attributedTitle = NSDictionary(object: UIFont.tableViewCellTitle as Any, forKey: NSFontAttributeName as NSCopying) as? [String : Any]
let attributedSubtitle = NSDictionary(object: UIFont.tableViewCellSubtitle as Any, forKey: NSFontAttributeName as NSCopying) as? [String : Any]
//TextLabel
let titleAttributedText = NSMutableAttributedString()
//officialTag
let officialTag = animalEntity.officialTag //UK 123456 123456
let mgtTag = animalEntity.managementTag //WER3456
let age = DateUtil.calculateAge(dateTime: animalEntity.dob! as Date) //13 y
let animalCategory = animalEntity.animalTag //Heifer Calf
let breed = animalEntity.breed //AB
titleAttributedText.append(NSAttributedString(string: officialTag! + "\n", attributes: attributedTitle))
titleAttributedText.append(NSAttributedString(string: "Mgmt Tag: \(mgtTag!), \(age), \(animalCategory!), \(breed!) \n", attributes: attributedSubtitle))
return titleAttributedText
}
//detailLabel formatting data
class func animalDetails() -> NSMutableAttributedString {
let attributedSubtitle = NSDictionary(object: UIFont.tableViewCellSubtitle as Any, forKey: NSFontAttributeName as NSCopying) as? [String : Any]
//detailsLabel
let detailsAttributedText = NSMutableAttributedString()
let price = "1234.85"
let lotNumber = "TREPOU123"
detailsAttributedText.append(NSAttributedString(string: price + "\n\n", attributes: attributedSubtitle))
detailsAttributedText.append(NSAttributedString(string: lotNumber, attributes: attributedSubtitle))
return detailsAttributedText
}

Get string from substring

I have following string "#[Hema](hema_ramburuth), #[Ilesh P](ilesh.panchal), #[Lewis Murphy](lewis) how are you?". I want to display this screen like this "Hema, Ilesh P, Lewis Murphy how are you?" also I want to identify the screen for the click event.
I have used the ActiveLabel repo for the click.
Hey I have had encountered a similar requirement. So this is how I have handled.
I have created an extension for String
extension String {
/// Returns range of text in the string
func getRange(OfText text: String) -> NSRange {
let nsRepresentation = self as NSString
return nsRepresentation.range(of: text)
}
}
In your View Controller,
var tapPrivacyGesture = UITapGestureRecognizer()
#IBOutlet weak var yourLabel: UILabel!
var displayText = String()
func matchesForRegexInText(regex: String, text: String, firstBracket: String, lastBracket: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: [])
let nsString = text as NSString
let results = regex.matches(
in: text,
options: [],
range: NSRange(location: 0, length: nsString.length))
return results.map { nsString.substring(with: $0.range) }.map { $0.replacingOccurrences(of: firstBracket, with: "") }.map { $0.replacingOccurrences(of: lastBracket, with: "") }
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
var givenString = "#[Hema](hema_ramburuth), #[Ilesh P](ilesh.panchal), #[Lewis Murphy](lewis) how are you?"
let nameStrings = matchesForRegexInText(regex: "\\[(.*?)\\]", text: givenString, firstBracket: "[", lastBracket: "]")
let removeForUIStrings = matchesForRegexInText(regex: "\\((.*?)\\)", text: givenString, firstBracket: "(", lastBracket: ")")
removeForUIStrings.forEach {
givenString = givenString.replacingOccurrences(of: "(\($0))", with: "")
}
nameStrings.forEach {
givenString = givenString.replacingOccurrences(of: "[\($0)]", with: $0)
}
givenString = givenString.replacingOccurrences(of: "#", with: "")
print(givenString)
displayText = givenString
tapPrivacyGesture.addTarget(self, action: #selector(self.handlePolicyTap(tap:)))
yourLabel.addGestureRecognizer(tapPrivacyGesture)
yourLabel.isUserInteractionEnabled = true
func handlePolicyTap(tap: UITapGestureRecognizer) {
let storage = NSTextStorage(attributedString: yourLabel.attributedText ?? NSAttributedString())
let layoutManager = NSLayoutManager()
storage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: CGSize(width: yourLabel.frame.size.width, height: yourLabel.frame.size.height+100))
textContainer.lineFragmentPadding = 0.0
textContainer.lineBreakMode = (yourLabel.lineBreakMode)
textContainer.maximumNumberOfLines = yourLabel.numberOfLines
layoutManager.addTextContainer(textContainer)
let location: CGPoint = tap.location(in: yourLabel)
let characterIndex: Int = layoutManager.characterIndex(for: location, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
guard
characterIndex < storage.length,
let question = currentQuestion else {
return
}
nameStrings.forEach {
let range = displayText.getRange(OfText: $0)
if range.contains(characterIndex) {
/// Perform actions on click of this string
}
}
}
As from your question, just hard-code parsing done below.
let fullString = "#[Hema](hema_ramburuth), #[Ilesh P](ilesh.panchal), #[Lewis Murphy](lewis) how are you?"
let allarray = fullString.split(separator: ",")
let messageArray = allarray.last
let message = messageArray?.split(separator: ")")
let correctMessage = message?.last
var allNames : String = ""
for namesString in allarray {
if allNames.count > 0 {
allNames += ", "
}
let name = String(namesString)
allNames += name.slice(from: "#[", to: "]") ?? ""
}
if allNames.count > 0 {
allNames += correctMessage ?? ""
}
print("Name and Message --- > \(allNames)")
Slicing string using String extension
extension String {
func slice(from: String, to: String) -> String? {
return (range(of: from)?.upperBound).flatMap { substringFrom in
(range(of: to, range: substringFrom..<endIndex)?.lowerBound).map { substringTo in
substring(with: substringFrom..<substringTo)
}
}
}
}
I've printed output as below:
Name and Message --- > Hema, Ilesh P, Lewis Murphy how are you?

UILabel.attributedText set attributes once and then just change text (string)

How to set UILabel text attributes only once and then just change text (string)
mTextValue.attributedText = NSAttributedString(string: "STRING",
attributes:
[NSAttributedStringKey.strokeWidth: -3.0,
NSAttributedStringKey.strokeColor: UIColor.black])
mTextValue.text = "NEW STRING" // won't change anything
or to set new string do I have to set NSAttributedString to .attributedText again and again?
You could declare a mutableAttributed string separat and change the string of it like here:
let yourString = "my string"
let yourAttributes = [NSAttributedStringKey.strokeWidth: -3.0, NSAttributedStringKey.strokeColor: UIColor.black] as [NSAttributedStringKey : Any]
let mutableAttributedString = NSMutableAttributedString(string: yourString, attributes: yourAttributes)
let yourNewString = "my new string"
mutableAttributedString.mutableString.setString(yourNewString)
Full example:
import UIKit
class ViewController: UIViewController {
var mutableAttributedString = NSMutableAttributedString()
#IBAction func buttonTapped(_ sender: Any) {
mutableAttributedString.mutableString.setString("new string")
mainLabel.attributedText = mutableAttributedString
}
#IBOutlet weak var mainLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let yourString = "my string"
let yourAttributes = [NSAttributedStringKey.strokeWidth: -3.0, NSAttributedStringKey.strokeColor: UIColor.blue] as [NSAttributedStringKey : Any]
mutableAttributedString = NSMutableAttributedString(string: yourString, attributes: yourAttributes)
mainLabel.attributedText = mutableAttributedString
}
}

Get word that was tapped in UILabel instead of character [iOS]

I am trying to extract the word that was tapped in a UILabel using tap gesture recognizer. I am able to get the character that was tapped, as well as the range of the character, but I am not able to extract the full word. Is there a way to get the full string of the word that was tapped instead of the character?
if let label = descriptionLabel, tapGestureRecognizer != nil {
if label.attributedText == nil {
return
}
let storage = NSTextStorage(attributedString: label.attributedText ?? NSAttributedString())
let textContainer = NSTextContainer(size: label.bounds.size)
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainer)
storage.addLayoutManager(layoutManager)
textContainer.lineFragmentPadding = 0.0
textContainer.lineBreakMode = (label.lineBreakMode)
textContainer.maximumNumberOfLines = label.numberOfLines
let location: CGPoint = tapGestureRecognizer!.location(in: label)
let characterIndex: Int = layoutManager.characterIndex(for: location, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
if characterIndex < storage.length {
print("Character Index: \(Int(characterIndex))")
let range = NSRange(location: characterIndex, length: 1)
let substring: String? = (label.attributedText?.string as NSString?)?.substring(with: range)
//prints out one character, how do I get the full word of this character
print(substring)
}
}
Much appreciated
I don't like this way, but it works. Place the following after the print(substring) statement. Why doesn't UIKit have a method to extract the full string at a Range? Ridiculous.
let afterWords: [Any] = (afterString.components(separatedBy: " "))
let beforeWords: [Any] = (beforeString.components(separatedBy: ", "))
var attachmentString = ""
if let stringBeforeLocation = beforeWords.last as? String, let stringAfterLocation = afterWords.first as? String {
attachmentString = stringBeforeLocation
if stringAfterLocation.count > 0 {
let choppedString = (stringAfterLocation as NSString).substring(from: 1)
attachmentString = attachmentString + choppedString
print("FULL STRING TAPPED \(attachmentString)")
}
}

make part of the text bold in a UITextField

Based on the answers here I made this code:
extension NSMutableAttributedString {
func bold(text:String, size:CGFloat) -> NSMutableAttributedString {
let attrs:[String:AnyObject] = [NSFontAttributeName : UIFont.boldSystemFontOfSize(size)]
let boldString = NSMutableAttributedString(string:"\(text)", attributes:attrs)
self.appendAttributedString(boldString)
return self
}
func normal(text:String)->NSMutableAttributedString {
let normal = NSAttributedString(string: text)
self.appendAttributedString(normal)
return self
}
}
and I use it like this:
#IBOutlet weak var m_field: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let string = NSMutableAttributedString()
string.bold("Bold_text: ",size: 12).normal("normal text")
m_field.attributedText = string
}
but it doesn't work, all my text is the same (bold I think)
what am I doing wrong?
Enjoy - below code works for swift 3
let normalText = "Hi am normal"
let boldText = "And I am BOLD!"
let attributedString = NSMutableAttributedString(string:normalText)
let attrs = [NSFontAttributeName : UIFont.boldSystemFont(ofSize: 15)]
let boldString = NSMutableAttributedString(string:boldText, attributes:attrs)
attributedString.append(boldString)
txt.attributedText = attributedString
where txt is TextField outlet
assign "**string**" variable value to **attributedText** property
var m_field = UITextField()
m_field.frame = CGRect(x: 0, y: 66, width: 400, height: 100)
let string = NSMutableAttributedString()
string.bold("Bold_text: ",size: 15).normal("normal text")
m_field.attributedText = string
self.view .addSubview(m_field)

Resources