Adding fraction timer display, exaggerating recording animation, moving delete button to toolbar, display full recording duration immediately after stop recording.

pull/1834/head
Warrick Corfe-Tan 4 years ago
parent b3b020a253
commit 123a60483e

@ -153,6 +153,28 @@ $session-font-h4: 16px;
color: subtle($color); color: subtle($color);
} }
@mixin pulse-color($color) {
animation: pulseColor 2s infinite;
@keyframes pulseColor {
0% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba($color, 0.7);
}
70% {
transform: scale(1);
box-shadow: 0 0 0 10px rgba($color, 0);
}
100% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba($color, 0);
}
}
}
$session-subtle-factor: 0.6; $session-subtle-factor: 0.6;
@function subtle($color) { @function subtle($color) {
@ -195,6 +217,23 @@ $session-fadein-duration: 0.1s;
} }
} }
@keyframes pulse-shadow {
0% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.7);
}
70% {
transform: scale(1);
box-shadow: 0 0 0 10px rgba(0, 0, 0, 0);
}
100% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
}
}
// ////////////////////////////////////////////// // //////////////////////////////////////////////
// ///////////////// Various //////////////////// // ///////////////// Various ////////////////////
// ////////////////////////////////////////////// // //////////////////////////////////////////////

@ -329,6 +329,10 @@
} }
} }
.send-message-button {
animation: fadein $session-transition-duration;
}
.session-recording { .session-recording {
height: $composition-container-height; height: $composition-container-height;
display: flex; display: flex;
@ -342,11 +346,14 @@
&--actions { &--actions {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center;
width: $actions-element-size; width: $actions-element-size;
height: $actions-element-size; height: $actions-element-size;
border-radius: 50%; border-radius: 50%;
.session-button {
animation: fadein $session-transition-duration;
}
.session-icon-button { .session-icon-button {
animation: fadein $session-transition-duration; animation: fadein $session-transition-duration;
opacity: 1; opacity: 1;
@ -415,6 +422,11 @@
&.playback-timer { &.playback-timer {
margin-right: $session-margin-sm; margin-right: $session-margin-sm;
animation: fadein $session-transition-duration;
@media (-webkit-min-device-pixel-ratio: 1.6) {
margin-left: auto;
}
} }
&-light { &-light {
@ -422,9 +434,9 @@
width: $session-margin-sm; width: $session-margin-sm;
border-radius: 50%; border-radius: 50%;
background-color: $session-color-danger-alt; background-color: $session-color-danger-alt;
margin-left: $session-margin-sm; margin: 0 $session-margin-sm;
animation: pulseLight 4s infinite; @include pulse-color($session-color-danger-alt);
} }
} }
} }

@ -45,6 +45,7 @@ export interface StyledFlexWrapperProps {
export const StyledFlexWrapper = styled.div` export const StyledFlexWrapper = styled.div`
display: flex; display: flex;
flex-direction: ${(props: StyledFlexWrapperProps) => props.flexDirection}; flex-direction: ${(props: StyledFlexWrapperProps) => props.flexDirection};
align-items: center;
.session-button { .session-button {
margin: ${(props: StyledFlexWrapperProps) => props.marginHorizontal}; margin: ${(props: StyledFlexWrapperProps) => props.marginHorizontal};
@ -105,10 +106,11 @@ class SessionRecordingInner extends React.Component<Props, State> {
nowTimestamp, nowTimestamp,
} = this.state; } = this.state;
const actionStopRecording = actionHover && isRecording; const hasRecordingAndPaused = !isRecording && !isPlaying;
const actionPlayAudio = !isRecording && !isPlaying;
const actionPauseAudio = !isRecording && !isPaused && isPlaying; const actionPauseAudio = !isRecording && !isPaused && isPlaying;
const actionDefault = !actionStopRecording && !actionPlayAudio && !actionPauseAudio;
// const actionDefault = !actionStopRecording && !actionPlayAudio && !actionPauseAudio;
const actionDefault = !isRecording && !hasRecordingAndPaused && !actionPauseAudio;
// if we are recording, we base the time recording on our state values // if we are recording, we base the time recording on our state values
// if we are playing ( audioElement?.currentTime is !== 0, use that instead) // if we are playing ( audioElement?.currentTime is !== 0, use that instead)
@ -119,11 +121,19 @@ class SessionRecordingInner extends React.Component<Props, State> {
: (this.audioElement && : (this.audioElement &&
(this.audioElement?.currentTime * 1000 || this.audioElement?.duration)) || (this.audioElement?.currentTime * 1000 || this.audioElement?.duration)) ||
0; 0;
let displayTimeString = moment.utc(displayTimeMs).format('m:ss');
const displayTimeString = moment.utc(displayTimeMs).format('m:ss'); const recordingLengthMs = this.audioElement?.duration ? this.audioElement?.duration * 1000 : undefined;
const actionPauseFn = isPlaying ? this.pauseAudio : this.stopRecordingStream;
const themeToUse = useTheme(); let remainingTimeString;
if (recordingLengthMs !== undefined) {
console.log({ recordingLengthMs });
console.log({ displayTimeMs });
remainingTimeString = ` / ${moment.utc(recordingLengthMs).format('m:ss')}`;
displayTimeString += remainingTimeString;
}
const actionPauseFn = isPlaying ? this.pauseAudio : this.stopRecordingStream;
return ( return (
<div role="main" className="session-recording" tabIndex={0} onKeyDown={this.onKeyDown}> <div role="main" className="session-recording" tabIndex={0} onKeyDown={this.onKeyDown}>
@ -132,7 +142,7 @@ class SessionRecordingInner extends React.Component<Props, State> {
onMouseEnter={this.handleHoverActions} onMouseEnter={this.handleHoverActions}
onMouseLeave={this.handleUnhoverActions} onMouseLeave={this.handleUnhoverActions}
> >
{actionStopRecording && ( {isRecording && (
<SessionIconButton <SessionIconButton
iconType={SessionIconType.Pause} iconType={SessionIconType.Pause}
iconSize={SessionIconSize.Medium} iconSize={SessionIconSize.Medium}
@ -147,12 +157,23 @@ class SessionRecordingInner extends React.Component<Props, State> {
onClick={actionPauseFn} onClick={actionPauseFn}
/> />
)} )}
{actionPlayAudio && ( {hasRecordingAndPaused && (
<SessionIconButton <StyledFlexWrapper
iconType={SessionIconType.Play} flexDirection='row'
iconSize={SessionIconSize.Medium} marginHorizontal={Constants.UI.SPACING.marginXs}
onClick={this.playAudio} >
/> <SessionIconButton
iconType={SessionIconType.Play}
iconSize={SessionIconSize.Medium}
onClick={this.playAudio}
/>
<SessionButton
text={window.i18n('delete')}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Secondary}
onClick={this.onDeleteVoiceMessage}
/>
</StyledFlexWrapper>
)} )}
{actionDefault && ( {actionDefault && (
@ -163,10 +184,14 @@ class SessionRecordingInner extends React.Component<Props, State> {
)} )}
</div> </div>
<div className={classNames('session-recording--timer', !isRecording && 'playback-timer')}> {isRecording || (!isRecording && remainingTimeString) ?
{displayTimeString} <div className={classNames('session-recording--timer', !isRecording && 'playback-timer')}>
{isRecording && <div className="session-recording--timer-light" />} {displayTimeString}
</div> {isRecording && <div className="session-recording--timer-light" />}
</div>
:
null
}
{!isRecording && ( {!isRecording && (
<div className="send-message-button"> <div className="send-message-button">
@ -179,35 +204,6 @@ class SessionRecordingInner extends React.Component<Props, State> {
</div> </div>
)} )}
<div className="session-recording--status">
{isRecording ? (
<SessionButton
// text={window.i18n('recording')}
text={'Stop recording'}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Primary}
onClick={this.stopRecordingStream}
/>
) : (
<StyledFlexWrapper
flexDirection='row'
marginHorizontal={themeToUse.common.margins.xs}
>
<SessionButton
text={window.i18n('delete')}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.DangerAlt}
onClick={this.onDeleteVoiceMessage}
/>
<SessionButton
text={'Send'}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Primary}
onClick={this.onSendVoiceMessage}
/>
</StyledFlexWrapper>
)}
</div>
</div> </div>
); );
} }
@ -352,10 +348,48 @@ class SessionRecordingInner extends React.Component<Props, State> {
this.recorder = undefined; this.recorder = undefined;
this.audioBlobMp3 = blob; this.audioBlobMp3 = blob;
this.updateAudioElementAndDuration();
// Stop recording // Stop recording
this.stopRecordingState(); this.stopRecordingState();
} }
private async onStopRecordingClick() {
this.stopRecordingStream();
this.updateAudioElementAndDuration();
this.stopRecordingState();
}
/**
* Creates an audio element using the recorded audio blob.
* Updates the duration for displaying audio duration.
*/
private updateAudioElementAndDuration() {
// init audio element
const audioURL = window.URL.createObjectURL(this.audioBlobMp3);
this.audioElement = new Audio(audioURL);
// ww adding record duration
this.setState({
recordDuration: this.audioElement.duration
})
this.audioElement.loop = false;
this.audioElement.onended = () => {
this.pauseAudio();
};
this.audioElement.oncanplaythrough = async () => {
const duration = this.state.recordDuration;
if (duration && this.audioElement && this.audioElement.currentTime < duration) {
await this.audioElement?.play();
}
};
}
private async onKeyDown(event: any) { private async onKeyDown(event: any) {
if (event.key === 'Escape') { if (event.key === 'Escape') {
await this.onDeleteVoiceMessage(); await this.onDeleteVoiceMessage();

Loading…
Cancel
Save