From a905094d4d3556341d285ccd72bbe221b9945101 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Mon, 14 Dec 2015 02:28:13 -0500 Subject: [PATCH] inviting, joining, and leaving conversations --- app/assets/javascripts/src/Metamaps.js.erb | 113 +++++++++++------- .../javascripts/src/views/chatView.js.erb | 30 ++++- app/assets/javascripts/src/views/room.js | 40 +++---- app/assets/stylesheets/clean.css.erb | 8 ++ app/assets/stylesheets/junto.css.erb | 30 ++++- realtime/realtime-server.js | 4 + 6 files changed, 151 insertions(+), 74 deletions(-) diff --git a/app/assets/javascripts/src/Metamaps.js.erb b/app/assets/javascripts/src/Metamaps.js.erb index 59e701f4..f22d824e 100644 --- a/app/assets/javascripts/src/Metamaps.js.erb +++ b/app/assets/javascripts/src/Metamaps.js.erb @@ -1915,8 +1915,10 @@ Metamaps.Realtime = { webrtc: null, readyToCall: false, mappersOnMap: {}, + chatOpen: false, status: true, // stores whether realtime is True/On or False/Off, broadcastingStatus: false, + inConversation: false, localVideo: null, init: function () { var self = Metamaps.Realtime; @@ -1927,19 +1929,10 @@ Metamaps.Realtime = { var turnOff = function () { self.turnOff(); }; - var toggleVideo = function () { - self.toggleVideo(); - }; $(".rtOn").click(reenableRealtime); $(".rtOff").click(turnOff); - $(".startVideo").click(toggleVideo); - $(document).on(Metamaps.Views.chatView.events.openTray, function () { - $('.main').addClass('compressed'); - }); - $(document).on(Metamaps.Views.chatView.events.closeTray, function () { - $('.main').removeClass('compressed'); - }); + self.addJuntoListeners(); var railsEnv = $('body').data('env'); var whichToConnect = railsEnv === 'development' ? self.stringForLocalhost : self.stringForHeroku; @@ -1995,7 +1988,34 @@ Metamaps.Realtime = { self.createChat(); } // if Metamaps.Active.Mapper }, - handleVideoAdded: function (v) { + addJuntoListeners: function () { + var self = Metamaps.Realtime; + + $(document).on(Metamaps.Views.chatView.events.openTray, function () { + $('.main').addClass('compressed'); + self.chatOpen = true; + self.positionPeerIcons(); + }); + $(document).on(Metamaps.Views.chatView.events.closeTray, function () { + $('.main').removeClass('compressed'); + self.chatOpen = false; + self.positionPeerIcons(); + }); + $(document).on(Metamaps.Views.chatView.events.videosOn, function () { + $('#wrapper').removeClass('hideVideos'); + }); + $(document).on(Metamaps.Views.chatView.events.videosOff, function () { + $('#wrapper').addClass('hideVideos'); + }); + $(document).on(Metamaps.Views.chatView.events.cursorsOn, function () { + $('#wrapper').removeClass('hideCursors'); + }); + $(document).on(Metamaps.Views.chatView.events.cursorsOff, function () { + $('#wrapper').addClass('hideCursors'); + }); + }, + handleVideoAdded: function (v, id) { + var self = Metamaps.Realtime; // random position for now var top = Math.floor((Math.random() * ($('#wrapper').height() - 100)) + 1); var left = Math.floor((Math.random() * ($('#wrapper').width() - 100)) + 1); @@ -2006,6 +2026,9 @@ Metamaps.Realtime = { top: top + 'px', left: left + 'px' }); + v.$container.find('.video-cutoff').css({ + border: '2px solid ' + self.mappersOnMap[id].color + }); }, startActiveMap: function () { var self = Metamaps.Realtime; @@ -2069,7 +2092,23 @@ Metamaps.Realtime = { var notifyText = 'There\'s a conversation happening, want to join?'; notifyText += ' '; notifyText += ' '; - Metamaps.GlobalUI.notifyUser(notifyText); + Metamaps.GlobalUI.notifyUser(notifyText, true); + self.room.conversationInProgress(); + }, + conversationHasBegun: function () { + var self = Metamaps.Realtime; + + if (self.inConversation) return; + var notifyText = 'There\'s a conversation starting, want to join?'; + notifyText += ' '; + notifyText += ' '; + Metamaps.GlobalUI.notifyUser(notifyText, true); + self.room.conversationInProgress(); + }, + conversationHasEnded: function () { + var self = Metamaps.Realtime; + + self.room.conversationEnding(); }, invitedToCall: function (inviter) { var self = Metamaps.Realtime; @@ -2078,7 +2117,7 @@ Metamaps.Realtime = { var notifyText = username + ' is suggesting a video call. What do you think?'; notifyText += ' '; notifyText += ' '; - Metamaps.GlobalUI.notifyUser(notifyText); + Metamaps.GlobalUI.notifyUser(notifyText, true); }, acceptCall: function (userid) { var self = Metamaps.Realtime; @@ -2133,38 +2172,16 @@ Metamaps.Realtime = { } self.room.join(); }); + self.inConversation = true; self.webrtc.startLocalVideo(); Metamaps.GlobalUI.clearNotify(); }, - startVideo: function() { - var - self = Metamaps.Realtime; + leaveCall: function () { + var self = Metamaps.Realtime; - if (!self.videoInitialized) { - self.webrtc.startLocalVideo(); - } - else { - self.webrtc.resume(); - } - self.broadcastingStatus = true; - self.localVideo.view.$container.show(); - $(".startVideo").html("stop broadcasting"); - }, - stopVideo: function () { - var - self = Metamaps.Realtime; - - self.webrtc.pause(); - self.broadcastingStatus = false; - self.localVideo.view.$container.hide(); - $(".startVideo").html("start my video"); - }, - toggleVideo: function () { - var - self = Metamaps.Realtime; - - if (!self.broadcastingStatus) self.startVideo(); - else self.stopVideo(); + self.room.leaveVideoOnly(); + self.inConversation = false; + self.localVideo.view.$container.hide(); }, turnOff: function (silent) { var self = Metamaps.Realtime; @@ -2198,6 +2215,8 @@ Metamaps.Realtime = { // receive word that there's a conversation in progress socket.on('maps-' + Metamaps.Active.Map.id + '-callInProgress', self.promptToJoin); + socket.on('maps-' + Metamaps.Active.Map.id + '-callStarting', self.conversationHasBegun); + socket.on('maps-' + Metamaps.Active.Map.id + '-callEnding', self.conversationHasEnded); // if you're the 'new guy' update your list with who's already online socket.on(myId + '-' + Metamaps.Active.Map.id + '-UpdateMapperList', self.updateMapperList); @@ -2310,6 +2329,8 @@ Metamaps.Realtime = { $(document).on(Metamaps.Views.room.events.newMessage, sendNewMessage); $(document).on(Metamaps.Views.room.events.callEnded, function () { + socket.emit('callEnded', { mapid: Metamaps.Active.Map.id }); // so that anyone who isn't currently in the call gets notified + self.inConversation = false; Metamaps.GlobalUI.notifyUser('Conversation has ended.'); self.localVideo.view.$container.hide(); self.webrtc.webrtc.localStreams.forEach(function (stream) { @@ -2538,9 +2559,10 @@ Metamaps.Realtime = { var self = Metamaps.Realtime; var socket = Metamaps.Realtime.socket; + var boundary = self.chatOpen ? '#wrapper' : document; var mapper = self.mappersOnMap[id]; - var xMax=$(document).width(); - var yMax=$(document).height(); + var xMax=$(boundary).width(); + var yMax=$(boundary).height(); var compassDiameter=56; var compassArrowSize=24; @@ -2575,9 +2597,10 @@ Metamaps.Realtime = { var self = Metamaps.Realtime; var socket = Metamaps.Realtime.socket; + var boundary = self.chatOpen ? '#wrapper' : document; var xLimit, yLimit; - var xMax=$(document).width(); - var yMax=$(document).height(); + var xMax=$(boundary).width(); + var yMax=$(boundary).height(); var compassDiameter=56; var compassArrowSize=24; diff --git a/app/assets/javascripts/src/views/chatView.js.erb b/app/assets/javascripts/src/views/chatView.js.erb index 1179d29e..fcbb9eda 100644 --- a/app/assets/javascripts/src/views/chatView.js.erb +++ b/app/assets/javascripts/src/views/chatView.js.erb @@ -13,8 +13,9 @@ Metamaps.Views.chatView = (function () { "
" + "", participantHTML: "
" + - "
" + + "
" + "
{{ username }}
" + + "" + "
" + "
", templates: function() { @@ -33,6 +34,7 @@ Metamaps.Views.chatView = (function () { this.$videoToggle = $('
'); this.$cursorToggle = $('
'); this.$participants = $('
'); + this.$conversationInProgress = $('
LIVE LEAVEJOIN
'); this.$chatHeader = $('
CHAT
'); this.$soundToggle = $('
'); this.$messages = $('
'); @@ -46,6 +48,8 @@ Metamaps.Views.chatView = (function () { this.$chatHeader.append(this.$soundToggle); + this.$participants.append(this.$conversationInProgress); + this.$container.append(this.$juntoHeader); this.$container.append(this.$participants); this.$container.append(this.$chatHeader); @@ -162,9 +166,13 @@ Metamaps.Views.chatView = (function () { }, videoToggleClick: function() { this.$videoToggle.toggleClass('active'); + this.videosShowing = !this.videosShowing; + $(document).trigger(this.videosShowing ? chatView.events.videosOn : chatView.events.videosOff); }, cursorToggleClick: function() { this.$cursorToggle.toggleClass('active'); + this.cursorsShowing = !this.cursorsShowing; + $(document).trigger(this.cursorsShowing ? chatView.events.cursorsOn : chatView.events.cursorsOff); }, soundToggleClick: function() { this.alertSound = !this.alertSound; @@ -194,6 +202,8 @@ Metamaps.Views.chatView = (function () { this.isOpen = false; this.alertSound = false; // whether to play sounds on arrival of new messages or not + this.cursorsShowing = true; + this.videosShowing = true; this.unreadMessages = 0; this.participants = new Backbone.Collection(); @@ -208,6 +218,18 @@ Metamaps.Views.chatView = (function () { }); }; + chatView.prototype.conversationInProgress = function (participating) { + this.$conversationInProgress.show(); + this.$participants.addClass('is-live'); + if (participating) this.$conversationInProgress.addClass('is-participating'); + } + + chatView.prototype.conversationEnded = function () { + this.$conversationInProgress.hide(); + this.$participants.removeClass('is-live'); + this.$conversationInProgress.removeClass('is-participating'); + } + chatView.prototype.addParticipant = function (participant) { this.participants.add(participant); } @@ -276,7 +298,11 @@ Metamaps.Views.chatView = (function () { openTray: 'ChatView:openTray', closeTray: 'ChatView:closeTray', inputFocus: 'ChatView:inputFocus', - inputBlur: 'ChatView:inputBlur' + inputBlur: 'ChatView:inputBlur', + cursorsOff: 'ChatView:cursorsOff', + cursorsOn: 'ChatView:cursorsOn', + videosOff: 'ChatView:videosOff', + videosOn: 'ChatView:videosOn' }; return chatView; diff --git a/app/assets/javascripts/src/views/room.js b/app/assets/javascripts/src/views/room.js index 53acd099..9f1c32c9 100644 --- a/app/assets/javascripts/src/views/room.js +++ b/app/assets/javascripts/src/views/room.js @@ -31,11 +31,24 @@ Metamaps.Views.room = (function () { room.prototype.join = function(cb) { this.isActiveRoom = true; this.webrtc.joinRoom(this.room, cb); + this.chat.conversationInProgress(true); // true indicates participation + } + + room.prototype.conversationInProgress = function() { + this.chat.conversationInProgress(false); // false indicates not participating + } + + room.prototype.conversationEnding = function() { + this.chat.conversationEnded(); } room.prototype.leaveVideoOnly = function() { + for (var id in this.videos) { + this.removeVideo(id); + } this.isActiveRoom = false; this.webrtc.leaveRoom(); + this.chat.conversationEnded(); } room.prototype.leave = function() { @@ -44,6 +57,7 @@ Metamaps.Views.room = (function () { } this.isActiveRoom = false; this.webrtc.leaveRoom(); + this.chat.conversationEnded(); this.chat.removeParticipants(); this.chat.clearMessages(); this.messages.reset(); @@ -109,30 +123,6 @@ Metamaps.Views.room = (function () { v.$container.show(); }); - this.socket.on('addVideo', function (data) { - var existingPeer = self.webrtc.webrtc.peers.find(function(p) { return p.id === data.id; }); - if (!existingPeer) { - var peer = self.webrtc.webrtc.createPeer({ - id: data.id, - type: 'video', - enableDataChannels: true, - receiveMedia: { - mandatory: { - OfferToReceiveAudio: true, - OfferToReceiveVideo: true - } - } - }); - console.log(data); - peer.avatar = data.avatar; - peer.username = data.username; - self.webrtc.emit('createdPeer', peer); - peer.start(); - - // the rest will happen automatically through the 'peerStreamAdded' event and associated event handlers - } - }); - var sendChatMessage = function (event, data) { self.sendChatMessage(data); }; @@ -151,7 +141,7 @@ Metamaps.Views.room = (function () { var v = new VideoView(video, null, id, false, { DOUBLE_CLICK_TOLERANCE: 200, avatar: peer.avatar, username: peer.username }); - if (this._videoAdded) this._videoAdded(v); + if (this._videoAdded) this._videoAdded(v, peer.nick); this.videos[peer.id] = v; } diff --git a/app/assets/stylesheets/clean.css.erb b/app/assets/stylesheets/clean.css.erb index 697c3e0d..992ced76 100644 --- a/app/assets/stylesheets/clean.css.erb +++ b/app/assets/stylesheets/clean.css.erb @@ -739,3 +739,11 @@ box-shadow: 0px 1px 1.5px rgba(0,0,0,0.12), 0 1px 1px rgba(0,0,0,0.24); body a#barometer_tab:hover { background-position: 0 -110px; } + +.hideVideos .collaborator-video { + display: none !important; +} + +.hideCursors .collabCompass { + display: none !important; +} diff --git a/app/assets/stylesheets/junto.css.erb b/app/assets/stylesheets/junto.css.erb index a1f1a13d..f66dd6ee 100644 --- a/app/assets/stylesheets/junto.css.erb +++ b/app/assets/stylesheets/junto.css.erb @@ -172,6 +172,27 @@ color: #f5f5f5; overflow-y: auto; } +.chat-box .participants .conversation-live { + display: none; + padding: 5px 10px 5px 10px; + background: #c04f4f; + margin: 5px 10px; + border-radius: 2px; +} +.chat-box .participants .conversation-live .call-action { + float: right; + cursor: pointer; + color: #EBFF00; +} +.chat-box .participants .conversation-live .leave { + display: none; +} +.chat-box .participants .conversation-live.is-participating .leave { + display: block; +} +.chat-box .participants .conversation-live.is-participating .join { + display: none; +} .chat-box .participants .participant { width: 89%; padding: 8px 8px 2px 8px; @@ -188,14 +209,13 @@ padding-top: 2px; } .chat-box .participants .participant .chat-participant-image img { - border: 2px solid #424242; width: 32px; height: 32px; border-radius: 18px; cursor: pointer; } .chat-box .participants .participant .chat-participant-name { - width: 73%; + width: 53%; float: left; font-size: 13px; font-weight: bold; @@ -203,6 +223,12 @@ padding: 2px 8px 0; text-align: left; } +.chat-box .participants.is-live .participant .chat-participant-invite { + display: none; +} +.chat-box .participants .participant .chat-participant-invite { + float: right; +} .chat-box .chat-header { width: 100%; padding: 16px 8px 16px 16px; diff --git a/realtime/realtime-server.js b/realtime/realtime-server.js index cb7b637c..cd386aa6 100644 --- a/realtime/realtime-server.js +++ b/realtime/realtime-server.js @@ -34,10 +34,14 @@ function start() { // send response back to the inviter socket.on('callAccepted', function (data) { socket.broadcast.emit(data.inviter + '-' + data.mapid + '-callAccepted', data.invited); + socket.broadcast.emit('maps-' + data.mapid + '-callStarting'); }); socket.on('callDenied', function (data) { socket.broadcast.emit(data.inviter + '-' + data.mapid + '-callDenied', data.invited); }); + socket.on('callEnded', function (data) { + socket.broadcast.emit('maps-' + data.mapid + '-callEnding'); + }); // this will ping everyone on a map that there's a person just joined the map socket.on('newMapperNotify', function (data) {