Browse Source

Implemented pictures for session.

pull/67/head
Simon Eisenmann 11 years ago
parent
commit
f38fd982aa
  1. 25
      src/styles/components/_buddylist.scss
  2. 2
      static/css/main.min.css
  3. 64
      static/js/filters/buddyimagesrc.js
  4. 74
      static/js/services/buddylist.js
  5. 69
      static/js/services/buddypicture.js
  6. 3
      static/js/services/services.js
  7. 2
      static/partials/buddy.html
  8. 13
      static/partials/buddyactions.html

25
src/styles/components/_buddylist.scss

@ -154,6 +154,7 @@
.#{$fa-css-prefix} { .#{$fa-css-prefix} {
color: $actioncolor2; color: $actioncolor2;
line-height: 46px; line-height: 46px;
font-size: 3em;
} }
img { img {
bottom: 0; bottom: 0;
@ -172,6 +173,7 @@
margin-right:4px; margin-right:4px;
.#{$fa-css-prefix} { .#{$fa-css-prefix} {
line-height: 30px; line-height: 30px;
font-size: 2em;
} }
} }
.buddy1 { .buddy1 {
@ -201,9 +203,10 @@
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
display: inline-block;
width:174px;
text-align:left; text-align:left;
vertical-align:middle;
display: inline-block;
width: 132px;
} }
} }
@ -220,28 +223,32 @@
transition-duration: .3s; transition-duration: .3s;
white-space: nowrap; white-space: nowrap;
z-index: 5; z-index: 5;
.#{$fa-css-prefix} { > .btn {
font-size: 1.5em; width: 42px;
pointer-events: none; height: 40px;
padding: 0px;
text-align: center;
font-size: 2em;
} }
} }
.buddy .buddysessions { .buddy .buddysessions {
margin-top: 56px; margin-top: 56px;
max-height:0px; max-height:0px;
margin-bottom: 10px;
transition-property: max-height; transition-property: max-height;
transition-duration: 1s; transition-duration: 1s;
transition-delay: .1s; transition-delay: .1s;
ul { ul {
padding-top: 10px; padding-top: 10px;
margin-left: 14px; margin: 0 10px 0 14px;
padding-left: 0px; padding-left: 0px;
border-left: 1px dotted $bordercolor; border-left: 1px dotted $bordercolor;
} }
ul li { ul li {
margin-bottom: 1px; margin-bottom: 4px;
margin-top: 1px; margin-top: 2px;
margin-left: -4px; margin-left: 0px;
list-style-type: none; list-style-type: none;
} }
.currentsession .buddy3 { .currentsession .buddy3 {

2
static/css/main.min.css vendored

File diff suppressed because one or more lines are too long

64
static/js/filters/buddyimagesrc.js

@ -20,33 +20,6 @@
*/ */
define(["underscore"], function(_) { define(["underscore"], function(_) {
// Simple function which converts data urls to blobs, both base64 or not.
var dataURLToBlob = (function() {
var is_base64 = ";base64,";
return function(dataURL) {
var parts, ct;
if (dataURL.indexOf(is_base64) === -1) {
// No base64.
parts = dataURL.split(",");
ct = parts[0].split(":")[1];
return new Blob([parts[1]], {
type: ct
});
}
parts = dataURL.split(is_base64);
ct = parts[0].split(":")[1];
var data = window.atob(parts[1]);
var length = data.length;
var buffer = new Uint8Array(length);
for (var i = 0; i < length; i++) {
buffer[i] = data.charCodeAt(i);
}
return new Blob([buffer], {
type: ct
});
};
}());
// Create URLs for blobs. // Create URLs for blobs.
var blobToObjectURL = function(blob) { var blobToObjectURL = function(blob) {
return URL.createObjectURL(blob); return URL.createObjectURL(blob);
@ -57,7 +30,7 @@ define(["underscore"], function(_) {
}; };
// buddyImageSrc // buddyImageSrc
return ["buddyData", "appData", function(buddyData, appData) { return ["buddyData", "buddyPicture", "appData", function(buddyData, buddyPicture, appData) {
// Cache created blob urls. // Cache created blob urls.
var urls = {}; var urls = {};
@ -75,24 +48,35 @@ define(["underscore"], function(_) {
}); });
}, 5000); }, 5000);
return function(id) { return function(id, display) {
var scope = buddyData.lookup(id, false, true); if (typeof(display) === "undefined") {
if (scope) { var scope = buddyData.lookup(id, false, true);
var display = scope.display; if (scope) {
if (display) { display = scope.display;
}
}
if (display) {
if (display.buddyPictureLocalUrl) {
return display.buddyPictureLocalUrl;
} else if (display.buddyPicture) {
var url = urls[id];
if (url) {
revokeURL(id, url);
}
// No existing data. Check if service does find something.
buddyPicture.update(display);
if (display.buddyPictureLocalUrl) { if (display.buddyPictureLocalUrl) {
return display.buddyPictureLocalUrl; return display.buddyPictureLocalUrl;
} else if (display.buddyPicture) { }
var url = urls[id]; // Check if we should handle it as blob.
if (url) { url = display.buddyPicture;
revokeURL(id, url); if (url.indexOf("data:") === 0) {
} var blob = buddyPicture.toBlob(null, url);
// New data -> new url.
var blob = dataURLToBlob(display.buddyPicture);
url = display.buddyPictureLocalUrl = urls[id] = blobToObjectURL(blob); url = display.buddyPictureLocalUrl = urls[id] = blobToObjectURL(blob);
return url; return url;
} }
return null;
} }
} else { } else {
var data = appData.get(); var data = appData.get();

74
static/js/services/buddylist.js

@ -129,7 +129,7 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text!
}; };
// buddyList // buddyList
return ["$window", "$compile", "playSound", "buddyData", "buddySession", "fastScroll", "mediaStream", "animationFrame", "$q", function($window, $compile, playSound, buddyData, buddySession, fastScroll, mediaStream, animationFrame, $q) { return ["$window", "$compile", "playSound", "buddyData", "buddySession", "buddyPicture", "fastScroll", "mediaStream", "animationFrame", "$q", function($window, $compile, playSound, buddyData, buddySession, buddyPicture, fastScroll, mediaStream, animationFrame, $q) {
var buddyTemplate = $compile(templateBuddy); var buddyTemplate = $compile(templateBuddy);
var buddyActions = $compile(templateBuddyActions); var buddyActions = $compile(templateBuddyActions);
@ -378,55 +378,6 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text!
}; };
Buddylist.prototype.updateBuddyPicture = function(status) {
url = status.buddyPicture;
if (!url) {
return;
}
if (url.indexOf("img:") === 0) {
status.buddyPicture = status.buddyPictureLocalUrl = mediaStream.url.buddy(url.substr(4));
}
};
Buddylist.prototype.dumpBuddyPictureToBlob = function(scope, data) {
if (!data) {
data = this.dumpBuddyPictureToString(scope);
if (!data) {
return null;
}
}
// NOTE(longsleep): toBlob is not widely supported narf ..
// see: https://code.google.com/p/chromium/issues/detail?id=67587
var parts = data.match(/data:([^;]*)(;base64)?,([0-9A-Za-z+\/]+)/);
var binStr = atob(parts[3]);
var buf = new ArrayBuffer(binStr.length);
var view = new Uint8Array(buf);
for (var i = 0; i < view.length; i++) {
view[i] = binStr.charCodeAt(i);
}
return new Blob([view], {'type': parts[1]});
};
Buddylist.prototype.dumpBuddyPictureToString = function(scope) {
var img = scope.element.find(".buddyPicture img").get(0);
if (img) {
var canvas = $window.document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL("image/jpeg");
}
return null;
};
Buddylist.prototype.setDisplay = function(id, scope, data, queueName) { Buddylist.prototype.setDisplay = function(id, scope, data, queueName) {
var status = data.Status; var status = data.Status;
@ -434,8 +385,7 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text!
// Set display.name. // Set display.name.
display.displayName = status.displayName; display.displayName = status.displayName;
// Set display.picture. // Set display.picture.
display.buddyPicture = status.buddyPicture; buddyPicture.update(display, status.buddyPicture);
this.updateBuddyPicture(display);
// Set display subline. // Set display subline.
this.updateSubline(display, status.message); this.updateSubline(display, status.message);
// Add to render queue when no element exists. // Add to render queue when no element exists.
@ -473,11 +423,9 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text!
} }
// Update display picture. // Update display picture.
if (contact) { if (contact) {
display.buddyPicture = contact.buddyPicture || status.buddyPicture || null; buddyPicture.update(display, contact.buddyPicture || status.buddyPicture || null);
this.updateBuddyPicture(display);
} else if (status.buddyPicture) { } else if (status.buddyPicture) {
display.buddyPicture = status.buddyPicture || null; buddyPicture.update(display, status.buddyPicture || null);
this.updateBuddyPicture(display);
} }
}; };
@ -640,7 +588,7 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text!
delete status.message; delete status.message;
// Convert buddy image. // Convert buddy image.
if (status.buddyPicture) { if (status.buddyPicture) {
var img = this.dumpBuddyPictureToString(scope); var img = buddyPicture.toString(scope.element.find(".buddyPicture img").get(0));
if (img) { if (img) {
status.buddyPicture = img; status.buddyPicture = img;
} else { } else {
@ -684,10 +632,16 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text!
Buddylist.prototype.click = function(buddyElement, target) { Buddylist.prototype.click = function(buddyElement, target) {
//console.log("click handler", buddyElement, target); var be = buddyElement.get(0);
var action = $(target).data("action"); // Traverse up to find click action.
var action;
do {
action = $(target).data("action");
target = $(target).parent().get(0);
} while (!action && target && target !== be);
// Make call the default action.
if (!action) { if (!action) {
// Make call the default action.
action = "chat"; action = "chat";
} }

69
static/js/services/buddypicture.js

@ -0,0 +1,69 @@
/*
* Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG
*
* This file is part of Spreed WebRTC.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
define(['underscore'], function(underscore) {
// buddyPicture
return ["mediaStream", "$window", function(mediaStream, $window) {
var buddyPicture = {
update: function(data, url) {
if (typeof(url) !== "undefined") {
data.buddyPicture = url;
} else {
url = data.buddyPicture;
}
if (!url) {
return;
}
if (url.indexOf("img:") === 0) {
data.buddyPicture = data.buddyPictureLocalUrl = mediaStream.url.buddy(url.substr(4));
}
},
toString: function(img, mime_type) {
if (img) {
if (typeof(mime_type) === "undefined") {
mime_type = "image/jpeg";
}
var canvas = $window.document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL(mime_type);
}
return null;
}
};
return buddyPicture;
}];
});

3
static/js/services/services.js

@ -28,6 +28,7 @@ define([
'services/appdata', 'services/appdata',
'services/buddydata', 'services/buddydata',
'services/buddylist', 'services/buddylist',
'services/buddypicture',
'services/enrichmessage', 'services/enrichmessage',
'services/safemessage', 'services/safemessage',
'services/alertify', 'services/alertify',
@ -56,6 +57,7 @@ mediaStream,
appData, appData,
buddyData, buddyData,
buddyList, buddyList,
buddyPicture,
enrichMessage, enrichMessage,
safeMessage, safeMessage,
alertify, alertify,
@ -86,6 +88,7 @@ animationFrame) {
appData: appData, appData: appData,
buddyData: buddyData, buddyData: buddyData,
buddyList: buddyList, buddyList: buddyList,
buddyPicture: buddyPicture,
enrichMessage: enrichMessage, enrichMessage: enrichMessage,
safeMessage: safeMessage, safeMessage: safeMessage,
alertify: alertify, alertify: alertify,

2
static/partials/buddy.html

@ -1,5 +1,5 @@
<div class="buddy" ng-class="{'contact': contact, 'withSubline': display.subline || session.Userid}"> <div class="buddy" ng-class="{'contact': contact, 'withSubline': display.subline || session.Userid}">
<div class="buddyPicture"><i class="fa fa-user fa-3x"/><img ng-show="display.buddyPicture" alt ng-src="{{display.buddyPicture}}" width="46" height="46"/></div> <div class="buddyPicture"><i class="fa fa-user"/><img ng-show="display.buddyPicture" alt ng-src="{{display.buddyPicture}}"/></div>
<div class="buddy1">{{session.Id|displayName}}</div> <div class="buddy1">{{session.Id|displayName}}</div>
<div class="buddy2"><span ng-show="session.Userid"><i class="fa contact" data-action="contact"></i><span ng-show="session.count"> ({{session.count}})</span></span> <span title="{{display.sublineFull}}">{{display.subline}}</span></div> <div class="buddy2"><span ng-show="session.Userid"><i class="fa contact" data-action="contact"></i><span ng-show="session.count"> ({{session.count}})</span></span> <span title="{{display.sublineFull}}">{{display.subline}}</span></div>
</div> </div>

13
static/partials/buddyactions.html

@ -1,11 +1,18 @@
<div class="buddyhover"> <div class="buddyhover">
<div class="buddyactions active"> <div class="buddyactions active">
<a class="btn btn-info" data-action="call" title="{{_('Start video call')}}"><i class="fa fa-phone fa-fw"></i></a> <a class="btn btn-info" data-action="call" title="{{_('Start video call')}}"><i class="fa fa-phone"></i></a>
<a class="btn btn-info" data-action="chat" title="{{_('Start chat')}}"><i class="fa fa-comments-o fa-fw"></i></a> <a class="btn btn-info" data-action="chat" title="{{_('Start chat')}}"><i class="fa fa-comments-o"></i></a>
</div> </div>
<div class="buddysessions" ng-if="session.count>1"> <div class="buddysessions" ng-if="session.count>1">
<ul> <ul>
<li ng-repeat="(id, s) in session.sessions" ng-class="{currentsession: s.Id === session.Id}"><span class="btn-group"><a class="btn btn-sm btn-default buddy3" ng-click="$event.stopPropagation()"><span>{{s.Status.displayName}}<span ng-show="s.Status.message">, {{s.Status.message}}</span></span></a><a class="btn btn-sm btn-default" title="{{_('Start video call')}}" ng-click="doCall(s.Id); $event.stopPropagation()"><i class="fa fa-eye"></i></a><a class="btn btn-sm btn-default" title="{{_('Start chat')}}" ng-click="doChat(s.Id); $event.stopPropagation()"><i class="fa fa-comments-o"></i></a></span></li> <li ng-repeat="(id, s) in session.sessions" ng-class="{currentsession: s.Id === session.Id}">
<span>
<div class="buddyPicture buddyPictureSmall"><i class="fa fa-user"/><img ng-show="s.Status.buddyPicture" alt ng-src="{{s.Id|buddyImageSrc:s.Status}}"/></div>
<div class="buddy3" title="{{s.Status.message}}">{{s.Status.displayName}}<span ng-show="s.Status.message">, {{s.Status.message}}</span></div>
<a class="btn btn-sm btn-default" title="{{_('Start video call')}}" ng-click="doCall(s.Id); $event.stopPropagation()"><i class="fa fa-phone"></i></a>
<a class="btn btn-sm btn-default" title="{{_('Start chat')}}" ng-click="doChat(s.Id); $event.stopPropagation()"><i class="fa fa-comments-o"></i></a>
</span>
</li>
</ul> </ul>
</div> </div>
</div> </div>

Loading…
Cancel
Save