I downloaded TigerText Demo app from here and I opened it in xcode but its a huge app I just need conversation part or that single viewcontorller no need of login because I will pass that hard coded like this.
[[TTKit sharedInstance] loginWithUserId:#"username" password:#"password"
success:^(TTUser *user) {
// Handle login.
} failure:^(NSError *error) {
// Handle failure.
}];
After that there will be only one view where users will see there msgs. no login and not organization views required.
To display messages in 'ConversationViewController' you will first need a TTRosterEntry object (An object that represents a conversation), if you would like to load all TTRosterEntry objects regardless of their organization you can use this api
NSFetchedResultsController *frc = [[TTKit sharedInstance] rosterFetchControllerForAllOrganizationsWithDelegate:self];
NSArray *rostersForAllOrganizations = [frc fetchedObjects];
Once you select a roster you can load 'ConversationViewController'
ConversationViewController *conversation = [GetAppDelegate.storyboard instantiateViewControllerWithIdentifier:#"ConversationViewController"];
conversation.rosterEntry = rosterEntry;
[self.navigationController pushViewController:conversation animated:YES];
Related
I want to implement a functionality in a chat app by which user will be able to search a group by its unique provided code. I have used quickblox for implementing chat functionality. so please provide me a way to do that functionality with quickblox.
Please check official Document of Quickchat .
SimpleSample-chat_users-ios
They have mention all the detail in their document.
Moreover , Just Download the demo and try to implement.
Group_chat
Before implement Group chat don't forget to read typical setting section.
Typical settings [Functionality in Groupchat]
Authentication: Chat history: you may wish to keep
the archive of all public discussion history which is easily supported
by QuickBlox. Some platforms will also require you to implement abuse
and moderation mechanisms which are also supported both via API and
admin panel. File attachments: typically attachments are not supported
1:1 / IM chat: in many applications you may wish to allow users start
a private communication with other user Friending: QuickBlox supports
friending or adding other users to favourites which you may use in
your application - see also [chat: friending / favourite users lists]
start groupchat with creating Dialogue.
Create_new_group_chat_dialog
QBChatDialog *chatDialog = [[QBChatDialog alloc]
initWithDialogID:null type:QBChatDialogTypeGroup];
chatDialog.name = #"Chat with Bob, Sam, Garry"; //set according to requirement
chatDialog.occupantIDs = #[#(55), #(678), #(22)];
[QBRequest createDialog:chatDialog successBlock:^(QBResponse *response, QBChatDialog *createdDialog) {
} errorBlock:^(QBResponse *response) {
}];
Second step --> Create chatnotification
- (QBChatMessage *)createChatNotificationForGroupChatCreation:(QBDialog *)dialog
{
// create message:
QBChatMessage *inviteMessage = [QBChatMessage message];
NSMutableDictionary *customParams = [NSMutableDictionary new];
customParams[#"xmpp_room_jid"] = dialog.roomJID;
customParams[#"name"] = dialog.name;
customParams[#"_id"] = dialog.ID;
customParams[#"type"] = #(dialog.type);
customParams[#"occupants_ids"] = [dialog.occupantIDs componentsJoinedByString:#","];
// Add notification_type=1 to extra params when you created a group chat
//
customParams[#"notification_type"] = #"1";
inviteMessage.customParameters = customParams;
return inviteMessage;
}
...
for (NSString *occupantID in dialog.occupantIDs) {
QBChatMessage *inviteMessage = [self createChatNotificationForGroupChatCreation:dialog];
NSTimeInterval timestamp = (unsigned long)[[NSDate date] timeIntervalSince1970];
customParams[#"date_sent"] = #(timestamp);
// send notification
//
inviteMessage.recipientID = [occupantID integerValue];
[[QBChat instance] sendSystemMessage:inviteMessage completion:^(NSError * _Nullable error) {
}];
}
You will receive opponent in this delegate .
- (void)chatDidReceiveSystemMessage:(QBChatMessage *)message
{
}
You can implement required functionality in group-chat with abolve link.
Like , Get online users ,Leave group chat dialog , Attachment in group. etc.
I am using Azure Mobile Service as a backend for an iOS application. I have set up everything to work with offline sync which allows me to view, add, or modify data even when there is no network connection. I am running into a problem when I add a new object into a table. The add works well locally but when I synchronize data it creates a duplicate item on the local database with a slightly different objectId. The created item is not duplicated on the server side.
Here's how I am setup. By the way, thanks to #TheBasicMind for posting this model.
Here's a link to his explanation of the model: enter link description here
Here's what I do to setup the sync context and sync table:
// Initialize the Mobile Service client with your URL and key
MSClient *client = self.hpc.client;
NSManagedObjectContext *context = self.hpc.syncContext;
MSCoreDataStore *store = [[MSCoreDataStore alloc] initWithManagedObjectContext:context];
client.syncContext = [[MSSyncContext alloc] initWithDelegate:syncDelegate dataSource:store callback:nil];
// Add a Mobile Service filter to enable the busy indicator
self.client = [client clientWithFilter:self];
// Create an MSSyncTable instance to allow us to work with the Athlete table
self.syncAthleteTable = [self.client syncTableWithName:#"Athlete"];
Here's how I add a record for the moment:
NSDictionary *newItem = #{#"firstname": firstname, #"lastname": lastname, #"laterality" : laterality};
[self.athletesService addItem:newItem completion:^{
NSLog(#"New athlete added");
}];
-(void)addItem:(NSDictionary *)item completion:(CompletionBlock)completion
{
// Insert the item into the Athlete table
[self.syncAthleteTable insert:item completion:^(NSDictionary *result, NSError *error)
{
[self logErrorIfNotNil:error];
// Let the caller know that we finished
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}];
}
The add works as expected and it is added in a UITableView as I have an NSFetchedResultsController listening on my Main Context.
Here's where the problem occurs. When I synchronize data with the server using this function:
-(void)syncData:(CompletionBlock)completion
{
// push all changes in the sync context, then pull new data
[self.client.syncContext pushWithCompletion:^(NSError *error) {
[self logErrorIfNotNil:error];
[self pullData:completion];
}];
}
-(void)pullData:(CompletionBlock)completion
{
MSQuery *query = [self.syncAthleteTable query];
// Pulls data from the remote server into the local table.
// We're pulling all items and filtering in the view
// query ID is used for incremental sync
[self.syncAthleteTable pullWithQuery:query queryId:#"allAthletes" completion:^(NSError *error) {
[self logErrorIfNotNil:error];
[self refreshDataOnSuccess:completion];
}];
}
- (void) refreshDataOnSuccess:(CompletionBlock)completion
{
MSQuery *query = [self.syncAthleteTable query];
[query readWithCompletion:^(MSQueryResult *results, NSError *error) {
[self logErrorIfNotNil:error];
NSLog(#"Data that pulled from local store: ");
for ( NSDictionary *dict in results.items ) {
NSLog(#"%# %#", [dict objectForKey:#"firstname"], [dict objectForKey:#"lastname"] );
}
// Let the caller know that we finished
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}];
}
After the synchronization the NSFetchedResultsChangeInsert is called a second time for the same record with a slightly different objectID. Here's an example of the first and second objectIDs:
tD7ADE77E-0ED0-4055-BAF6-B6CF8A6960AE9
tD7ADE77E-0ED0-4055-BAF6-B6CF8A6960AE11
I am stuck here.
Any help is highly appreciated. Thank you!
In the past, when I've seen this happen, its because the "id" field the client is sending was being changed or ignored by the server logic.
Locally the store finds the object in core data using that field, so a change to it could result in the client SDK thinking it needs to insert a new object and not update an existing one.
One easy way to confirm this, is by using the tableOperation:complete: method on the data delegate and comparing the "id" column between the item originally and that being returned by operation execute.
I am using Azure Mobile Service as a backend for an iOS app. I have set up everything to work with offline sync which allows me to view, add, or modify data even when there is no network connection. I am now into testing and I run into an error: "The item provided was not valid" when I try to synchronize data.
Here's what I am doing:
I add a new athlete to the syncTableWithName:#"Athlete" with this:
NSDictionary *newItem = #{#"firstname": #"Charles", #"lastname": #"Lambert", #"laterality" : #"Orthodox"};
[self.athletesService addItem:newItem completion:^{
NSLog(#"New athlete added");
}];
Here's the addItem function:
-(void)addItem:(NSDictionary *)item completion:(CompletionBlock)completion
{
// Insert the item into the Athlete table
[self.syncTable insert:item completion:^(NSDictionary *result, NSError *error)
{
[self logErrorIfNotNil:error];
// Let the caller know that we finished
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}];
}
For now everything is fine and the item is in the syncTable. The problem is when I try to synchronize with the Azure Mobile Service. Here's the syncData function I am calling:
-(void)syncData:(CompletionBlock)completion
{
// push all changes in the sync context, then pull new data
[self.client.syncContext pushWithCompletion:^(NSError *error) {
[self logErrorIfNotNil:error];
[self pullData:completion];
}];
}
The pushWithCompletion gets me the error: "The item provided was not valid." and same for the pullData function that gets called after:
-(void)pullData:(CompletionBlock)completion
{
MSQuery *query = [self.syncTable query];
// Pulls data from the remote server into the local table.
// We're pulling all items and filtering in the view
// query ID is used for incremental sync
[self.syncTable pullWithQuery:query queryId:#"allAthletes" completion:^(NSError *error) {
[self logErrorIfNotNil:error];
// Let the caller know that we finished
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}];
}
I have tried inserting directly in the MSTable and that works fine. It's really when I am using the MSSyncTable that I run into this error. Although when I insert data manually in my database and that I synchronize my context I can fetch data and display within my UITableView.
Lookin forward to see what you guys think about this. Thanks a lot!
I just edited my question thanks to #phillipv.
When I add an item using NSDictionary just like I did I run into the error "The item provided was not valid". So I tried adding an item by first inserting it to my managedObjectContext and then calling:
NSDictionary *dict = [MSCoreDataStore tableItemFromManagedObject:newAthlete];
I then I get the error when I try to sync: "The item provided did not have a valid id."
I feel like I am experiencing a circle.. :S
#Charley14, you can work around the bug by adding the following handler.
- (void)tableOperation:(nonnull MSTableOperation *)operation onComplete:(nonnull MSSyncItemBlock)completion
{
NSMutableDictionary *rwItem = [NSMutableDictionary dictionaryWithDictionary:operation.item];
// Temporary workaround
[rwItem removeObjectsForKeys:#[ #"relationship1", #"relationship2"]];
operation.item = rwItem;
[operation executeWithCompletion:completion];
}
The tableOperation:onComplete: handler is simply removing keys that correspond to the relationships. You will have to replace 'relationship1', 'relationship2' in the code snippet with names of actual relationships in your application.
Once the bug (https://github.com/Azure/azure-mobile-services/issues/779) is fixed, this workaround can be removed.
This appears to be a bug in the iOS SDK, as the Many to One relationship is not supposed to be exposed in the object given to the operation during a Push call.
Created the following bug with more details on GitHub: https://github.com/Azure/azure-mobile-services/issues/779
The cause of the error message is due to the fact that the relationship is a NSSet on the object, and the NSJSONSerializer throws as it does not know how to convert that to JSON.
I’m testing code based on the firechat-ios example. I’ve added the FirebaseSimpleLogin call loginToFacebookAppWithId and have it set up so that one view controller performs the login and then transitions to a different view controller that holds the chat logic:
self.firebase = [[Firebase alloc] initWithUrl:#"https://xxxxx.firebaseio.com/"];
[self observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
NSLog(#"%#", snapshot.value);
// Add the chat message to the array.
[self.chat addObject:snapshot.value];
// Reload the table view so the new message will show up.
[self.tableView reloadData];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}];
FirebaseSimpleLogin *authClient = [[FirebaseSimpleLogin alloc] initWithRef:self.firebase];
[authClient loginToFacebookAppWithId:kFacebookAppID permissions:#[#"email"]
audience:ACFacebookAudienceOnlyMe
withCompletionBlock:^(NSError *error, FAUser *user) {
if (error != nil) {
// There was an error logging in
NSLog(#"facebook error");
} else {
// We have a logged in facebook user
NSLog(#"facebook logged in");
[authClient checkAuthStatusWithBlock:^(NSError* error, FAUser* user) {
if (error != nil) {
// Oh no! There was an error performing the check
NSLog(#"auth error");
} else if (user == nil) {
// No user is logged in
NSLog(#"auth not logged in");
} else {
// There is a logged in user
NSLog(#"auth logged in");
// segue to the chat view controller
[self performSegueWithIdentifier:#"segueToViewController" sender:self];
}
}];
}
}];
Here are the firebase rules:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
The problem is, about 10% of the time, the UITableView of the chat messages is blank, and I don’t see any chat message entries in the log. I’ve tried playing around with the order of observeEventType, putting it before and after the loginToFacebookAppWithId call.
I’m wondering if there is a race condition where maybe the messages are arriving before I call observeEventType. I’ve checked the return value of observeEventType and I get a FirebaseHandle of 1 even when no messages arrive. I’ve also upgraded the firebase framework that comes with firechat ios to https://cdn.firebase.com/ObjC/Firebase.framework-LATEST.zip and it still fails.
I thought that maybe the connection dropped, but I’m able to post messages with childByAutoId after I’ve authenticated and see them appear on the firebase server. I just never receive any messages.
I wonder if it’s trying to send me the messages in the brief moment before I’m authenticated, and failing because I don’t have read permission. Is there a way to delay event observations until after I’m in?
I’ve tried everything I can think of but I can’t make it work reliably.
---------- UPDATE ----------
I seem to be able to log in every time if I type my credentials manually. I'm currently checking for a previous successful login with:
[FBSession openActiveSessionWithAllowLoginUI:false]
To determine if I successfully logged in on the last launch of the app. If it fails, I go to a view controller for FirebaseSimpleLogin. But if it works, I call FirebaseSimpleLogin in the current view controller and wait till it succeeds in the background.
I'm running in the simulator, so I tried deleting the preferences plist at:
~/Library/Application Support/iPhone Simulator/7.0.3/Applications/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/Library/Preferences/com.xxxxxxxxxx.plist
and relaunching, which forces me to re-authenticate. Then I tried typing in my credentials and logging in 25 times without a problem.
So I think the problem is either somehow related to trying to login with Facebook before I use FirebaseSimpleLogin, or logging in with credentials from the previous launch (without bringing up the login dialog). I'm still trying to narrow down the culprit.
---------- UPDATE 2 ----------
I just wanted to add a note that after further testing, I found that the call to:
[FBSession openActiveSessionWithAllowLoginUI:false]
has no effect on FirebaseSimpleLogin. If I skip that call altogether and simply substitute true or false there, I can reproduce the issue. The problem turned out to be a race condition, see my answer below.
I finally figured out what was happening, it was due a wrong assumption on my part about UIViewController message callbacks and CFRunLoop.
The code sample in my question was distilled down from my real code to remove extraneous calls, but it turns out the part I removed was actually the culprit. I had written a function to log in and wait until success or failure on the spot (rather than receiving the response in a block later) by using a run loop:
-(bool)loginUsingFacebookReturningError:(NSError**)error andUser:(FAUser**)user
{
__block NSError *errorTemp;
__block FAUser *userTemp;
[self loginUsingFacebookWithCompletionBlock:^(NSError *error, FAUser *user) {
errorTemp = error;
userTemp = user;
CFRunLoopStop(CFRunLoopGetCurrent());
}];
CFRunLoopRun(); // needs a timeout or way for the user to cancel but I haven't implemented it yet
if(error) *error = errorTemp;
if(user) *user = userTemp;
return !errorTemp && userTemp;
}
-(void)loginUsingFacebookWithCompletionBlock:(void (^)(NSError* error, FAUser* user))block
{
FirebaseSimpleLogin *authClient = [[FirebaseSimpleLogin alloc] initWithRef:self.firebase];
[authClient loginToFacebookAppWithId:kFacebookAppID permissions:#[#"email"]
audience:ACFacebookAudienceOnlyMe
withCompletionBlock:^(NSError *error, FAUser *user) {
if (error != nil) {
// There was an error logging in
NSLog(#"facebook error");
block(error, nil);
} else {
// We have a logged in facebook user
NSLog(#"facebook logged in");
[authClient checkAuthStatusWithBlock:block];
}
}];
}
This was called with:
NSError *error;
FAUser *user;
bool success = [self loginUsingFacebookReturningError:&error andUser:&user];
The way loginUsingFacebookReturningError works is, it calls loginUsingFacebookWithCompletionBlock which fires off the loginToFacebookAppWithId and checkAuthStatusWithBlock messages like usual, but then I start a run loop. The run loop allows processing to happen in the background, even though the main thread pauses on CFRunLoopRun() until the completion block calls CFRunLoopStop().
What I hadn't realized is that run loops continue to process the application's messages in the background. So while I thought program flow had stopped in viewDidLoad, it had actually continued and called viewWillAppear, which is where I had placed my call to observeEventType (because I assumed that authentication would be complete by the time the program got there).
This created a race condition where the program attached the observeEventType callback during the time that Facebook and Firebase were authenticating. 90% of the time, authentication had completed before observeEventType was called, but 10% of the time there was lag or other network delays and observeEventType was called prematurely.
I fixed the problem by moving the FirebaseSimpleLogin code to its own view controller in the storyboard, and using the completion block to initiate the segue to the next view controller, which installed the observeEventType callback.
So to summarize: the solution is to call FirebaseSimpleLogin's authentication, and then AFTER it has finished and the completion block is done, call observeEventType. Otherwise Firebase's rules will deny your request to see data that's only visible to authenticated users (which is correct).
Here is the final code, untested but the method works:
// only global for illustration purposes, should really go in a singleton or AppDelegate, or be passed through the segue to the next view controller
Firebase *gFirebase;
// LoginViewController (root view controller in storyboard)
- (void)viewDidLoad
{
[super viewDidLoad];
gFirebase = [[Firebase alloc] initWithUrl:#"https://xxxxx.firebaseio.com/"];
FirebaseSimpleLogin *authClient = [[FirebaseSimpleLogin alloc] initWithRef:gFirebase];
[authClient loginToFacebookAppWithId:kFacebookAppID permissions:#[#"email"]
audience:ACFacebookAudienceOnlyMe
withCompletionBlock:^(NSError *error, FAUser *user) {
if (error != nil) {
// There was an error logging in
NSLog(#"facebook error");
} else {
// We have a logged in facebook user
NSLog(#"facebook logged in");
[authClient checkAuthStatusWithBlock:^(NSError* error, FAUser* user) {
if (error != nil) {
// Oh no! There was an error performing the check
NSLog(#"auth error");
} else if (user == nil) {
// No user is logged in
NSLog(#"auth not logged in");
} else {
// There is a logged in user
NSLog(#"auth logged in");
// segue to the chat view controller
[self performSegueWithIdentifier:#"segueToViewController" sender:self];
}
}];
}
}];
}
// ViewController (destination of segueToViewController)
- (void)viewDidLoad
{
[super viewDidLoad];
[gFirebase observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
NSLog(#"%#", snapshot.value);
// Add the chat message to the array.
[self.chat addObject:snapshot.value];
// Reload the table view so the new message will show up.
[self.tableView reloadData];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}];
}
I'm trying to insert a "Moment" into a user's Google+ account, using the google-api-objectivec-client library. I think have the authentication process working properly. It's primarily the same way I have YouTube authentication set up, but with the correct scope and keychain name. However, when I try to run the query to insert the moment I get the following error:
Error Domain=com.google.GTLJSONRPCErrorDomain Code=401 "The operation
couldn’t be completed. (Unauthorized)"
After looking at Google's documentation more carefully (here) I found the following comment:
When authenticating for moments.insert, you must include the data-requestvisibleactions
parameter to specify which types of App Activities your application will write.
Google has several examples of how to do this with other programming languages, but they don't have any examples for the objective-c library, and the objective-c project doesn't contain any examples of how to do this either.
I know that there's another authentication method, using the GPPSignIn button, which has a way to set the actions. However, my application is using multiple other Google API clients (YouTube, YouTube Analytics, and URL Shortener). Mixing the GoogleOpenSource.framework with the other Objective-C libraries causes a conflict. So, I need to use the GTMOAuth2ViewControllerTouch class.
My Authentication Code
GTMOAuth2ViewControllerTouch *viewController =
[GTMOAuth2ViewControllerTouch controllerWithScope:kGTLAuthScopePlusLogin
clientID:kGoogleApiClientId
clientSecret:kGoogleApiClientSecret
keychainItemName:kGooglePlusKeychainName
completionHandler:^(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error) {
if (error)
NSLog(#"Error: %#", error.description);
else
app.googlePlusService.authorizer = auth; //this sets a property of my app delegate, to be used elsewhere in the application
}];
[self.navigationController pushViewController:viewController animated:YES];
The code I'm using to insert the "Moment"
NSString *shareUrl = "http://www.google.com"; //just for this example
GTLPlusMoment *moment = [[GTLPlusMoment alloc] init];
moment.type = #"http://schemas.google.com/AddActivity";
GTLPlusItemScope *target = [[GTLPlusItemScope alloc] init];
target.url = shareUrl;
moment.target = target;
GTLQueryPlus *query =
[GTLQueryPlus queryForMomentsInsertWithObject:moment
userId:#"me"
collection:kGTLPlusCollectionVault];
[app.googlePlusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
id object,
NSError *error) {
if (error) {
NSLog(#"Got bad response from plus.moments.insert: %#", error);
} else {
NSLog(#"Moment inserted: %#",moment.identifier);
}
}];
Has anyone out there successfully found the place to add the data-requestvisibleactions parameter to either the authentication call or queryForMomentsInsertWithObject method to allow them to execute the moments.insert action without receiving an error?
Thanks!
You can add data-requestvisibleactions using Java Script code in Authentication. Once you authorized with java script, it will be authorized for all types of insert moments. There is no method in Objective c for adding data-requestvisibleactions in your code. Only the option is possible through Java Script.
For More derails Refer THIS