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,
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 += ' <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);
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) {
var self = Metamaps.Realtime;
@ -2078,7 +2117,7 @@ Metamaps.Realtime = {
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 btn-no" onclick="Metamaps.Realtime.denyCall(' + inviter + ')">No</button>';
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.room.leaveVideoOnly();
self.inConversation = 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();
},
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;

View file

@ -13,8 +13,9 @@ Metamaps.Views.chatView = (function () {
"<div class='clearfloat'></div>" +
"</div>",
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>" +
"<button type='button' class='button chat-participant-invite' onclick='Metamaps.Realtime.inviteACall({{ id}});'>I</button>" +
"<div class='clearfloat'></div>" +
"</div>",
templates: function() {
@ -33,6 +34,7 @@ Metamaps.Views.chatView = (function () {
this.$videoToggle = $('<div class="video-toggle"></div>');
this.$cursorToggle = $('<div class="cursor-toggle"></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.$soundToggle = $('<div class="sound-toggle active"></div>');
this.$messages = $('<div class="chat-messages"></div>');
@ -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;

View file

@ -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;
}

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

View file

@ -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;

View file

@ -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) {