Q-municate is an open source code chat application with wide range of communication features available (such as one-to-one messaging, group chat messaging, file transfers, Facebook signup and audio/video calls). http://q-municate.com/
We are please to present you with an out of the box chat application. You can customize this application depending of your needs. QuickBlox is used for the backend http://quickblox.com
Find the source code and more information about Q-municate in our Developers section: http://quickblox.com/developers/q-municate
This description was written by the QuickBlox Web team in order to fully explain how you can build a communication javascript app with the Quickblox API.
Q-municate is designed for all developers, including beginners, as we move from simple to more complex implementation. Enjoy and please get in touch if you need any assistance.
- The web component is based on the QuickBlox platform
- The user interface is in English
- No crashes or exceptions are allowed
- The app immediately reacts to any user action or give notifications about each action which requires time to be processed
- User information is kept safely and securely.
- User's password is encoded and kept in the local storage.
- The App should work correctly in the following browsers:
- Chrome 13+
- Firefox 4+
- Opera 17+
- Safari 6.1+ (without audio, video calls)
- IE 10+ (without audio, video calls)
Q-municate is a fully fledged chat application using the Quickblox API.
Please note, in order to start using Chat 2.0, you should read the following.
- Welcome page
- Sign up page (with QM account)
- Sign up with Facebook
- Log in page (with QM account)
- Main page
- Contact list
- Chat page
- Group chat page
- Audio calls (WebRTC)
- Video calls (WebRTC)
- My profile page
- Сontact profile page
- Local Search
- Global Search
- File transfer via chat
- Chat emojes
- Icons and sound on a browser's tab
- Full screen mode for audio and video calls
Please note all these features are available in the code, so you can customize your app depending on your needs.
- Full screen mode for audio and video calls
- Improvements of calls
- Bug fixes of the chat session expiration
- My profile page
- Сontact profile page
- Retina icons
- Improvements
- Bug fixes
- Video calls (WebRTC)
- Audio calls (WebRTC)
- Call history
- Icons and sound on a browser's tab
- Bug fixes
- Backbone (Core and QB wrapper)
- Backbone (Session, User, Contact modules)
- Backbone (Contact List, Dialog modules)
- Backbone (Message, Attach modules)
- Bug fixes
- Optimization of emoji upload
- Fixed FB SDK asynchronous uploading
- Fixed cache data uploading from the Local Storage
- Optimization of css files import
- Integration of current features with mobile versions
- Bug fixes
- Welcome page
- Log in page (with QM account)
- Forgot password
- Sign up with Facebook
- Log in page (with QM account)
- Import friends from Facebook
- Main page
- Local Search
- Global Search
- Contact list
- Chat page
- Group chat page
- File transfer via chat
- Chat emojes
When user opens the App, the welcome page is shown.
- Connect with Facebook allows the user to sign up with their Facebook credentials;
- Sign Up with email opens the sign up page;
- 'Already have an account?' opens login page.
Sign up page allows to create a new QM user.
#####Fields set:
- Full name – accepts everything except '<', '>' and ';', 3-50 characters; mandatory;
- Email – should look like an email address, 3-255 characters, mandatory;
- Password – accepts everything except non-Latin characters and spaces; 8-40 character; mandatory;
- Choose user picture avatar icon- will be auto filled with selected image, if image is chosen.
- Choose user picture – all area and button is clickable. After clicking, user chooses image from the computer, not mandatory;
- Sign Up:
- If all fields are populated correctly, user receives a welcome email and is redirected to the main page.
- If some fields aren't populated correctly, the user sees the Sign Up Page with the appropriate alert and password field is cleared. The alert depends on what field user has filled in incorrectly;
- User Agreement opens the page http://q-municate.com/agreement/ in a new tab;
- Privacy Policy opens the page http://quickblox.com/privacy/ in a new tap.
User.prototype.signup = function(params, avatarFile) {
var self = this;
QB.createSession(function(err, session) {
if (session) {
Session.create({ token: session.token });
QB.users.create(params, function(err, newUser) {
if (newUser) {
delete params.full_name;
delete params.tag_list;
QB.login(params, function(err, user) {
if (user) {
Session.update({ date: new Date(), authParams: Session.encrypt(params) });
chatService.connect(user, function(roster) {
// callback
if (avatarFile) self.uploadAvatar(avatarFile);
});
}
});
}
});
}
});
};
User.prototype.uploadAvatar = function(file) {
var self = this, custom_data;
QB.content.createAndUpload({file: file, 'public': true}, function(err, blob) {
if (blob) {
custom_data = JSON.stringify({avatar_url: blob.path});
QB.users.update(self.id, {blob_id: blob.id, custom_data: custom_data}, function(err, user) {
// callback
});
}
});
};
Sign Up with Facebook allows to create QM user with the help of Facebook credentials.
Sign Up with Facebook feature creates a QM user with Facebook credentials.
If the user signs up via Facebook, they can’t log in using QM login form.
If the user signs up with Facebook - the app will download FB avatar image, full name, and email. Friends who use the App will be imported from the FB account.
FB.login(function(response) {
if (response.status === 'connected') {
User.connectFB(response.authResponse.accessToken);
}
}, {scope: QMCONFIG.fbAccount.scope});
User.prototype.connectFB = function(token) {
var self = this;
QB.createSession({provider: 'facebook', keys: {token: token}}, function(err, session) {
if (session) {
Session.create({ token: session.token });
QB.users.get(session.user_id, function(err, user) {
if (user) {
Session.update({ date: new Date(), authParams: Session.encrypt(params) });
chatService.connect(user, function(roster) {
self.import(roster);
});
}
});
}
});
};
User.prototype.import = function(roster) {
var self = this;
var isFriendsPermission = false;
FB.api('/me/permissions', function (response) {
response.data.forEach(function(item) {
if (item.permission === 'user_friends' && item.status === 'granted')
isFriendsPermission = true;
});
if (isFriendsPermission) {
FB.api('/me/friends', function (friends) {
var ids = [];
for (var i = 0, len = friends.data.length; i < len; i++) {
ids.push(friends.data[i].id);
}
if (ids.length > 0)
dialog.download(roster, ids);
else
dialog.download(roster);
});
} else {
dialog.download(roster);
}
self.updateQBUser();
});
};
User.prototype.updateQBUser = function() {
var custom_data = JSON.stringify({is_import: '1'});
QB.users.update(this.id, {custom_data: custom_data}, function(err, user) {
// callback
});
};
User can log in the app as a QM user.
- Email – text/numeric/symbolic fields 3 chars min - no border, mandatory (email symbols validation included). The user can able to paste their email address in this field if it is currently in clipboard;
- Password – text/numeric/symbolic field 8-40 chars (should contain alphanumeric and punctuation characters only) , mandatory Input symbols are replaced with *, so that the user's password is not visible. The user should be able to paste their password in this field if it is currently in the clipboard;
- Remember me – checkbox is checked by default. Allows the user to save their login data so that he/she doesn't have to enter them again if the user leaves and returns, or refreshes the page. If this checkbox is unchecked, then the user returns to the Main page of the App after refreshing the page or after closing. Login Page is shown again if the user logs out.
- Connect with Facebook button allows the user to sign up with Facebook credentials;
- Log in button allows the user to enter the App:
- If the user provides valid login credentials, they're is redirected to Main page;
- If the user provides incorrect/invalid login credentials (email and password), the App shows Log in page with alert message;
- Forgot password? link redirects the user to the Forgot password page.
User.prototype.login = function(params) {
QB.createSession(params, function(err, session) {
if (session) {
Session.create({ token: session.token });
QB.users.get(session.user_id, function(err, user) {
if (user) {
Session.update({ date: new Date(), authParams: Session.encrypt(params) });
chatService.connect(user, function(roster) {
// callback
});
}
});
}
});
};
After clicking the QM logo and Q-municate at the top left corner, the user is redirected to the Main page.
The Main page is displayed a list of user’s contact chats.
- All user contacts (online/offline/pending contact request) are displayed in the left panel in 2 sections – Recent and History (the same as in the Chats page). For each contact are shown full name, avatar image and online/offline status. The icons for statuses:
- Green icon – user is online;
- Question icon - pending contact request;
- No icon - user is offline.
- Contacts shown as a scrollable table view;
- Contact is highlighted when hovering;
- The user can click on a contact to open a chat;
- Search field;
- A version of the app is displayed at the bottom of the page;
- Search Friends button opens Global Search pop-up;
- Contacts button:
- User can create a chat with any contact;
- User can create a group chat with any contacts.
- Navigate to user’s profile or log out by clicking on the user at top right corner.
- Possible actions after right clicking a contact in the left panel:
- Video call – start a video call;
- Audio call – start an audio call;
- Add people – add people to the group chat;
- Profile – open a details page;
- Delete contact – delete from contacts.
If there is no connection to the internet, an alert message is displayed on the top section.
When connection in recovered, the alert message disappears.
// connect to chat service
ChatService.prototype.connect = function(user, callback) {
var self = this;
var password = Session.token;
QB.chat.connect({jid: self.getUserJid(user), password: password}, function(err, roster) {
if (roster) {
Session.update({ date: new Date() });
// set inner listener functions
QB.chat.onMessageListener = MessageView.onMessage;
QB.chat.onContactListListener = ContactListView.onPresence;
QB.chat.onSubscribeListener = ContactListView.onSubscribe;
QB.chat.onConfirmSubscribeListener = ContactListView.onConfirm;
QB.chat.onRejectSubscribeListener = ContactListView.onReject;
QB.webrtc.onCallListener = VideoChatView.onCall;
QB.webrtc.onAcceptCallListener = VideoChatView.onAccept;
QB.webrtc.onRejectCallListener = VideoChatView.onReject;
QB.webrtc.onStopCallListener = VideoChatView.onStop;
QB.webrtc.onUpdateCallListener = VideoChatView.onUpdateCall;
QB.webrtc.onRemoteStreamListener = VideoChatView.onRemoteStream;
callback(roster);
}
});
};
// get all dialogs
Dialog.prototype.download = function() {
QB.chat.dialog.list({sort_desc: 'last_message_date_sent'}, function(err, dialogs) {
if (dialogs) {
// callback
}
});
};
User can add or delete contacts from their contact list.
After sending a request, the user sees the following page:
When the user sends a request, they see “Your request has been sent” in the chat section, the contact is marked with “?”. The user is not able to write messages to the contact before accepting a request.
After receiving a request, the user sees the following page:
- Tick icon adds new contact to user’s contact list;
- Cross icon rejects the contact request.
// send subscribe request
var time = Math.floor(Date.now() / 1000;
QB.chat.roster.add(jid, function() {
QB.chat.send(jid, {type: 'chat', body: 'Contact request', extension: {
save_to_history: 1,
date_sent: time,
notification_type: '4'
}});
});
// send confirm answer
QB.chat.roster.confirm(jid, function() {
QB.chat.send(jid, {type: 'chat', body: 'Contact request', extension: {
save_to_history: 1,
date_sent: time,
notification_type: '5'
}});
});
// send reject answer
QB.chat.roster.reject(jid, function() {
QB.chat.send(jid, {type: 'chat', body: 'Contact request', extension: {
save_to_history: 1,
date_sent: time,
notification_type: '6'
}});
});
// delete a contact
QB.chat.roster.remove(jid, function() {
QB.chat.send(jid, {type: 'chat', body: 'Contact request', extension: {
save_to_history: 1,
date_sent: time,
notification_type: '7'
}});
});
User can chat with all contacts from their contact list.
After opening a private (one-to-one) chat, the user sees last 50 messages. He can open older history (till the first message) by scrolling.
Messages are sent after pressing Enter button.
If the user has chats with unread messages, these chats are displayed with a counter of the unread messages on the right.
The recent section displays contacts with whom the user has recently interacted with (within the last day).
- The phone icon starts an audio call;
- The video icon starts a video call;
- The plus icon allows to add contacts to a group chat;
- The profile icon opens contact’s details page;
- The delete icon opens a pop-up and allows to delete a contact from the contact list;
- The smile icon opens chat Emojes;
- The attachment icon allows to add files from the computer.
// create a private dialog
QB.chat.dialog.create({type: 3, occupants_ids: id}, function(err, dialog) {
if (dialog) {
// callback
}
});
// get all messages for dialog
Message.prototype.download = function(dialog_id, count) {
var params = {chat_dialog_id: dialog_id, sort_desc: 'date_sent', limit: 50, skip: count || 0};
QB.chat.message.list(params, function(err, messages) {
if (messages) {
// callback
}
});
};
// send message
Message.prototype.send = function(value) {
QB.chat.send(jid, {type: 'chat', body: value, extension: {
save_to_history: 1,
date_sent: Math.floor(Date.now() / 1000;
}});
};
Users can create a group chat with any or all of the contacts in their contact list.
Each member of the group chat has the same capabilities.
- Change a group chat name
- Change a group chat avatar
- Add new contacts to a chat.
- Leave a chat.
- Show/hide chat’s members.
- Start a video/audio call, write a message or open a profile page of any contact in a group chat if this contact is in the contact list. If no - user can send a request to him.
/* on creator side
---------------------------------------*/
// create the group dialog
QB.chat.dialog.create({type: 2, occupants_ids: params.ids, name: params.name}, function(err, dialog) {
if (dialog) {
// join to created room
QB.chat.muc.join(dialog.xmpp_room_jid, function() {
// send message about added people for history
QB.chat.send(dialog.room_jid, {type: 'groupchat', body: 'Notification message', extension: {
save_to_history: 1,
date_sent: Math.floor(Date.now() / 1000),
notification_type: '1',
occupants_ids: dialog.occupants_ids.join()
}});
// send notifications about adding people
for (var i = 0, len = dialog.occupants_ids.length, id, jid; i < len; i++) {
id = dialog.occupants_ids[i];
jid = QB.chat.helpers.getUserJid(id, appId); // appId - your QB application ID
QB.chat.send(jid, {type: 'chat', extension: {
notification_type: '1',
dialog_id: dialog._id,
room_jid: dialog.xmpp_room_jid,
room_name: dialog.name,
occupants_ids: dialog.occupants_ids.join()
}});
}
});
}
});
/* on recipient side
---------------------------------------*/
// receive a new message
QB.chat.onMessageListener = function(senderId, message) {
// check if this message is a notification about new room
if (message.extension && message.extension.notification_type === '1') {
// join to created room
QB.chat.muc.join(message.extension.room_jid, function() {
// callback
})
}
};
/* leave a room
---------------------------------------*/
QB.chat.send(dialog.room_jid, {type: 'groupchat', body: 'Notification message', extension: {
save_to_history: 1,
date_sent: Math.floor(Date.now() / 1000),
notification_type: '2',
deleted_id: User.id
}});
QB.chat.dialog.update(dialog.id, {pull_all: {occupants_ids: [User.id]}}, function(err, dialog) {
// callback
});
Any user with a microphone can start an audio call by clicking audio call icon in the chat section.
A call is started after allowing the application to use the microphone, and is displayed in the chat section.
- Disable camera – camera is turned off by default. Users cannot start a video call by clicking this icon;
- Mute voice – clicking this icon, user can turn on/off their microphone;
- End call – ends current call and redirects user to the Chats Page. Colour of the buttons:
- Red – a feature isn’t enabled;
- Black - a feature is enabled.
// call user
var mediaParams = {
audio: true,
video: false,
elemId: 'localStream',
options: {
muted: true
}
};
QB.webrtc.getUserMedia(mediaParams, function(err, stream) {
if (stream) {
QB.webrtc.call(params.opponent_id, 'audio', {
dialog_id: params.dialogId,
avatar: User.avatar_url,
full_name: User.full_name
});
}
});
// accept call
QB.webrtc.getUserMedia(mediaParams, function(err, stream) {
if (stream) {
QB.webrtc.accept(params.opponent_id, {
dialog_id: params.dialogId
});
}
});
// reject call
QB.webrtc.reject(params.opponent_id, {
dialog_id: params.dialogId
});
// stop call
QB.webrtc.stop(params.opponent_id, 'manually', {
dialog_id: params.dialogId
});
Any user with a webcam and a microphone can start a video call by clicking the video call icon in the chat section.
A call is started after allowing the application to use the camera and microphone, and is displayed in the chat section.
Call history is displayed in the chat section.
- Disable camera – by clicking this icon, the user can turn on/off their camera. If the user hovers over this icon when the camera is disabled, a pop-up saying “Camera is off” is displayed;
- Mute voice – clicking this icon, the user can turn on/off their microphone;
- End call – ends current call and redirects the user to the Chats page.
Colours of the buttons:
- Red – feature is disabled/not allowed;
- Black - feature is enabled.
// call user
var mediaParams = {
audio: true,
video: true,
elemId: 'localStream',
options: {
muted: true,
mirror: true
}
};
QB.webrtc.getUserMedia(mediaParams, function(err, stream) {
if (stream) {
QB.webrtc.call(params.opponent_id, 'video', {
dialog_id: params.dialogId,
avatar: User.avatar_url,
full_name: User.full_name
});
}
});
// mute webcam
QB.webrtc.mute('video');
QB.webrtc.update(params.opponent_id, {
dialog_id: params.dialogId,
mute: 'video'
});
// unmute webcam
QB.webrtc.unmute('video');
QB.webrtc.update(params.opponent_id, {
dialog_id: params.dialogId,
unmute: 'video'
});
The profile page allows the user view and edit their profile info.
- Name – allows everything except '<', '>' and ';', 3-50 characters; mandatory;
- Email – if the user has a long email, only beginning of an email is displayed (the remaining is hidden by ellipsis);
- User picture field is filled with the user's current profile photo if an image was chosen while signing up;
- Status – text/numeric/symbolic field; 0-80 characters;
- Phone – numeric/symbolic field; 0-20 characters.
- Set Profile Photo – after clicking, the user can choose an image from their computer.
- Change password – after clicking, the user can change their password;
- Add/ Edit status – the user can add or change their status (changes are saved immediately).
- Edit User name – the user can change their user name (changes are saved immediately).
- Connect - allows the user connect their QM account with Facebook account.
User.prototype.updateProfile = function(params) {
QB.users.update(this.id, params, function(err, user) {
if (user) {
// callback
}
});
};
The details page is used for contacts profile information.
Contact profile page shows the user’s information:
- Full name. If a name is very long, extra characters are hidden by ellipsis;
- Status (short text message). The full status is always displayed;
- Presence (online/offline);
- Tel. number (if filled). If a number is very long, extra characters are hidden by ellipsis.
- Video call button starts a video call with current user;
- Audio call button starts an audio call with current user;
- Message button starts a chat with current user;
- Delete contact opens the Delete user pop-up.
User.prototype.getContactProfile = function(contactId) {
QB.users.get(contactId, function(err, user) {
if (user) {
// callback
}
});
};
User can use the local search field to find contacts in their contact list.
The search is started automatically upon inputting characters. Contacts matching the search are displayed in the original order that they were located in, in the contacts list.
- Global Search - opens the Global search pop-up to find users across the whole app.
User can use the global search to find all users of Q-municate.
- The search field – allows the user input different search criteria;
- “Add” icons – allows the user send a request to any QM user.
User.prototype.getContactProfile = function(userName, page) {
QB.users.get({full_name: userName, page: page}, function(users) {
if (users) {
// callback
}
});
};
After clicking the 'attach' icon, the user can choose a file from their computer to send. User can upload any file type. An attachment is sent automatically after selecting it in the file selection dialog.
An attachment is sent as a separate message (it's not possible to send a message with an attachment). A spinner shows the upload progress.
- The user can stop uploading by clicking a Cancel button;
- The user can download a file by clicking a Download button;
- The user can play an audio or video file in the chat section;
- The user can open a full image by clicking it in the chat section. screen
Message.prototype.attach = function(file) {
var attachment;
QB.content.createAndUpload({file: file, 'public': true}, function(err, blob) {
if (blob) {
attachment = {
type: type,
url: blob.path,
name: blob.name,
size: blob.size,
'content-type': blob.content_type
};
QB.chat.send(user_jid, {type: 'chat', extension: {
attachments: [
attachment
]
}});
}
});
};
User can send an emoji by clicking the smile icon. Emojis are divided over 5 pages.
The favicon of the Q-municate tab changes with unread messages, and a sound is place upon recieving a message.
If the user recieves a message, but the QM tab isn’t open or a dialog with unread messages isn’t active – the QM tab favicon changes:
- A red dot is added to the QM icon;
- The amount of unread dialogs in brackets is added to the QM tab;
- A sound plays when a message is received.
If the QM tab is active while messages receiving, no actions are taken.
During the audio or video call user can click Extend icon to open a call in a separate window.
- Narrow icon – after clicking this icon, a call in narrowed back to the chat section;
- Mute camera – clicking this icon, user can turn on/off his camera (only for video calls);
- Mute voice – clicking this icon, user can turn on/off his microphone (for both audio and video calls);
- End call – ends current call and redirects user to the Chats Page.
If you want to build your own app using Q-municate as a base, please do the following:
- Download the project from here (GitHub)
- Run
sudo npm install -g bower
in your terminal - Run
sudo gem install compass
in your terminal - Run
sudo npm install -g grunt-cli
in your terminal - Run
bower install
to install all additional packages in your terminal - Run
sudo npm install
to install all additional packages in your terminal - Register a QuickBlox account (if you don't have one yet).
- Login to the QuickBlox admin panel
- Create a new app
- Click on the app title in the list to reveal the app's credentials:
- Create Facebook Application for ability connecting via Facebook
- Copy the credentials (App ID, Authorization key, Authorization secret) and your Facebook App ID into your Q-municate project code in
config.js
- Run
grunt build
in your terminal to build Q-municate - Run
grunt serve
in your terminal to run Q-municate
- Download nw.js dependent to your system(Win, OS X, Linux) NW.js.
- Add in 'package.json' after 'engines' section next lines:
"window": {
"toolbar": false,
"width": 1000,
"height": 800
},
"main": "app/index.html"
- Run: $ /path/to/nw . (suppose the current directory contains 'package.json'). Read more https://github.com/nwjs/nw.js#quick-start about OS X and Windows
- How to package app.