diff --git a/assets/css/components/calls/callWindow.css b/assets/css/components/calls/callWindow.css new file mode 100644 index 00000000..013edba7 --- /dev/null +++ b/assets/css/components/calls/callWindow.css @@ -0,0 +1,54 @@ +/** + * Calls window stylesheet + * + * @author Pierre HUBERT + */ + +.call-window { + background-color: white; + width: 300px; + height: 300px; + position: fixed; + top: 100px; + right: 10px; + z-index: 100; + border: 1px black solid; +} + + +/** + * Loading message + */ +.loading-message-container { + position: absolute; + height: inherit; + width: inherit; + display: flex; + background: 1px #0009; + flex-direction: column; + justify-content: space-around; + text-align: center; + font-size: 150%; + color: white; +} + + +/** + * Toolbar + */ +.call-toolbar { + height: 20px; + background-color: #000000b3; + color: white; + display: flex; + align-items: center; + padding-left: 10px; +} + +.call-toolbar > i:first-child { + margin-right: 6px; +} + +.call-title { + flex: 1; +} \ No newline at end of file diff --git a/assets/js/common/functionsSchema.js b/assets/js/common/functionsSchema.js index a5cf4ab3..735382c8 100644 --- a/assets/js/common/functionsSchema.js +++ b/assets/js/common/functionsSchema.js @@ -1167,6 +1167,27 @@ var ComunicWeb = { controller: { //TODO : implement }, + + /** + * Call window + */ + callWindow: { + //TODO : implement + }, + + /** + * Current calls list + */ + currentList: { + //TODO : implement + }, + + /** + * User media getter + */ + userMedia: { + //TODO : implement + }, }, /** diff --git a/assets/js/components/calls/callWindow.js b/assets/js/components/calls/callWindow.js new file mode 100644 index 00000000..6c65dd1c --- /dev/null +++ b/assets/js/components/calls/callWindow.js @@ -0,0 +1,117 @@ +/** + * Single call window management + * + * @author Pierre HUBERT + */ + +ComunicWeb.components.calls.callWindow = { + + /** + * Initialize a call + * + * @param {Object} info Information about the call to initialize + */ + initCall: function(info){ + + /** + * Initialize call object + */ + var call = { + info: info, + open: true, + window: {} + }; + + //We have to begin to draw conversation UI + var callContainer = createElem2({ + appendTo: byId("callsTarget") ? byId("callsTarget") : byId("wrapper"), //If call target is not found, add call in page wrapper + type: "div", + class: "call-window" + }); + call.window.container = callContainer; + + + //Create loading message area + call.window.loadingMessageContainer = createElem2({ + appendTo: callContainer, + type: "div", + class: "loading-message-container", + innerHTML: "" + }); + + call.window.loadingMessageContainer = createElem2({ + appendTo: call.window.loadingMessageContainer, + type: "div", + class: "message", + innerHTML: "Loading..." + }); + + /** + * Set loading message visiblity + * + * @param {Boolean} visible TRUE to make it visible / FALSE else + */ + call.setLoadingMessageVisibility = function(visible){ + call.window.loadingMessageContainer.style.display = visible ? "flex" : "none"; + } + + /** + * Update call loading message + * + * @param {String} message The new message to show to the + * users + */ + call.setLoadingMessage = function(message){ + call.window.loadingMessageContainer.innerHTML = message; + } + + + //Add toolbar + call.window.toolbar = createElem2({ + appendTo: callContainer, + type: "div", + class: "call-toolbar", + innerHTML: "" + }); + + //Call title + call.window.title = createElem2({ + appendTo: call.window.toolbar, + type: "div", + class: "call-title", + innerHTML: "Loading..." + }); + + /** + * Update the title of the call + */ + call.setTitle = function(title){ + call.window.title.innerHTML = title; + } + + //Add close button + call.window.closeButton = createElem2({ + appendTo: call.window.toolbar, + type: "button", + class: "btn btn-box-tool close-btn", + innerHTML: "" + }); + + + //Get information about related conversation to get the name of the call + ComunicWeb.components.conversations.interface.getInfosOne(info.conversation_id, function(conv_info){ + + if(conv_info.error) + return notify("Could not get information about related conversation!", "danger"); + + ComunicWeb.components.conversations.utils.getName(conv_info, function(name){ + call.setTitle(name); + }) + + }, false); + + //Load user media + call.setLoadingMessage("Waiting for your microphone and camera..."); + } + +} \ No newline at end of file diff --git a/assets/js/components/calls/controller.js b/assets/js/components/calls/controller.js index 89ee9fcb..a5fad5dc 100644 --- a/assets/js/components/calls/controller.js +++ b/assets/js/components/calls/controller.js @@ -42,6 +42,33 @@ ComunicWeb.components.calls.controller = { }); }); + + // Each time a page is opened, wec check if we have to create calls target + document.addEventListener("openPage", function(){ + + //Signed out users can not make calls + if(!signed_in()) + return; + + //Need a wrapper to continue + if(!byId("wrapper")) + return; + + //Check if calls target already exists + if(byId("callsTarget")) + return; + + //Call system must be available + if(!ComunicWeb.components.calls.controller.isAvailable()) + return; + + //Create call target + createElem2({ + appendTo: byId("wrapper"), + type: "div", + id: "callsTarget" + }); + }); }, /** @@ -65,6 +92,28 @@ ComunicWeb.components.calls.controller = { //Read configuration return this.getConfig().enabled; - } + }, + /** + * Initiate a call for a conversation + * + * @param {Number} conversationID The ID of the target conversation + */ + call: function(conversationID){ + + //Create / Get call information for the conversation + ComunicWeb.components.calls.interface.createForConversation(conversationID, function(call){ + + if(call.error) + return notify("Could not get a call for this conversation!", "danger"); + + //Add the call to the list of opened calls + ComunicWeb.components.calls.currentList.addCallToList(call.id); + + //Initialize call + ComunicWeb.components.calls.callWindow.initCall(call); + + }); + + } } \ No newline at end of file diff --git a/assets/js/components/calls/currentList.js b/assets/js/components/calls/currentList.js new file mode 100644 index 00000000..50828e32 --- /dev/null +++ b/assets/js/components/calls/currentList.js @@ -0,0 +1,69 @@ +/** + * Currents calls list management + * + * @author Pierre HUBERT + */ + +ComunicWeb.components.calls.currentList = { + + /** + * This variable contains the name of the session storage + * variable that contains active calls + */ + _local_storage_list_calls_name: "current-calls", + + + /** + * Get the list of active calls + * + * @return {number[]} The list of calls + */ + getCurrentCallsList: function(){ + var string = localStorage.getItem(this._local_storage_list_calls_name); + + if(string === null || string == "") + return []; + else + return string.split(","); + }, + + /** + * Save a new list of calls + * + * @param {number[]} list The new list of calls to save + */ + saveNewCallsList: function(list){ + localStorage.setItem(this._local_storage_list_calls_name, list.join(",")); + }, + + /** + * Add a call to the list of opened call + * + * @param {number} id The ID of the call to add + */ + addCallToList: function(id){ + let list = this.getCurrentCallsList(); + + if(!list.includes(""+id)) + list.push(id); + + this.saveNewCallsList(list); + }, + + /** + * Remove a call from the list of calls + * + * @param {Number} id The ID of the call to remove + */ + removeCallFromList: function(id){ + + let list = this.getCurrentCallsList(); + + while(list.includes(""+id)) + list.splice(list.indexOf(""+id), 1); + + this.saveNewCallsList(list); + + }, + +} \ No newline at end of file diff --git a/assets/js/components/calls/interface.js b/assets/js/components/calls/interface.js index 590a0a23..08ef8ea6 100644 --- a/assets/js/components/calls/interface.js +++ b/assets/js/components/calls/interface.js @@ -14,6 +14,22 @@ ComunicWeb.components.calls.interface = { */ getConfig: function(callback){ ComunicWeb.common.api.makeAPIrequest("calls/config", {}, true, callback); - } + }, + /** + * Create a call for a conversation + * + * @param {Number} convID The ID of the target conversation + * @param {function} callback + */ + createForConversation : function(convID, callback){ + ComunicWeb.common.api.makeAPIrequest( + "calls/createForConversation", + { + conversationID: convID + }, + true, + callback + ); + } } \ No newline at end of file diff --git a/assets/js/components/calls/userMedia.js b/assets/js/components/calls/userMedia.js new file mode 100644 index 00000000..1bf6358a --- /dev/null +++ b/assets/js/components/calls/userMedia.js @@ -0,0 +1,43 @@ +/** + * User media getter + * + * @author Pierre HUBERT + */ + +ComunicWeb.components.calls.userMedia = { + + /** + * Pointer on current user media + */ + _currMedia: undefined, + + /** + * Get user media + * + * @return {Promise} A promise to get user media + */ + get: function(){ + + //Check if we have already got user media + if(this._currMedia != undefined && this._currMedia.active) + return new Promise(function(resolve, error){ + resolve(ComunicWeb.components.calls.userMedia._currMedia); + }); + + //Use latest API + return navigator.mediaDevices + + //Request user media + .getUserMedia({ + audio: true, + video: true + }) + + //Save stream + .then(function(stream){ + ComunicWeb.components.calls.userMedia._currMedia = stream; + return stream; + }); + } + +} \ No newline at end of file diff --git a/assets/js/components/conversations/chatWindows.js b/assets/js/components/conversations/chatWindows.js index f4a008fa..c4494620 100644 --- a/assets/js/components/conversations/chatWindows.js +++ b/assets/js/components/conversations/chatWindows.js @@ -594,6 +594,9 @@ ComunicWeb.components.conversations.chatWindows = { }); conversation.box.callButton = button; + button.addEventListener("click", function(){ + ComunicWeb.components.calls.controller.call(conversation.infos.ID); + }); }, diff --git a/system/config/dev.config.php b/system/config/dev.config.php index 1f5571a4..f5e0ef3b 100644 --- a/system/config/dev.config.php +++ b/system/config/dev.config.php @@ -218,6 +218,9 @@ class Dev { //Incognito mode component "css/components/incognito/ui.css", + //Calls component + "css/components/calls/callWindow.css", + //Pacman (easter egg) stylesheet "css/components/pacman.css", @@ -440,6 +443,9 @@ class Dev { //Calls compontent "js/components/calls/interface.js", "js/components/calls/controller.js", + "js/components/calls/callWindow.js", + "js/components/calls/currentList.js", + "js/components/calls/userMedia.js", //Pacman component (easter egg) "js/components/pacman.js",