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 = $('');
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) {