inviting, joining, and leaving conversations

This commit is contained in:
Connor Turland 2015-12-14 02:28:13 -05:00
parent 8b090be0b3
commit a905094d4d
6 changed files with 151 additions and 74 deletions

View file

@ -1915,8 +1915,10 @@ Metamaps.Realtime = {
webrtc: null, webrtc: null,
readyToCall: false, readyToCall: false,
mappersOnMap: {}, mappersOnMap: {},
chatOpen: false,
status: true, // stores whether realtime is True/On or False/Off, status: true, // stores whether realtime is True/On or False/Off,
broadcastingStatus: false, broadcastingStatus: false,
inConversation: false,
localVideo: null, localVideo: null,
init: function () { init: function () {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -1927,19 +1929,10 @@ Metamaps.Realtime = {
var turnOff = function () { var turnOff = function () {
self.turnOff(); self.turnOff();
}; };
var toggleVideo = function () {
self.toggleVideo();
};
$(".rtOn").click(reenableRealtime); $(".rtOn").click(reenableRealtime);
$(".rtOff").click(turnOff); $(".rtOff").click(turnOff);
$(".startVideo").click(toggleVideo);
$(document).on(Metamaps.Views.chatView.events.openTray, function () { self.addJuntoListeners();
$('.main').addClass('compressed');
});
$(document).on(Metamaps.Views.chatView.events.closeTray, function () {
$('.main').removeClass('compressed');
});
var railsEnv = $('body').data('env'); var railsEnv = $('body').data('env');
var whichToConnect = railsEnv === 'development' ? self.stringForLocalhost : self.stringForHeroku; var whichToConnect = railsEnv === 'development' ? self.stringForLocalhost : self.stringForHeroku;
@ -1995,7 +1988,34 @@ Metamaps.Realtime = {
self.createChat(); self.createChat();
} // if Metamaps.Active.Mapper } // 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 // random position for now
var top = Math.floor((Math.random() * ($('#wrapper').height() - 100)) + 1); var top = Math.floor((Math.random() * ($('#wrapper').height() - 100)) + 1);
var left = Math.floor((Math.random() * ($('#wrapper').width() - 100)) + 1); var left = Math.floor((Math.random() * ($('#wrapper').width() - 100)) + 1);
@ -2006,6 +2026,9 @@ Metamaps.Realtime = {
top: top + 'px', top: top + 'px',
left: left + 'px' left: left + 'px'
}); });
v.$container.find('.video-cutoff').css({
border: '2px solid ' + self.mappersOnMap[id].color
});
}, },
startActiveMap: function () { startActiveMap: function () {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -2069,7 +2092,23 @@ Metamaps.Realtime = {
var notifyText = 'There\'s a conversation happening, want to join?'; var notifyText = 'There\'s a conversation happening, want to join?';
notifyText += ' <button type="button" class="toast-button button" onclick="Metamaps.Realtime.joinCall()">Yes</button>'; notifyText += ' <button type="button" class="toast-button button" onclick="Metamaps.Realtime.joinCall()">Yes</button>';
notifyText += ' <button type="button" class="toast-button button btn-no" onclick="Metamaps.GlobalUI.clearNotify()">No</button>'; notifyText += ' <button type="button" class="toast-button button btn-no" onclick="Metamaps.GlobalUI.clearNotify()">No</button>';
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 += ' <button type="button" class="toast-button button" onclick="Metamaps.Realtime.joinCall()">Yes</button>';
notifyText += ' <button type="button" class="toast-button button btn-no" onclick="Metamaps.GlobalUI.clearNotify()">No</button>';
Metamaps.GlobalUI.notifyUser(notifyText, true);
self.room.conversationInProgress();
},
conversationHasEnded: function () {
var self = Metamaps.Realtime;
self.room.conversationEnding();
}, },
invitedToCall: function (inviter) { invitedToCall: function (inviter) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -2078,7 +2117,7 @@ Metamaps.Realtime = {
var notifyText = username + ' is suggesting a video call. What do you think?'; var notifyText = username + ' is suggesting a video call. What do you think?';
notifyText += ' <button type="button" class="toast-button button" onclick="Metamaps.Realtime.acceptCall(' + inviter + ')">Yes</button>'; notifyText += ' <button type="button" class="toast-button button" onclick="Metamaps.Realtime.acceptCall(' + inviter + ')">Yes</button>';
notifyText += ' <button type="button" class="toast-button button btn-no" onclick="Metamaps.Realtime.denyCall(' + inviter + ')">No</button>'; notifyText += ' <button type="button" class="toast-button button btn-no" onclick="Metamaps.Realtime.denyCall(' + inviter + ')">No</button>';
Metamaps.GlobalUI.notifyUser(notifyText); Metamaps.GlobalUI.notifyUser(notifyText, true);
}, },
acceptCall: function (userid) { acceptCall: function (userid) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -2133,38 +2172,16 @@ Metamaps.Realtime = {
} }
self.room.join(); self.room.join();
}); });
self.inConversation = true;
self.webrtc.startLocalVideo(); self.webrtc.startLocalVideo();
Metamaps.GlobalUI.clearNotify(); Metamaps.GlobalUI.clearNotify();
}, },
startVideo: function() { leaveCall: function () {
var var self = Metamaps.Realtime;
self = Metamaps.Realtime;
if (!self.videoInitialized) { self.room.leaveVideoOnly();
self.webrtc.startLocalVideo(); self.inConversation = false;
}
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(); self.localVideo.view.$container.hide();
$(".startVideo").html("start my video");
},
toggleVideo: function () {
var
self = Metamaps.Realtime;
if (!self.broadcastingStatus) self.startVideo();
else self.stopVideo();
}, },
turnOff: function (silent) { turnOff: function (silent) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -2198,6 +2215,8 @@ Metamaps.Realtime = {
// receive word that there's a conversation in progress // 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 + '-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 // if you're the 'new guy' update your list with who's already online
socket.on(myId + '-' + Metamaps.Active.Map.id + '-UpdateMapperList', self.updateMapperList); 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.newMessage, sendNewMessage);
$(document).on(Metamaps.Views.room.events.callEnded, function () { $(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.'); Metamaps.GlobalUI.notifyUser('Conversation has ended.');
self.localVideo.view.$container.hide(); self.localVideo.view.$container.hide();
self.webrtc.webrtc.localStreams.forEach(function (stream) { self.webrtc.webrtc.localStreams.forEach(function (stream) {
@ -2538,9 +2559,10 @@ Metamaps.Realtime = {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket; var socket = Metamaps.Realtime.socket;
var boundary = self.chatOpen ? '#wrapper' : document;
var mapper = self.mappersOnMap[id]; var mapper = self.mappersOnMap[id];
var xMax=$(document).width(); var xMax=$(boundary).width();
var yMax=$(document).height(); var yMax=$(boundary).height();
var compassDiameter=56; var compassDiameter=56;
var compassArrowSize=24; var compassArrowSize=24;
@ -2575,9 +2597,10 @@ Metamaps.Realtime = {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket; var socket = Metamaps.Realtime.socket;
var boundary = self.chatOpen ? '#wrapper' : document;
var xLimit, yLimit; var xLimit, yLimit;
var xMax=$(document).width(); var xMax=$(boundary).width();
var yMax=$(document).height(); var yMax=$(boundary).height();
var compassDiameter=56; var compassDiameter=56;
var compassArrowSize=24; var compassArrowSize=24;

View file

@ -13,8 +13,9 @@ Metamaps.Views.chatView = (function () {
"<div class='clearfloat'></div>" + "<div class='clearfloat'></div>" +
"</div>", "</div>",
participantHTML: "<div class='participant participant-{{ id }}'>" + participantHTML: "<div class='participant participant-{{ id }}'>" +
"<div class='chat-participant-image'><img src='{{ image }}' /></div>" + "<div class='chat-participant-image'><img src='{{ image }}' style='border: 2px solid {{ color }};' /></div>" +
"<div class='chat-participant-name'>{{ username }}</div>" + "<div class='chat-participant-name'>{{ username }}</div>" +
"<button type='button' class='button chat-participant-invite' onclick='Metamaps.Realtime.inviteACall({{ id}});'>I</button>" +
"<div class='clearfloat'></div>" + "<div class='clearfloat'></div>" +
"</div>", "</div>",
templates: function() { templates: function() {
@ -33,6 +34,7 @@ Metamaps.Views.chatView = (function () {
this.$videoToggle = $('<div class="video-toggle"></div>'); this.$videoToggle = $('<div class="video-toggle"></div>');
this.$cursorToggle = $('<div class="cursor-toggle"></div>'); this.$cursorToggle = $('<div class="cursor-toggle"></div>');
this.$participants = $('<div class="participants"></div>'); this.$participants = $('<div class="participants"></div>');
this.$conversationInProgress = $('<div class="conversation-live">LIVE <span class="call-action leave" onclick="Metamaps.Realtime.leaveCall();">LEAVE</span><span class="call-action join" onclick="Metamaps.Realtime.joinCall();">JOIN</span></div>');
this.$chatHeader = $('<div class="chat-header">CHAT</div>'); this.$chatHeader = $('<div class="chat-header">CHAT</div>');
this.$soundToggle = $('<div class="sound-toggle active"></div>'); this.$soundToggle = $('<div class="sound-toggle active"></div>');
this.$messages = $('<div class="chat-messages"></div>'); this.$messages = $('<div class="chat-messages"></div>');
@ -46,6 +48,8 @@ Metamaps.Views.chatView = (function () {
this.$chatHeader.append(this.$soundToggle); this.$chatHeader.append(this.$soundToggle);
this.$participants.append(this.$conversationInProgress);
this.$container.append(this.$juntoHeader); this.$container.append(this.$juntoHeader);
this.$container.append(this.$participants); this.$container.append(this.$participants);
this.$container.append(this.$chatHeader); this.$container.append(this.$chatHeader);
@ -162,9 +166,13 @@ Metamaps.Views.chatView = (function () {
}, },
videoToggleClick: function() { videoToggleClick: function() {
this.$videoToggle.toggleClass('active'); this.$videoToggle.toggleClass('active');
this.videosShowing = !this.videosShowing;
$(document).trigger(this.videosShowing ? chatView.events.videosOn : chatView.events.videosOff);
}, },
cursorToggleClick: function() { cursorToggleClick: function() {
this.$cursorToggle.toggleClass('active'); this.$cursorToggle.toggleClass('active');
this.cursorsShowing = !this.cursorsShowing;
$(document).trigger(this.cursorsShowing ? chatView.events.cursorsOn : chatView.events.cursorsOff);
}, },
soundToggleClick: function() { soundToggleClick: function() {
this.alertSound = !this.alertSound; this.alertSound = !this.alertSound;
@ -194,6 +202,8 @@ Metamaps.Views.chatView = (function () {
this.isOpen = false; this.isOpen = false;
this.alertSound = false; // whether to play sounds on arrival of new messages or not this.alertSound = false; // whether to play sounds on arrival of new messages or not
this.cursorsShowing = true;
this.videosShowing = true;
this.unreadMessages = 0; this.unreadMessages = 0;
this.participants = new Backbone.Collection(); 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) { chatView.prototype.addParticipant = function (participant) {
this.participants.add(participant); this.participants.add(participant);
} }
@ -276,7 +298,11 @@ Metamaps.Views.chatView = (function () {
openTray: 'ChatView:openTray', openTray: 'ChatView:openTray',
closeTray: 'ChatView:closeTray', closeTray: 'ChatView:closeTray',
inputFocus: 'ChatView:inputFocus', inputFocus: 'ChatView:inputFocus',
inputBlur: 'ChatView:inputBlur' inputBlur: 'ChatView:inputBlur',
cursorsOff: 'ChatView:cursorsOff',
cursorsOn: 'ChatView:cursorsOn',
videosOff: 'ChatView:videosOff',
videosOn: 'ChatView:videosOn'
}; };
return chatView; return chatView;

View file

@ -31,11 +31,24 @@ Metamaps.Views.room = (function () {
room.prototype.join = function(cb) { room.prototype.join = function(cb) {
this.isActiveRoom = true; this.isActiveRoom = true;
this.webrtc.joinRoom(this.room, cb); 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() { room.prototype.leaveVideoOnly = function() {
for (var id in this.videos) {
this.removeVideo(id);
}
this.isActiveRoom = false; this.isActiveRoom = false;
this.webrtc.leaveRoom(); this.webrtc.leaveRoom();
this.chat.conversationEnded();
} }
room.prototype.leave = function() { room.prototype.leave = function() {
@ -44,6 +57,7 @@ Metamaps.Views.room = (function () {
} }
this.isActiveRoom = false; this.isActiveRoom = false;
this.webrtc.leaveRoom(); this.webrtc.leaveRoom();
this.chat.conversationEnded();
this.chat.removeParticipants(); this.chat.removeParticipants();
this.chat.clearMessages(); this.chat.clearMessages();
this.messages.reset(); this.messages.reset();
@ -109,30 +123,6 @@ Metamaps.Views.room = (function () {
v.$container.show(); 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) { var sendChatMessage = function (event, data) {
self.sendChatMessage(data); self.sendChatMessage(data);
}; };
@ -151,7 +141,7 @@ Metamaps.Views.room = (function () {
var var
v = new VideoView(video, null, id, false, { DOUBLE_CLICK_TOLERANCE: 200, avatar: peer.avatar, username: peer.username }); 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; this.videos[peer.id] = v;
} }

View file

@ -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 { body a#barometer_tab:hover {
background-position: 0 -110px; background-position: 0 -110px;
} }
.hideVideos .collaborator-video {
display: none !important;
}
.hideCursors .collabCompass {
display: none !important;
}

View file

@ -172,6 +172,27 @@
color: #f5f5f5; color: #f5f5f5;
overflow-y: auto; 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 { .chat-box .participants .participant {
width: 89%; width: 89%;
padding: 8px 8px 2px 8px; padding: 8px 8px 2px 8px;
@ -188,14 +209,13 @@
padding-top: 2px; padding-top: 2px;
} }
.chat-box .participants .participant .chat-participant-image img { .chat-box .participants .participant .chat-participant-image img {
border: 2px solid #424242;
width: 32px; width: 32px;
height: 32px; height: 32px;
border-radius: 18px; border-radius: 18px;
cursor: pointer; cursor: pointer;
} }
.chat-box .participants .participant .chat-participant-name { .chat-box .participants .participant .chat-participant-name {
width: 73%; width: 53%;
float: left; float: left;
font-size: 13px; font-size: 13px;
font-weight: bold; font-weight: bold;
@ -203,6 +223,12 @@
padding: 2px 8px 0; padding: 2px 8px 0;
text-align: left; 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 { .chat-box .chat-header {
width: 100%; width: 100%;
padding: 16px 8px 16px 16px; padding: 16px 8px 16px 16px;

View file

@ -34,10 +34,14 @@ function start() {
// send response back to the inviter // send response back to the inviter
socket.on('callAccepted', function (data) { socket.on('callAccepted', function (data) {
socket.broadcast.emit(data.inviter + '-' + data.mapid + '-callAccepted', data.invited); socket.broadcast.emit(data.inviter + '-' + data.mapid + '-callAccepted', data.invited);
socket.broadcast.emit('maps-' + data.mapid + '-callStarting');
}); });
socket.on('callDenied', function (data) { socket.on('callDenied', function (data) {
socket.broadcast.emit(data.inviter + '-' + data.mapid + '-callDenied', data.invited); 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 // this will ping everyone on a map that there's a person just joined the map
socket.on('newMapperNotify', function (data) { socket.on('newMapperNotify', function (data) {