Browse Source

Voice record in desktop version

master
Igor Zhukov 7 years ago
parent
commit
1071104ac1
  1. BIN
      app/img/icons/IconsetW.png
  2. BIN
      app/img/icons/IconsetW_2x.png
  3. 63
      app/js/directives.js
  4. 2
      app/js/locales/en-us.json
  5. 3
      app/js/message_composer.js
  6. 70
      app/less/app.less
  7. 89
      app/less/desktop.less
  8. 77
      app/less/mobile.less
  9. 16
      app/partials/desktop/send_form.html

BIN
app/img/icons/IconsetW.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

BIN
app/img/icons/IconsetW_2x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

63
app/js/directives.js

@ -1494,6 +1494,9 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1494,6 +1494,9 @@ angular.module('myApp.directives', ['myApp.filters'])
return
}
if ($(sendFormWrap).is(':visible')) {
if (!sendForm || !sendForm.offsetHeight) {
sendForm = $('.im_send_form', element)[0]
}
$(sendFormWrap).css({
height: $(sendForm).height()
})
@ -1552,7 +1555,6 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1552,7 +1555,6 @@ angular.module('myApp.directives', ['myApp.filters'])
return {
link: link,
templateUrl: templateUrl('send_form'),
replace: true,
scope: {
draftMessage: '=',
mentions: '=',
@ -1561,16 +1563,16 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1561,16 +1563,16 @@ angular.module('myApp.directives', ['myApp.filters'])
}
function link ($scope, element, attrs) {
var messageFieldWrap = $('.im_send_field_wrap', element)[0]
var messageField = $('textarea', element)[0]
var emojiButton = $('.composer_emoji_insert_btn', element)[0]
var emojiPanel = $('.composer_emoji_panel', element)[0]
var fileSelects = $('input', element)
var dropbox = $('.im_send_dropbox_wrap', element)[0]
var messageFieldWrap = $('.im_send_field_wrap', element)[0]
var sendFieldPanel = $('.im_send_field_panel', element)[0]
var dragStarted
var dragTimeout
var submitBtn = $('.im_submit', element)[0]
var voiceRecorderWrap = $('.im_voice_recorder_wrap', element)[0]
var voiceRecordBtn = $('.im_record', element)[0]
var stickerImageCompiled = $compile('<a class="composer_sticker_btn" data-sticker="{{::document.id}}" my-load-sticker document="document" thumb="true" img-class="composer_sticker_image"></a>')
@ -1581,7 +1583,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1581,7 +1583,7 @@ angular.module('myApp.directives', ['myApp.filters'])
var voiceRecordDurationInterval = null
var voiceRecorderPromise = null
if (voiceRecordSupported) {
$(sendFieldPanel).addClass('im_record_supported')
element.addClass('im_record_supported')
}
$scope.voiceRecorder = {duration: 0, recording: false, processing: false}
@ -1700,7 +1702,13 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1700,7 +1702,13 @@ angular.module('myApp.directives', ['myApp.filters'])
$(voiceRecordBtn).on('contextmenu', cancelEvent)
$(voiceRecordBtn).on('touchstart', function(event) {
var voiceRecordTouch = Config.Navigator.touch ? true : false
var voiceRecordEvents = {
start: voiceRecordTouch ? 'touchstart' : 'mousedown',
move: voiceRecordTouch ? 'touchmove' : 'mousemove',
stop: voiceRecordTouch ? 'touchend' : 'mouseup'
}
$(voiceRecordBtn).on(voiceRecordEvents.start, function(event) {
if ($scope.voiceRecorder.processing) {
return
}
@ -1739,18 +1747,23 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1739,18 +1747,23 @@ angular.module('myApp.directives', ['myApp.filters'])
var curBoundaries = {}
var updateVoiceHoverBoundaries = function () {
var offset = element.offset()
var boundElement = $('.im_bottom_panel_wrap')
// console.warn(dT(), 'bound', boundElement[0])
var offset = boundElement.offset()
curBoundaries = {
top: offset.top,
left: offset.left,
width: element.outerWidth(),
height: element.outerHeight(),
width: boundElement.outerWidth(),
height: boundElement.outerHeight(),
}
}
var updateVoiceHoveredClass = function (event, returnHover) {
var originalEvent = event.originalEvent || event
var touch = originalEvent.changedTouches && originalEvent.changedTouches[0]
var touch = voiceRecordTouch
? originalEvent.changedTouches && originalEvent.changedTouches[0]
: originalEvent
// console.log('event', voiceRecordTouch, originalEvent)
var isHover = touch &&
touch.pageX >= curBoundaries.left &&
touch.pageX <= curBoundaries.left + curBoundaries.width &&
@ -1758,6 +1771,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1758,6 +1771,7 @@ angular.module('myApp.directives', ['myApp.filters'])
touch.pageY <= curBoundaries.top + curBoundaries.height
if (curHover != isHover) {
console.warn(dT(), 'change hover', isHover)
element.toggleClass('im_send_form_hover', isHover)
curHover = isHover
}
@ -1767,10 +1781,18 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1767,10 +1781,18 @@ angular.module('myApp.directives', ['myApp.filters'])
updateVoiceHoverBoundaries()
updateVoiceHoveredClass(event)
$($window).on('touchmove', updateVoiceHoveredClass)
if (!Config.Mobile) {
$(voiceRecorderWrap).css({
height: messageFieldWrap.offsetHeight,
width: messageFieldWrap.offsetWidth
})
}
$($window).on(voiceRecordEvents.move, updateVoiceHoveredClass)
$($window).one('touchend', function(event) {
$($window).off('touchmove', updateVoiceHoveredClass)
$($window).one(voiceRecordEvents.stop, function(event) {
console.warn(111)
$($window).off(voiceRecordEvents.move, updateVoiceHoveredClass)
var isHover = updateVoiceHoveredClass(event, true)
@ -1982,14 +2004,14 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1982,14 +2004,14 @@ angular.module('myApp.directives', ['myApp.filters'])
if (e.type == 'dragenter' || e.type == 'dragover') {
if (dragStateChanged) {
if (!Config.Mobile) {
$(emojiButton).hide()
}
$(dropbox)
.css({height: messageFieldWrap.offsetHeight + 2, width: messageFieldWrap.offsetWidth})
.show()
$(dropbox).css({
height: messageFieldWrap.offsetHeight,
width: messageFieldWrap.offsetWidth
})
element.addClass('im_send_form_dragging')
}
} else {
return cancelEvent(e)
if (e.type == 'drop') {
$scope.$apply(function () {
$scope.draftMessage.files = Array.prototype.slice.call(e.originalEvent.dataTransfer.files)
@ -1997,10 +2019,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1997,10 +2019,7 @@ angular.module('myApp.directives', ['myApp.filters'])
})
}
dragTimeout = setTimeout(function () {
$(dropbox).hide()
if (!Config.Mobile) {
$(emojiButton).show()
}
element.removeClass('im_send_form_dragging')
dragStarted = false
dragTimeout = false
}, 300)

2
app/js/locales/en-us.json

@ -530,7 +530,7 @@ @@ -530,7 +530,7 @@
"im_submit_message": "Send",
"im_submit_edit_message": "Save",
"im_edit_message_title": "Edit message",
"im_voice_recording_label": "Release outside this field to cancel",
"im_voice_recording_label": "Release outside this form to cancel",
"im_voice_processing_label": "Processing{dots}",
"login_sign_in": "Sign in",
"login_enter_number_description": "Please choose your country and enter your full phone number.",

3
app/js/message_composer.js

@ -1610,7 +1610,8 @@ MessageComposer.prototype.resetTyping = function () { @@ -1610,7 +1610,8 @@ MessageComposer.prototype.resetTyping = function () {
}
MessageComposer.prototype.setPlaceholder = function (newPlaceholder) {
(this.richTextareaEl || this.textareaEl).attr('placeholder', newPlaceholder)
console.warn(dT(), 'set placeholder', this.richTextareaEl)
;(this.richTextareaEl || this.textareaEl).attr('placeholder', newPlaceholder)
}
function Scroller (content, options) {

70
app/less/app.less

@ -2551,6 +2551,21 @@ a.im_message_fwd_photo { @@ -2551,6 +2551,21 @@ a.im_message_fwd_photo {
color: #999;
position: absolute;
}
.im_send_form_dragging {
.im_send_dropbox_wrap {
display: block;
}
.composer_rich_textarea,
.im_message_field,
.composer_emoji_insert_btn,
.composer_progress_icon_wrap,
.composer_command_btn,
.composer_keyboard_btn,
.im_inline_placeholder_wrap {
visibility: hidden;
}
}
.im_send_field_wrap {
position: relative;
}
@ -3505,6 +3520,61 @@ li.inline_result_sticker.composer_autocomplete_option_active a { @@ -3505,6 +3520,61 @@ li.inline_result_sticker.composer_autocomplete_option_active a {
}
.im_voice_recorder_wrap {
display: none;
z-index: 100;
}
.im_recorder_indicator, .im_recorder_time {
float: left;
vertical-align: middle;
color: #333;
}
.im_recorder_indicator i {
background-color: #ff1010;
height: 10px;
width: 10px;
border-radius: 50%;
margin-right: 5px;
vertical-align: baseline;
display: inline-block;
animation: blinker 0.5s cubic-bezier(.5, 0, 1, 1) infinite alternate;
}
@keyframes blinker {
from { opacity: 1; }
to { opacity: 0; }
}
.im_recorder_label {
overflow: auto;
font-size: 12px;
text-align: center;
vertical-align: middle;
color: #3a6d99;
transition: color linear 0.2s;
i {
margin-right: 5px;
}
.im_send_form_hover & {
color: #CCC;
}
}
.im_voice_recording,
.im_processing_recording {
color: #AAA;
.im_voice_recorder_wrap {
display: block;
}
}
.error_modal_window {
.modal-dialog {
max-width: 350px;

89
app/less/desktop.less

@ -1290,6 +1290,75 @@ a.im_panel_peer_photo .peer_initials { @@ -1290,6 +1290,75 @@ a.im_panel_peer_photo .peer_initials {
}
}
.im_record {
display: none;
width: 50px;
height: 50px;
margin: -8px 0 0 -18px;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
padding: 13px 16px 13px 16px;
border-radius: 50px;
overflow: hidden;
background: #fff;
transition: background-color linear 0.2s;
.im_record_supported & {
display: block;
}
}
.im_send_form_hover .im_voice_recording .im_record {
background: #bfd9ed;
}
.icon-mic {
display: inline-block;
width: 18px;
height: 22px;
vertical-align: text-top;
opacity: 0.8;
.image-2x('../img/icons/IconsetW.png', 42px, 1171px);
background-position: -12px -285px;
background-color: transparent;
.im_record:hover & {
opacity: 1;
}
.im_record:active &,
.im_voice_recording & {
background-position: -12px -705px;
}
}
.im_voice_recorder_wrap {
padding: 17px 10px 0;
display: none;
position: absolute;
}
.im_voice_recording,
.im_processing_recording {
.im_voice_recorder_wrap {
display: block;
}
.composer_rich_textarea,
.im_message_field,
.composer_emoji_insert_btn,
.composer_progress_icon_wrap,
.composer_command_btn,
.composer_keyboard_btn,
.im_inline_placeholder_wrap {
visibility: hidden;
}
}
@media (max-height: 600px) {
a {
&.im_panel_peer_photo,
@ -1340,6 +1409,10 @@ a.im_panel_peer_photo .peer_initials { @@ -1340,6 +1409,10 @@ a.im_panel_peer_photo .peer_initials {
top: 0;
left: 100%;
margin: 0 0 0 15px;
.im_record_supported .im_send_form_empty & {
display: none;
}
}
.im_media_attach {
position: absolute;
@ -1412,6 +1485,22 @@ a.im_panel_peer_photo .peer_initials { @@ -1412,6 +1485,22 @@ a.im_panel_peer_photo .peer_initials {
padding-top: 5px;
padding-bottom: 5px;
}
.im_record {
display: none;
position: absolute;
top: -4px;
right: -56px;
.im_record_supported .im_send_form_empty & {
display: block;
}
}
.im_voice_recorder_wrap {
padding-top: 4px;
}
}
.im_edit_panel {

77
app/less/mobile.less

@ -1473,7 +1473,7 @@ a.im_message_fwd_author { @@ -1473,7 +1473,7 @@ a.im_message_fwd_author {
.im_record {
display: none;
right: 0;
top: -9px;
top: -8px;
width: 50px;
height: 50px;
position: absolute;
@ -1488,7 +1488,7 @@ a.im_message_fwd_author { @@ -1488,7 +1488,7 @@ a.im_message_fwd_author {
background: #fff;
transition: background-color linear 0.2s;
.im_send_form_empty .im_record_supported & {
.im_record_supported .im_send_form_empty & {
display: block;
}
}
@ -1499,13 +1499,24 @@ a.im_message_fwd_author { @@ -1499,13 +1499,24 @@ a.im_message_fwd_author {
.im_send_form_empty .im_submit {
opacity: 0.4;
}
.im_send_form_empty .im_record_supported .im_submit {
.im_record_supported .im_send_form_empty .im_submit {
display: none;
}
.im_voice_recorder_wrap {
height: 32px;
line-height: 32px;
right: 50px;
left: 0;
padding: 0 0 0 20px;
}
.im_recorder_label {
padding-right: 48px;
}
.im_voice_recording,
.im_processing_recording {
.im_processing_recording {
color: #AAA;
.im_voice_recorder_wrap {
@ -1515,11 +1526,12 @@ a.im_message_fwd_author { @@ -1515,11 +1526,12 @@ a.im_message_fwd_author {
.im_submit,
.im_attach {
display: none;
// visibility: hidden;
}
}
.im_processing_recording {
.im_recorder_indicator i {
.im_recorder_indicator i {
background-color: green;
}
@ -1563,61 +1575,6 @@ a.im_message_fwd_author { @@ -1563,61 +1575,6 @@ a.im_message_fwd_author {
}
}
.im_voice_recorder_wrap {
height: 32px;
display: none;
line-height: 32px;
right: 50px;
left: 0;
z-index: 100;
padding: 0 0 0 20px;
}
.im_recorder_indicator, .im_recorder_time {
float: left;
vertical-align: middle;
color: #333;
}
.im_recorder_indicator i {
background-color: #ff1010;
height: 10px;
width: 10px;
border-radius: 50%;
margin-right: 5px;
vertical-align: baseline;
display: inline-block;
animation: blinker 0.5s cubic-bezier(.5, 0, 1, 1) infinite alternate;
}
@keyframes blinker {
from { opacity: 1; }
to { opacity: 0; }
}
.im_recorder_label {
overflow: auto;
font-size: 12px;
text-align: center;
vertical-align: middle;
padding-right: 48px;
color: #3a6d99;
transition: color linear 0.2s;
i, span {
vertical-align: middle;
}
i {
margin-right: 5px;
}
.im_send_form_hover & {
color: #CCC;
}
}
.composer_rich_textarea {
min-height: 18px;
max-height: 136px;

16
app/partials/desktop/send_form.html

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<form class="im_send_form" ng-class="{im_send_form_empty: !draftMessage.text.length, composer_progress_enabled: draftMessage.inlineProgress}">
<form class="im_send_form" ng-class="{im_send_form_empty: !draftMessage.text.length, composer_progress_enabled: draftMessage.inlineProgress, im_voice_recording: voiceRecorder.recording, im_processing_recording: voiceRecorder.processing}">
<div class="im_send_form_inline_results" my-inline-results="inlineResults"></div>
@ -21,6 +21,16 @@ @@ -21,6 +21,16 @@
<a class="composer_keyboard_btn" ng-show="historyState.replyKeyboard._ == 'replyKeyboardMarkup'" ng-mousedown="draftMessage.replyKeyboardToggle($event)" ng-class="!historyState.replyKeyboard.pFlags.hidden ? 'active' : ''"><i class="icon icon-keyboard"></i></a>
<div class="im_send_dropbox_wrap" my-i18n="im_photos_drop_text"></div>
<div class="im_voice_recorder_wrap">
<div class="im_recorder_indicator"><i></i></div>
<div class="im_recorder_time" ng-bind="voiceRecorder.duration | duration"></div>
<div class="im_recorder_label" ng-switch="voiceRecorder.processing" my-i18n>
<span ng-switch-when="true" my-i18n-format="im_voice_processing_label"></span>
<span ng-switch-default my-i18n-format="im_voice_recording_label"></span>
<my-i18n-param name="dots"></my-i18n-param>
</div>
</div>
<textarea ng-model="draftMessage.text" class="form-control im_message_field no_outline" dir="auto" ng-trim="false"></textarea>
</div>
@ -40,6 +50,10 @@ @@ -40,6 +50,10 @@
<i class="icon icon-camera"></i>
</div>
<a class="im_record pull-left">
<i class="icon icon-mic"></i>
</a>
<div class="composer_emoji_panel"></div>
</div>

Loading…
Cancel
Save