I'm using Quickblox, I uploaded users profile pic as said in the stack over flow (How to upload the Users profile pic and how to fetch that profile pic from another users device?) It's working fine for me.
Then I'm able to see the user1 profile pic in user2 contacts.(By downloading user1's blob file and converting it into image)
But now my question is, if we want to create a new chat dialog with user1, and user2 as logged in. There I should link this user1's profile pic (which is uploaded as said in the above stack over flow example) with new dialog that I'm going to create to chat with user1.
Question:1 - So How can I link this user's profile pic with newly created chat dialog especially in case of One to one chat.(Private chat).
Question:2 -And that image in chat dialog should be able to update whenever user1 has changed his profile pic (using update blob api call). As we can see in WhatsApp.
In,
Question:1
If I understood your question, when you create a dialog for two user you want to show the dialog image in dialog list of yours and dialog image should be the image of other user correct I mean user1 should see dialog image as User2 and User2 should see dialog image as User1 correct ???
If yes, buddy sorry! but the approach you are following is wrong :) Dialog's property will be same for both the user's. So if you set the dialog's image as User1, user2 will see User1 pic but User1 will also see his own image which is wrong :)
What I did to tackle is, dont use any image or name for the dialog itself unless it is a group dialog :)
Everytime you receive a QBChat
you will have occupant id's in it. In case of QBChatPrivate
messages occupant id's count will be 2 and one of them will be your own id. So removing that will give you the id of other user.
Everytime I recieve a message I'll find out the participants involved in it other than myself, and before inserting message to coredata and showing it in app, I check my coredata to find if the user exists in my local db. If user exists I'll fetch all the info about the user like his profile pic, name and everything show his profile pic and his name in list.
Else I'll download all the info about the user using his id and then insert it to db and finally insert the message to db. And now when I show it I'll follow the same procedure, show user's name his profile picture and last message in dialog list.
This gives the feel like dialog is showing the other user name and his profile picture. But in reality dialog never had any image or name for private dialog :)
Conclusion
Dont save any image or name to the ABChatDialog itself in case of private dialog :)
Question:2
Image update in WhatsApp is not just involves client logic but also includes the support from server. Unfortunately you dont have such support from server where server sends out a notification to all the clients informing about profile pic changes. Let's hope Quickblox implements it soon.
Solution
We dealt it with a simple approach, Everytime user comes to the dialog list screen, we take all the users involved in all the dialogs that are currently visible and create a seperate NSOperations for each user and get all the info including his name, image everything to keep the user updated all the time :)
In our app we have provision where user can change his name as well, so it was important for us to update the user entirely and not just his profile pic :)
all the operations run in background thread keeping main thread free and update the coredata in background.
Using NSFetchedResultsController with coredata allows us to update the username and his profile pic as soon as it is updated.
and the same process will happen when you open a specific user message as well. we fetch and update the info for that specific user as soon as you open his messages.
This involves redundant server calls and we are pretty much aware of it, but this approach keeps the user info updated all the time.
EDIT
As per your request to provide you a little bit of code :) here is a very abstract not completely working code but I believe it should give you good head start :)
Question 1: This code gives you idea of how to add user first before adding the chat itself :)
- (void)processMessage:(QBChatMessage *)message{
// processMessage method is called in background thread so creating a background managed object context for the queue. You can make use of performBlock as well
//once you recieve message check if dialog exists in your db or not
NSManagedObjectContext *privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[privateManagedObjectContext setParentContext:appdelegate.managedObjectContext];
NSFetchRequest *request=[[NSFetchRequest alloc] initWithEntityName:@"Dialog"];
NSPredicate *predicate=[NSPredicate predicateWithFormat:@"id == %@",message.dialogID];
[request setPredicate:predicate];
NSArray *results=[privateManagedObjectContext executeFetchRequest:request error:nil];
if([results count]>0){
//once dialog found for the chat
Dialog *updatedDialog=(Dialog *)[results objectAtIndex:0];
// involves is a one to many relation ship between user and dialog
NSPredicate *userExistsPredicate=[NSPredicate predicateWithFormat:@"recipient_Id = %@",[NSNumber numberWithInteger:message.senderID]];
NSArray *foundUserArray=[[updatedDialog.involves allObjects] filteredArrayUsingPredicate:userExistsPredicate];
if([foundUserArray count] > 0){
//user exists in db
//check if its a duplicate chat sometime same chat comes back specially in group chat
NSFetchRequest *request=[[NSFetchRequest alloc] initWithEntityName:@"Chats"];
NSPredicate *predicate=[NSPredicate predicateWithFormat:@"chat_Id == %@",message.ID];
[request setPredicate:predicate];
NSArray *results=[privateManagedObjectContext executeFetchRequest:request error:nil];
if([results count] ==0){
//message not in db
Chats *recievedChat=[NSEntityDescription insertNewObjectForEntityForName:@"Chats" inManagedObjectContext:privateManagedObjectContext];
recievedChat.sender_Id=[NSNumber numberWithInteger:message.senderID];
recievedChat.date_sent=message.dateSent;
recievedChat.chat_Id=message.ID;
recievedChat.belongs=updatedDialog;
recievedChat.message_Body=message.text;
//populate the way you want it
//commit background context use perform block for better performance
NSError *updateDialogError = nil;
[privateManagedObjectContext save:&updateDialogError];
dispatch_async(dispatch_get_main_queue(), ^{
//commit main context
[appdelegate.managedObjectContext save:nil];
});
}
}
else{
//fetch user not in db
[QBRequest usersWithIDs:@[[NSNumber numberWithInteger:message.senderID]] page:nil
successBlock:^(QBResponse *response, QBGeneralResponsePage *page, NSArray *users) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSManagedObjectContext *privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[privateManagedObjectContext setParentContext:appdelegate.managedObjectContext];
NSFetchRequest *request=[[NSFetchRequest alloc] initWithEntityName:@"Dialog"];
NSPredicate *predicate=[NSPredicate predicateWithFormat:@"id == %@",message.dialogID];
[request setPredicate:predicate];
NSArray *results=[privateManagedObjectContext executeFetchRequest:request error:nil];
Dialog *updatedDialog=[results objectAtIndex:0];
NSMutableArray *occupants=[[NSMutableArray alloc] init];
//create user
for(QBUUser *user in users){
if(user.ID != appdelegate.currentUser.ID){
Recipient *recipient=[NSEntityDescription insertNewObjectForEntityForName:@"Recipient" inManagedObjectContext:privateManagedObjectContext];
recipient.recipient_Name=user.fullName;
recipient.recipient_Id=[NSNumber numberWithInteger:user.ID];
[occupants addObject:recipient];
}
}
NSMutableArray *newUsersArray=[NSMutableArray arrayWithArray:[updatedDialog.involves allObjects]];
[newUsersArray addObjectsFromArray:occupants];
updatedDialog.involves=[NSSet setWithArray:newUsersArray];
NSFetchRequest *chatRequest=[[NSFetchRequest alloc] initWithEntityName:@"Chats"];
NSPredicate *chatPredicate=[NSPredicate predicateWithFormat:@"chat_Id == %@",message.ID];
[chatRequest setPredicate:chatPredicate];
NSArray *chatResults=[privateManagedObjectContext executeFetchRequest:chatRequest error:nil];
//add chat
if([chatResults count] ==0){
//add chats or messages
Chats *recievedChat=[NSEntityDescription insertNewObjectForEntityForName:@"Chats" inManagedObjectContext:privateManagedObjectContext];
recievedChat.sender_Id=[NSNumber numberWithInteger:message.senderID];
recievedChat.date_sent=message.dateSent;
recievedChat.chat_Id=message.ID;
recievedChat.belongs=updatedDialog;
recievedChat.message_Body=message.text;
}
//save context
NSError *updateDialogError = nil;
[privateManagedObjectContext save:&updateDialogError];
dispatch_async(dispatch_get_main_queue(), ^{
//commit main context
[appdelegate.managedObjectContext save:nil];
});
});
}];
}
}
}
Question 2
You dont need code for that :) Once you go through tutorials I have stated you will understand how NSOperation works :) and then simply write quickblox api inside NSOperation to download image for you :)
I hope I made my point clear. Happy coding