Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Audio recording as mp3 and better ui for recording #9726

Merged
merged 13 commits into from
Mar 15, 2018
Merged
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ packages/rocketchat-videobridge/client/public/external_api.js
packages/rocketchat-theme/client/vendor/
private/moment-locales/
public/livechat/
public/recorderWorker.js
public/mp3-realtime-worker.js
public/lame.min.js
4 changes: 3 additions & 1 deletion packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1262,8 +1262,10 @@
"Message_Attachments": "Message Attachments",
"Message_Attachments_GroupAttach": "Group Attachment Buttons",
"Message_Attachments_GroupAttachDescription": "This groups the icons under an expandable menu. Takes up less screen space.",
"Message_Audio": "Audio Message",
"Message_Audio_bitRate": "Audio Message Bit Rate",
"Message_AudioRecorderEnabled": "Audio Recorder Enabled",
"Message_AudioRecorderEnabledDescription": "Requires 'audio/wav' files to be an accepted media type within 'File Upload' settings.",
"Message_AudioRecorderEnabled_Description": "Requires 'audio/mp3' files to be an accepted media type within 'File Upload' settings.",
"Message_BadWordsFilterList": "Add Bad Words to the Blacklist",
"Message_BadWordsFilterListDescription": "Add List of Comma-separated list of bad words to filter",
"Message_DateFormat": "Date Format",
Expand Down
6 changes: 6 additions & 0 deletions packages/rocketchat-lib/server/startup/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1177,11 +1177,17 @@ RocketChat.settings.addGroup('Message', function() {
'public': true,
i18nDescription: 'Message_Attachments_GroupAttachDescription'
});
});
this.section('Message_Audio', function() {
this.add('Message_AudioRecorderEnabled', true, {
type: 'boolean',
'public': true,
i18nDescription: 'Message_AudioRecorderEnabledDescription'
});
this.add('Message_Audio_bitRate', 32, {
type: 'int',
'public': true
});
});
this.add('Message_AllowEditing', true, {
type: 'boolean',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,26 @@
& .rc-input__icon-svg--plus {
transition: transform 0.1s linear;
}

&.cross {
color: red;
}

&.loading {
cursor: pointer;
display: none;
&.active {
display: flex;
}
}

&.mic {
display: none;
&.active {
display: flex;
}
}

}

&__action-menu {
Expand All @@ -151,6 +171,33 @@
& [data-small] {
display: none;
}

&__audio-recording {
display: none;
position: relative;
z-index: -1;
&.active{
display: flex;
z-index: 2;
}
}

&__audio-message{
&.hidden{
z-index: -1;
}
}

&__timer-box{
display: flex;
width: 50px;
}

&__timer-dot{
font-size: 1.5em;
color: #d60000;
line-height: 0.8em;
}
}

@media (width <= 500px) {
Expand Down
24 changes: 24 additions & 0 deletions packages/rocketchat-ui-message/client/messageBox.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
{{> icon block="rc-input__icon-svg" icon="send"}}
</div>
{{else}}
{{> messageBox__audioMessage}}
{{> messageBox__actions}}
{{/unless}}
{{# messageBox__actionsSmall}}
Expand Down Expand Up @@ -90,6 +91,29 @@
{{/if}}
</div>
</template>
<template name="messageBox__audioMessage">
<div class="rc-message-box__audio-recording">
<div class="rc-message-box__icon cross js-audio-message-cross">
<img src="/images/circle-cross.svg">
</div>
<div class="rc-message-box__timer-box">
<p class="rc-message-box__timer-dot">&#8226;&nbsp;</p>
<span class="rc-message-box__timer"> 00:00</span>
</div>
<div class="rc-message-box__icon check js-audio-message-check">
<img src="/images/circle-check.svg">
</div>
</div>
<div class="rc-message-box__audio-message">
<div class="rc-message-box__icon mic active js-audio-message-record">
{{> icon block="rc-input__icon-svg" icon="mic"}}
</div>
<div class="rc-message-box__icon loading js-audio-message-loading">
<img class="rc-input__icon-svg" src="/images/loading.svg">
</div>
</div>
</template>

<template name="messageBox__actionsSmall">
<div class="js-message-actions rc-message-box__action-label" data-small>
{{#each actions }}
Expand Down
166 changes: 164 additions & 2 deletions packages/rocketchat-ui-message/client/messageBox.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* globals fileUpload KonchatNotification chatMessages popover isRtl */
/* globals fileUpload KonchatNotification chatMessages popover isRtl AudioRecorder chatMessages fileUploadHandler*/
import toastr from 'toastr';
import moment from 'moment';
import _ from 'underscore';

let audioMessageIntervalId;

function katexSyntax() {
if (RocketChat.katex.katex_enabled()) {
Expand Down Expand Up @@ -269,6 +272,9 @@ Template.messageBox.helpers({
},
isEmojiEnable() {
return RocketChat.getUserPreference(Meteor.user(), 'useEmojis');
},
isAudioMessageAllowed() {
return RocketChat.settings.get('FileUpload_Enabled') && RocketChat.settings.get('Message_AudioRecorderEnabled') && (!RocketChat.settings.get('FileUpload_MediaTypeWhiteList'));
}
});

Expand Down Expand Up @@ -452,7 +458,7 @@ Template.messageBox.events({
}
],
mousePosition: {
x: document.querySelector('.rc-message-box__textarea').getBoundingClientRect().right + 10,
x: document.querySelector('.rc-message-box__textarea').getBoundingClientRect().right + 40,
y: document.querySelector('.rc-message-box__textarea').getBoundingClientRect().top
},
customCSSProperties: {
Expand All @@ -465,6 +471,162 @@ Template.messageBox.events({
};

popover.open(config);
},
'click .js-audio-message-record'(event) {
event.preventDefault();
const icon = document.querySelector('.rc-message-box__audio-message');
const timer = document.querySelector('.rc-message-box__timer');
const timer_box = document.querySelector('.rc-message-box__audio-recording');

chatMessages[RocketChat.openedRoom].recording = true;
AudioRecorder.start(function() {
const startTime = new Date;
timer.innerHTML = '00:00';
audioMessageIntervalId = setInterval(()=> {
const now = new Date;
const distance = now-startTime;
let minutes = Math.floor(distance / (1000 * 60));
let seconds = Math.floor((distance % (1000 * 60)) / 1000);
if (minutes < 10) { minutes = `0${ minutes }`; }
if (seconds < 10) { seconds = `0${ seconds }`; }
timer.innerHTML = `${ minutes }:${ seconds }`;
}, 1000);

icon.classList.add('hidden');
timer_box.classList.add('active');
});
},
'click .js-audio-message-cross'(event) {
event.preventDefault();
const icon = document.querySelector('.rc-message-box__audio-message');
const timer = document.querySelector('.rc-message-box__timer');
const timer_box = document.querySelector('.rc-message-box__audio-recording');

timer_box.classList.remove('active');
icon.classList.remove('hidden');
timer.innerHTML = '00:00';
if (audioMessageIntervalId) {
clearInterval(audioMessageIntervalId);
}

AudioRecorder.stop();
chatMessages[RocketChat.openedRoom].recording = false;
},
'click .js-audio-message-check'(event) {
event.preventDefault();
const icon = document.querySelector('.rc-message-box__audio-message');
const timer = document.querySelector('.rc-message-box__timer');
const timer_box = document.querySelector('.rc-message-box__audio-recording');
const loader = document.querySelector('.js-audio-message-loading');
const mic = document.querySelector('.js-audio-message-record');

icon.classList.remove('hidden');
timer_box.classList.remove('active');
mic.classList.remove('active');
loader.classList.add('active');

timer.innerHTML = '00:00';
if (audioMessageIntervalId) {
clearInterval(audioMessageIntervalId);
}

chatMessages[RocketChat.openedRoom].recording = false;
AudioRecorder.stop(function(blob) {

loader.classList.remove('active');
mic.classList.add('active');
const roomId = Session.get('openedRoom');
const record = {
name: `${ TAPi18n.__('Audio record') }.mp3`,
size: blob.size,
type: 'audio/mp3',
rid: roomId,
description: ''
};
const upload = fileUploadHandler('Uploads', record, blob);
let uploading = Session.get('uploading') || [];
uploading.push({
id: upload.id,
name: upload.getFileName(),
percentage: 0
});
Session.set('uploading', uploading);
upload.onProgress = function(progress) {
uploading = Session.get('uploading');

const item = _.findWhere(uploading, {id: upload.id});
if (item != null) {
item.percentage = Math.round(progress * 100) || 0;
return Session.set('uploading', uploading);
}
};

upload.start(function(error, file, storage) {
if (error) {
let uploading = Session.get('uploading');
if (!Array.isArray(uploading)) {
uploading = [];
}

const item = _.findWhere(uploading, { id: upload.id });

if (_.isObject(item)) {
item.error = error.message;
item.percentage = 0;
} else {
uploading.push({
error: error.error,
percentage: 0
});
}

Session.set('uploading', uploading);
return;
}


if (file) {
Meteor.call('sendFileMessage', roomId, storage, file, () => {
Meteor.setTimeout(() => {
const uploading = Session.get('uploading');
if (uploading !== null) {
const item = _.findWhere(uploading, {
id: upload.id
});
return Session.set('uploading', _.without(uploading, item));
}
}, 2000);
});
}
});

Tracker.autorun(function(c) {
const cancel = Session.get(`uploading-cancel-${ upload.id }`);
if (cancel) {
let item;
upload.stop();
c.stop();

uploading = Session.get('uploading');
if (uploading != null) {
item = _.findWhere(uploading, {id: upload.id});
if (item != null) {
item.percentage = 0;
}
Session.set('uploading', uploading);
}

return Meteor.setTimeout(function() {
uploading = Session.get('uploading');
if (uploading != null) {
item = _.findWhere(uploading, {id: upload.id});
return Session.set('uploading', _.without(uploading, item));
}
}, 1000);
}
});
});
return false;
}
});

Expand Down
36 changes: 1 addition & 35 deletions packages/rocketchat-ui-message/startup/messageBoxActions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* globals fileUpload chatMessages AudioRecorder device popover modal */
/* globals fileUpload device modal */

import mime from 'mime-type/with-db';
import {VRecDialog} from 'meteor/rocketchat:ui-vrecord';
Expand All @@ -12,40 +12,6 @@ RocketChat.messageBox.actions.add('Create_new', 'Video_message', {
}
});

RocketChat.messageBox.actions.add('Create_new', 'Audio_message', {
id: 'audio-message',
icon: 'mic',
condition: () => (navigator.getUserMedia || navigator.webkitGetUserMedia) && RocketChat.settings.get('FileUpload_Enabled') && RocketChat.settings.get('Message_AudioRecorderEnabled') && (!RocketChat.settings.get('FileUpload_MediaTypeWhiteList') || RocketChat.settings.get('FileUpload_MediaTypeWhiteList').match(/audio\/wav|audio\/\*/i)),
action({event, element}) {
event.preventDefault();
const icon = element.querySelector('.rc-icon');

if (chatMessages[RocketChat.openedRoom].recording) {
AudioRecorder.stop(function(blob) {
popover.close();
icon.style.color = '';
icon.classList.remove('pulse');
chatMessages[RocketChat.openedRoom].recording = false;
fileUpload([
{
file: blob,
type: 'audio',
name: `${ TAPi18n.__('Audio record') }.wav`
}
]);
});
return false;
}

chatMessages[RocketChat.openedRoom].recording = true;
AudioRecorder.start(function() {
icon.classList.add('pulse');
icon.style.color = 'red';
});
}
});


RocketChat.messageBox.actions.add('Add_files_from', 'Computer', {
id: 'file-upload',
icon: 'computer',
Expand Down
Loading