How to retrieve message as a String from MessageKit - swift

I am using MessageKit to make a basic chatting app. However, I wanted to do something with the text of the latest sent message.
This is an example of what I want:
print("This is what I was talking about:\n\n", newMessage.kind)
I get:
text("Hi StackOverflow!")
However, I wish to get only this String "Hi StackOverflow". Any help would be appreciated thanks.

You can use a switch statement. For example,
var message = ""
switch newMessage.kind {
case .text(let messageText):
message = messageText
default:
break
}
This question is similar to yours, and may be useful

func getTheMessageText(messageKind: MessageKind) -> String {
if case .text(let value) = messageKind {
return value
}
return ""
}
Usage: Call this method to get the message as a string like
let messageType:MessageType = messageList[indexPath.section]
getTheMessageText(messageKind: messageType.kind)

Related

Swift Firebase Authentication - two questions about error handling (I'm not sure how to name these errors)

It's really hard to find a proper title for this question. Please be easy on me.
The first part is a check to see if an account exists:
Auth.auth().fetchSignInMethods(forEmail: userEmail, completion: {
(providers, error) in
if error != nil {
self.displayAlertMessage(alertTitle: "Unhandled error", alertMessage: "Undefined error #SignUpViewController_0001");
return;
} else if providers != nil {
self.displayAlertMessage(alertTitle: "Error", alertMessage: "This account is not exist.");
return;
}
})
As you can see, I have something named Unhandled error with message Undefined error. I don't know how to name it properly. Can somebody explain that part to me?
The second one is about getting a localized string - any ideas to make it fancy?
Auth.auth().createUser(withEmail: userEmail, password: userPassword) { user, error in if error == nil && user != nil {
self.displayAlertMessage(alertTitle: "Success", alertMessage: "Your account created successfully. We send you a verification email.", dismiss: true);
} else {
self.displayAlertMessage(alertTitle: "Firebase error", alertMessage: "(error!.localizedDescription)");
}
}
Thanks for tips :)
You can handle the Errors this way:
Auth.auth().fetchSignInMethods(forEmail: email, completion: { (response, error) in
if let error = error, let errCode = AuthErrorCode(rawValue: error._code)
{
switch errCode {
case .emailAlreadyInUse:
GeneralHelper.sharedInstance.displayAlertMessage(titleStr: LocalizeConstant.CommonTitles.Alert.rawValue.localizedStr(), messageStr: LocalizeConstant.CommonTitles.Continue.rawValue.localizedStr())
case .accountExistsWithDifferentCredential:
GeneralHelper.sharedInstance.displayAlertMessage(titleStr: LocalizeConstant.CommonTitles.Alert.rawValue.localizedStr(), messageStr: LocalizeConstant.CommonTitles.Continue.rawValue.localizedStr())
default:
break
}
return
}
}
Here I am getting the errCode using AuthErrorCode provided by Firebase itself and then, I am passing in the received error code using error._code. So, now I can get the type of AuthErrorCode. Using this I am making cases like .emailAlreadyInUser, .accountExistsWithDifferentCredential etc. You can just type . and it will show you all the AuthErrorCodes. So, you can simply handle the error codes in this way.
Now, coming to the second part of the question, i.e. getting localized string. You can add localization to Firebase, for that you have to select the language code. Auth.auth().languageCode = "en" //For English. But, I do not think that it gives localized errors as there are many more languages than what Firebase supports. This mainly for sending localized emails.
To handle the localization, you have to create your own method as I did. You can see that I have called a function displayAlertMessage in which I am passing thetitleStr: LocalizeConstant.CommonTitles.Alert.rawValue.localizedStr(), which is a part of localization.
struct LocalizeConstant {
enum CommonTitles: String
{
case Alert = "common_alert"
}
}
This value designates to the key given by me in the localization file. If you do not know about localization, you have to do a Google search on it. Let's say I have two Localizable.strings one is in English and the other one is in French. In Localizable.strings(English), I've written Alert like this:
"common_alert" = "Alert";
And, In French:
"common_alert" = "Alerte!";
So, this is how I have manually added localization in my app. But, to achieve this you have to do two things. 1) You have to set up your appLanguage. 2) You have to call a method which will fetch the values from these keys defined in the Localizable.strings file.
To do this, I have created a method localizedStr(). It is an extension to String and you can use it as follows.
extension String{
func localizedStr() -> String
{
var finalRes = ""
if let path = Bundle.main.path(forResource: Constants.appLang, ofType: "lproj") //Constants.appLang is "en" here for "English", but you can set accordingly.
{
if let bundle = Bundle(path: path)
{
finalRes = NSLocalizedString(self, tableName: nil, bundle: bundle, value: " ", comment: " ")
}
}
return finalRes
}
}
Now, this method localizedStr() will give you a localized string according to your app language. Even, if Firebase provides localized error codes(which I think it does not), it is impossible to get the error description in each language. So this is the best way I came up with. It may not be the best method out there in the world, but it does the task.
P.S.: To optimize this throughout the app, either you can create an extension to AuthErrorCode or you can create a Helper function where you will just pass the error._code and it will return the localized string. I've added the long way so that you can understand everything in the best way.

Static member 'Case Insensitive Search' cannot be used on instance of type 'NSStringCompareOptions'

In my code I have the error like CaseInsensitiveSearch in NsStringCompareOption but I don't to how to solve please help me for solve the issue, I post my code what i am tried.
var message = QBChatMessage()
let img_range = (message.text as NSString).rangeOfString("{{", options: .CaseInsensitiveSearch) ---> Error in this line.
The error message seems to be misleading, and the actual problem
is that message.text is an optional string. In that case you can
use optional chaining:
if let img_range = message.text?.rangeOfString("{{", options: .CaseInsensitiveSearch) {
print(img_range)
} else {
// message.text is `nil` or does not contain the search string
}

How can I get the description error from stripe?

I am integrating stripe in my app. The code works but I would like to get the description error and show it to user with a label in case something goes wrong (CC number not correct etc):
// other stuff here
STPAPIClient.sharedClient().createTokenWithCard(stripeCard) { (token, error) -> Void in
if let error = error {
print(error.userInfo)
}
else if let token = token {
self.createBackendChargeWithToken(token) { status in
if status == PKPaymentAuthorizationStatus.Success{
dispatch_async(dispatch_get_main_queue()){
self.paymentActivity.hidden = true
self.paymentActivity.stopAnimating()
self.paymentActivityLabel.text = "Transaction approved!"
}
}
}
}
}
}
when I print error.userInfo I get the following:
[com.stripe.lib:ErrorMessageKey: Your card number is incorrect.,
com.stripe.lib:CardErrorCodeKey: com.stripe.lib:IncorrectNumber,
com.stripe.lib:ErrorParameterKey: number,
NSLocalizedDescription: Your card's number is invalid]
How can I extrapolate NSLocalizedDescription?
An error.userInfo is usually an NSDictionary.
When you print this dictionary, there's no types like with a Swift dictionary, so the print function does not always recognize what are strings, and does not show double quotes. But your userInfo dictionary keys are still probably strings.
I would first try accessing the error value like this:
print(error.userInfo["NSLocalizedDescription"])
to verify that indeed NSLocalizedDescription is a string key.
A tip: hold ALT and CLICK on a variable, it will show you its type, it helps for quickly debugging in Xcode.

RxSwift Using Variables Correctly

I am trying to convert a project to use RxSwift and MVVM. I have a service that syncs a list of data from Parse on every app launch and I basically want to make sure I am taking the correct approach.
What I have done is made a Variable subject and then allow my models to listen to this.
ParseService:
let rx_parseMushrooms = Variable<[ParseMushroom]>([])
MushroomLibraryModel:
_ = parseService.rx_parseMushrooms
.asObservable()
.map { (parseMushrooms:[ParseMushroom]) -> [Mushroom] in
let mushrooms = parseMushrooms.map { (parseMushroom:ParseMushroom) -> Mushroom in
let mushroom = Mapper<Mushroom>().map(parseMushroom.dictionaryWithValuesForKeys(parseMushroom.allKeys()))
return mushroom!
}
return mushrooms
}
.subscribeNext({ (mushrooms:[Mushroom]) -> Void in
self.mushrooms = mushrooms
print(mushrooms)
})
I do the same for expressing the sync state.
ParseService:
struct SyncState {
enum State {
case Unsynced, ConnectingToServer, SyncingInfo, FetchingImageList, SyncingImages, SyncComplete, SyncCompleteWithError
}
var infoToSync = 0
var imagesToSync = 0
var imagesSynced = 0
var state = State.Unsynced
}
let rx_syncState = Variable(SyncState())
I then update the variable a la
self.rx_syncState.value = self.syncState
SyncViewModel:
_ = parseService.rx_syncState
.asObservable()
.subscribeNext { [weak self] (syncState:ParseService.SyncState) -> Void in
switch syncState.state {
//show stuff based on state struct
}
}
Anyways, I would greatly appreciate if someone can tell me if this is a good way of going about it or if I am misusing RxSwift (and guide me on how I should be doing this).
Cheers!
Hmm... Here is an article about using Variable (note that Variable is a wrapper around BehaviorSubject.)
http://davesexton.com/blog/post/To-Use-Subject-Or-Not-To-Use-Subject.aspx
In your case, you already have a cold observable (the network call,) so you don't need a Subject/Variable. All you need to do is publish the observable you already have and use replay(1) to cache the value. I would expect a class named something like ParseServer that contains a computed property named something like mushrooms.
To help get the mushrooms out of parse, you could use this (this will create the cold observable you need):
extension PFQuery {
var rx_findObjects: Observable<[PFObject]> {
return Observable.create { observer in
self.findObjectsInBackgroundWithBlock({ results, error in
if let results = results {
observer.on(.Next(results))
observer.on(.Completed)
}
else {
observer.on(.Error(error ?? RxError.Unknown))
}
})
return AnonymousDisposable({ self.cancel() })
}
}
}
And then you would have something like:
class ParseServer {
var mushrooms: Observable<[Mushroom]> {
return PFQuery(className: "Mushroom").rx_findObjects
.map { $0.map { Mushroom(pfObject: $0) } }
.publish()
.replay(1)
}
}
I think the above is correct. I didn't run it through a compiler though, much less test it. It might need editing.
The idea though is that the first time you call myParseServer.mushrooms the system will call Parse to get the mushrooms out and cache them. From then on, it will just return the previous cashed mushrooms.

Fetch an email body in mailcore2 OSX with swift

I try use this class: MCOIMAPFetchContentOperation for fetch body mail.
But i don't know how invoke her in swift and i don't know the arguments who are necessary.
Description of the class is: "This class implements an operation to fetch the content of a message. It can be a part or a full message."
Can you help me please !
Your question is a little vague but I assume to mean something like this :
func loadMsg(msg: MCOIMAPMessage, folder: String) {
let operation: MCOIMAPFetchContentOperation = session.fetchMessageByUIDOperationWithFolder(folder, uid: msg.uid)
operation.start { (error:NSError!, data:NSData!) -> Void in
let messageParser: MCOMessageParser = MCOMessageParser(data: data)
let msgHTMLBody: NSString = messageParser.htmlBodyRendering()
print ("HTML: \(msgHTMLBody)")
}
}