diff --git a/build/build.js b/build/build.js index 0e0528d2..4ba0524a 100644 --- a/build/build.js +++ b/build/build.js @@ -18,6 +18,7 @@ * along with this program. If not, see . * */ +/*jshint -W030 */ ({ baseUrl: '../static/js', mainConfigFile: '../static/js/main.js', diff --git a/doc/plugin-test-authorize.js b/doc/plugin-test-authorize.js index bd645962..35f9b5ce 100644 --- a/doc/plugin-test-authorize.js +++ b/doc/plugin-test-authorize.js @@ -50,14 +50,14 @@ define(['angular', 'sjcl'], function(angular, sjcl) { $window.testCreateSuseridLocal = function(key, userid) { var k = sjcl.codec.utf8String.toBits(key); - var foo = new sjcl.misc.hmac(k, sjcl.hash.sha256) - var expiration = parseInt(((new Date).getTime()/1000)+3600, 10); + var foo = new sjcl.misc.hmac(k, sjcl.hash.sha256); + var expiration = parseInt(((new Date()).getTime()/1000)+3600, 10); var useridCombo = ""+expiration+":"+userid; var secret = foo.mac(useridCombo); var data = { useridcombo: useridCombo, secret: sjcl.codec.base64.fromBits(secret) - } + }; lastData = data; return data; @@ -86,7 +86,7 @@ define(['angular', 'sjcl'], function(angular, sjcl) { $window.testLastAuthenticate = function() { if (!lastNonce || !lastUserid) { console.log("Run testAuthorize first."); - return + return; } mediaStream.api.requestAuthentication(lastUserid, lastNonce); }; @@ -94,7 +94,7 @@ define(['angular', 'sjcl'], function(angular, sjcl) { $window.testLastAuthorize = function() { if (lastData === null) { console.log("Run testCreateSuseridServer fist."); - return + return; } $window.testAuthorize(lastData); }; @@ -103,6 +103,6 @@ define(['angular', 'sjcl'], function(angular, sjcl) { } - } + }; -}); \ No newline at end of file +}); diff --git a/src/styles/components/_buddypicture.scss b/src/styles/components/_buddypicture.scss new file mode 100644 index 00000000..af2322ab --- /dev/null +++ b/src/styles/components/_buddypicture.scss @@ -0,0 +1,56 @@ +/* + * 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 . + * + */ + +.buddyPicture { + .picture { + display: block; + margin-bottom: 5px; + } + .videoPicture { + position: relative; + } + .preview { + left: 0; + position: absolute; + top: 0; + &.previewPicture { + position: relative; + } + } + .showTakePicture { + .btn { + margin: 5px 0px; + } + } + .btn-takePicture, + .btn-retakePicture { + left: 85px; + position: absolute; + top: 110px; + } + .countdownPicture { + color: $componentbg; + font-size: 45px; + left: 90px; + position: absolute; + top: 55px; + } +} diff --git a/src/styles/main.scss b/src/styles/main.scss index 4d9c69bf..90b959ad 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -35,6 +35,7 @@ @import "components/rightslide"; @import "components/bar"; @import "components/buddylist"; +@import "components/buddypicture"; @import "components/settings"; @import "components/chat"; @import "components/usability"; diff --git a/static/js/directives/buddypicture.js b/static/js/directives/buddypicture.js new file mode 100644 index 00000000..4e88a1c8 --- /dev/null +++ b/static/js/directives/buddypicture.js @@ -0,0 +1,172 @@ +/* + * 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 . + * + */ +define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, _, template) { + + return ["$compile", function($compile) { + + var controller = ['$scope', 'safeApply', '$timeout', '$q', function($scope, safeApply, $timeout, $q) { + + $scope.showTakePicture = false; + $scope.waitingForPermission = false; + $scope.previewPicture = false; + $scope.countingDown = false; + $scope.video = null; + $scope.canvasPic = null; + $scope.canvasPrev = null; + + var localStream = null; + var delayToTakePicture = 3000; + var countDownFrom = 3; + + // Counts down from start to 1 + var takePictureCountDown = function(start, delayTotal) { + $scope.countingDown = true; + $scope.countdown = {}; + $scope.countdown.num = start; + var decrementNum = function(num) { + $timeout(function() { + $scope.countdown.num--; + if($scope.countdown.num === 0) { + $scope.countingDown = false; + } + }, delayTotal/start*num); + }; + for(var i = 1; i <= start; i++) { + decrementNum(i); + } + }; + + var getCanvasAspectRatio = function() { + var videoWidth = $scope.video.videoWidth; + var videoHeight = $scope.video.videoHeight; + var aspectRatio = videoWidth/videoHeight; + if (!aspectRatio) { + // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! + console.warn("Unable to compute aspectRatio", aspectRatio); + aspectRatio = 1.3333333333333333; + } + return aspectRatio; + }; + + var writePreviewPic = function() { + $scope.canvasPrev.getContext("2d").drawImage($scope.video, 0, 0, $scope.video.width, $scope.video.width/getCanvasAspectRatio()); + $scope.preview = $scope.canvasPrev.toDataURL("image/jpeg"); + }; + + var makePicture = function(stream, cntFrom, delayTotal) { + takePictureCountDown(cntFrom, delayTotal); + $timeout(function() { + videoStop(stream, $scope.video); + writePreviewPic(); + $scope.previewPicture = true; + }, delayTotal); + }; + + var videoStop = function(stream, video) { + if (stream) { + video.pause(); + stream.stop(); + stream = null; + } + }; + + var videoStart = function() { + $scope.waitingForPermission = true; + var videoConstraints = true; + var videoAllowed = $q.defer(); + if ($scope.user.settings.cameraId) { + videoConstraints = { + optional: [{ + sourceId: $scope.user.settings.cameraId + }] + }; + } + getUserMedia({ + video: videoConstraints + }, function(stream) { + $scope.showTakePicture = true; + localStream = stream; + $scope.waitingForPermission = false; + attachMediaStream($scope.video, stream); + safeApply($scope); + videoAllowed.resolve(true); + }, function(error) { + console.error('Failed to get access to local media. Error code was ' + error.code); + $scope.waitingForPermission = false; + safeApply($scope); + videoAllowed.resolve(false); + }); + return videoAllowed.promise; + }; + + $scope.initPicture = function() { + videoStart(localStream); + }; + + $scope.cancelPicture = function() { + $scope.showTakePicture = false; + $scope.previewPicture = false; + videoStop(localStream, $scope.video); + }; + + $scope.retakePicture = function() { + var permission = videoStart(localStream); + permission.then(function(isPermitted) { + if(isPermitted) { + $scope.previewPicture = false; + makePicture(localStream, countDownFrom, delayToTakePicture); + } + }); + }; + + $scope.takePicture = function() { + makePicture(localStream, countDownFrom, delayToTakePicture); + }; + + $scope.setAsProfilePicture = function() { + var x = (46 * getCanvasAspectRatio() - 46) / -2; + $scope.canvasPic.getContext("2d").drawImage($scope.video, x, 0, 46 * getCanvasAspectRatio(), 46); + $scope.user.buddyPicture = $scope.canvasPic.toDataURL("image/jpeg"); + console.info("Image size", $scope.user.buddyPicture.length); + $scope.cancelPicture(); + safeApply($scope); + }; + + }]; + + var link = function($scope, $element) { + $scope.video = $element.find("video").get(0); + $scope.canvasPic = $element.find("canvas#pic").get(0); + $scope.canvasPrev = $element.find("canvas#prev").get(0); + }; + + return { + scope: true, + restrict: 'E', + replace: true, + template: template, + controller: controller, + link: link + }; + + }]; + +}); diff --git a/static/js/directives/directives.js b/static/js/directives/directives.js index 66bfbe79..510fd6e3 100644 --- a/static/js/directives/directives.js +++ b/static/js/directives/directives.js @@ -25,6 +25,7 @@ define([ 'directives/onescape', 'directives/statusmessage', 'directives/buddylist', + 'directives/buddypicture', 'directives/settings', 'directives/chat', 'directives/audiovideo', @@ -34,13 +35,14 @@ define([ 'directives/screenshare', 'directives/roombar', 'directives/socialshare', - 'directives/page'], function(_, onEnter, onEscape, statusMessage, buddyList, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page) { + 'directives/page'], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPicture, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page) { var directives = { onEnter: onEnter, onEscape: onEscape, statusMessage: statusMessage, buddyList: buddyList, + buddyPicture: buddyPicture, settings: settings, chat: chat, audioVideo: audioVideo, diff --git a/static/js/directives/settings.js b/static/js/directives/settings.js index 69a1b2c9..6716aa05 100644 --- a/static/js/directives/settings.js +++ b/static/js/directives/settings.js @@ -26,8 +26,6 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t $scope.layout.settings = false; $scope.showAdvancedSettings = true; - $scope.showTakePicture = false; - $scope.showTakePictureReady = true; $scope.rememberSettings = true; $scope.desktopNotify = desktopNotify; $scope.mediaSources = mediaSources; @@ -46,8 +44,6 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t }); }); - var localStream = null; - // Make sure to save settings when they are open and the page is reloaded. $(window).on("unload", function() { if ($scope.layout.settings) { @@ -77,65 +73,6 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t safeApply($scope); }); }; - $scope.takePicture = function(element, stop) { - if (stop) { - $scope.showTakePicture = false; - if (localStream) { - localStream.stop(); - localStream = null; - } - } else { - var video = $(element).parent().find("video").get(0); - if (!$scope.showTakePicture) { - $scope.showTakePictureReady = false; - var videoConstraints = true; - if ($scope.user.settings.cameraId) { - videoConstraints = { - optional: [{ - sourceId: $scope.user.settings.cameraId - }] - } - } - getUserMedia({ - video: videoConstraints - }, function(stream) { - if ($scope.showTakePictureReady) { - stream.stop() - return; - } - $scope.showTakePicture = true; - localStream = stream; - $scope.showTakePictureReady = true; - attachMediaStream(video, stream); - safeApply($scope); - }, function(error) { - console.error('Failed to get access to local media. Error code was ' + error.code); - $scope.showTakePictureReady = true; - safeApply($scope); - }); - return; - } else { - var canvas = $(element).parent().find("canvas").get(0); - var videoWidth = video.videoWidth; - var videoHeight = video.videoHeight; - var aspectRatio = videoWidth / videoHeight; - if (!aspectRatio) { - // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! - console.warn("Unable to compute aspectRatio", aspectRatio); - aspectRatio = 1.3333333333333333; - } - var x = (46 * aspectRatio - 46) / -2 - canvas.getContext("2d").drawImage(video, x, 0, 46 * aspectRatio, 46); - $scope.user.buddyPicture = canvas.toDataURL("image/jpeg"); - console.info("Image size", $scope.user.buddyPicture.length); - localStream.stop(); - localStream = null; - $scope.showTakePictureReady = true; - $scope.showTakePicture = false; - safeApply($scope); - } - } - }; $scope.registerUserid = function(btn) { @@ -228,7 +165,7 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t template: template, controller: controller, link: link - } + }; }]; diff --git a/static/partials/buddypicture.html b/static/partials/buddypicture.html new file mode 100644 index 00000000..fde0b54f --- /dev/null +++ b/static/partials/buddypicture.html @@ -0,0 +1,20 @@ + diff --git a/static/partials/settings.html b/static/partials/settings.html index f4d011bb..8a53772d 100644 --- a/static/partials/settings.html +++ b/static/partials/settings.html @@ -5,17 +5,10 @@ {{_('Settings')}}
- +