Update colours and sizing for voice messages
Fixes https://github.com/vector-im/element-web/issues/17162
This commit is contained in:
parent
2bf931b9d3
commit
a94c1a90c1
9 changed files with 45 additions and 40 deletions
|
@ -39,7 +39,7 @@ limitations under the License.
|
||||||
width: 14px; // w&h are size of icon
|
width: 14px; // w&h are size of icon
|
||||||
height: 18px;
|
height: 18px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: 7px; // distance from left edge of waveform container (container has some margin too)
|
margin-right: 11px; // distance from left edge of waveform container (container has some margin too)
|
||||||
background-color: $voice-record-icon-color;
|
background-color: $voice-record-icon-color;
|
||||||
mask-repeat: no-repeat;
|
mask-repeat: no-repeat;
|
||||||
mask-size: contain;
|
mask-size: contain;
|
||||||
|
@ -55,7 +55,9 @@ limitations under the License.
|
||||||
position: relative; // important for the live circle
|
position: relative; // important for the live circle
|
||||||
|
|
||||||
&.mx_VoiceRecordComposerTile_recording {
|
&.mx_VoiceRecordComposerTile_recording {
|
||||||
padding-left: 16px; // +10px for the live circle, +6px for regular padding
|
// We are putting the circle in this padding, so we need +10px from the regular
|
||||||
|
// padding on the left side.
|
||||||
|
padding-left: 22px;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
animation: recording-pulse 2s infinite;
|
animation: recording-pulse 2s infinite;
|
||||||
|
@ -65,8 +67,8 @@ limitations under the License.
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 8px;
|
left: 12px; // 12px from the left edge for container padding
|
||||||
top: 16px; // vertically center
|
top: 18px; // vertically center (middle align with clock)
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,9 @@ limitations under the License.
|
||||||
|
|
||||||
// Container for live recording and playback controls
|
// Container for live recording and playback controls
|
||||||
.mx_VoiceMessagePrimaryContainer {
|
.mx_VoiceMessagePrimaryContainer {
|
||||||
padding: 6px; // makes us 4px taller than the send/stop button
|
// 7px top and bottom for visual design. 12px left & right, but the waveform (right)
|
||||||
padding-right: 5px; // there's 1px from the waveform itself, so account for that
|
// has a 1px padding on it that we want to account for.
|
||||||
|
padding: 7px 12px 7px 11px;
|
||||||
background-color: $voice-record-waveform-bg-color;
|
background-color: $voice-record-waveform-bg-color;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
||||||
|
@ -30,11 +31,9 @@ limitations under the License.
|
||||||
|
|
||||||
color: $voice-record-waveform-fg-color;
|
color: $voice-record-waveform-fg-color;
|
||||||
font-size: $font-14px;
|
font-size: $font-14px;
|
||||||
|
line-height: $font-24px;
|
||||||
|
|
||||||
.mx_Waveform {
|
.mx_Waveform {
|
||||||
// We want the bars to be 2px shorter than the play/pause button in the waveform control
|
|
||||||
height: 28px; // default is 30px, so we're subtracting the 2px border off the bars
|
|
||||||
|
|
||||||
.mx_Waveform_bar {
|
.mx_Waveform_bar {
|
||||||
background-color: $voice-record-waveform-incomplete-fg-color;
|
background-color: $voice-record-waveform-incomplete-fg-color;
|
||||||
|
|
||||||
|
@ -47,8 +46,8 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Clock {
|
.mx_Clock {
|
||||||
padding-right: 4px; // isolate from waveform
|
width: 42px; // we're not using a monospace font, so fake it
|
||||||
padding-left: 8px; // isolate from live circle
|
padding-right: 6px; // with the fixed width this ends up as a visual 8px most of the time, as intended.
|
||||||
width: 40px; // we're not using a monospace font, so fake it
|
padding-left: 8px; // isolate from recording circle / play control
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,13 @@ $preview-bar-bg-color: $header-panel-bg-color;
|
||||||
$groupFilterPanel-bg-color: rgba(38, 39, 43, 0.82);
|
$groupFilterPanel-bg-color: rgba(38, 39, 43, 0.82);
|
||||||
$inverted-bg-color: $base-color;
|
$inverted-bg-color: $base-color;
|
||||||
|
|
||||||
$voice-record-stop-border-color: #6F7882; // "Quarterly"
|
$voice-record-stop-border-color: #6F7882; // "Quartary"
|
||||||
$voice-record-waveform-bg-color: #394049; // "Dark Tile"
|
$voice-record-waveform-bg-color: #394049; // "Dark Tile"
|
||||||
$voice-record-waveform-fg-color: $tertiary-fg-color;
|
$voice-record-waveform-fg-color: $secondary-fg-color;
|
||||||
$voice-record-waveform-incomplete-fg-color: #5b646d;
|
$voice-record-waveform-incomplete-fg-color: #6F7882; // "Quartary"
|
||||||
$voice-record-icon-color: $tertiary-fg-color;
|
$voice-record-icon-color: #6F7882; // "Quartary"
|
||||||
$voice-playback-button-bg-color: $tertiary-fg-color;
|
$voice-playback-button-bg-color: $tertiary-fg-color;
|
||||||
$voice-playback-button-fg-color: $bg-color;
|
$voice-playback-button-fg-color: #21262C; // "Separator"
|
||||||
|
|
||||||
// used by AddressSelector
|
// used by AddressSelector
|
||||||
$selected-color: $room-highlight-color;
|
$selected-color: $room-highlight-color;
|
||||||
|
|
|
@ -127,11 +127,11 @@ $groupFilterPanel-divider-color: $roomlist-header-color;
|
||||||
// See non-legacy dark for variable information
|
// See non-legacy dark for variable information
|
||||||
$voice-record-stop-border-color: #6F7882;
|
$voice-record-stop-border-color: #6F7882;
|
||||||
$voice-record-waveform-bg-color: #394049;
|
$voice-record-waveform-bg-color: #394049;
|
||||||
$voice-record-waveform-fg-color: $tertiary-fg-color;
|
$voice-record-waveform-fg-color: $secondary-fg-color;
|
||||||
$voice-record-waveform-incomplete-fg-color: #5b646d;
|
$voice-record-waveform-incomplete-fg-color: #6F7882;
|
||||||
$voice-record-icon-color: $tertiary-fg-color;
|
$voice-record-icon-color: #6F7882;
|
||||||
$voice-playback-button-bg-color: $tertiary-fg-color;
|
$voice-playback-button-bg-color: $tertiary-fg-color;
|
||||||
$voice-playback-button-fg-color: $bg-color;
|
$voice-playback-button-fg-color: #21262C;
|
||||||
|
|
||||||
$roomtile-preview-color: #9e9e9e;
|
$roomtile-preview-color: #9e9e9e;
|
||||||
$roomtile-default-badge-bg-color: #61708b;
|
$roomtile-default-badge-bg-color: #61708b;
|
||||||
|
|
|
@ -192,15 +192,15 @@ $roomsublist-skeleton-ui-bg: linear-gradient(180deg, #ffffff 0%, #ffffff00 100%)
|
||||||
$groupFilterPanel-divider-color: $roomlist-header-color;
|
$groupFilterPanel-divider-color: $roomlist-header-color;
|
||||||
|
|
||||||
// See non-legacy _light for variable information
|
// See non-legacy _light for variable information
|
||||||
$voice-record-stop-border-color: #E3E8F0;
|
|
||||||
$voice-record-stop-symbol-color: #ff4b55;
|
$voice-record-stop-symbol-color: #ff4b55;
|
||||||
$voice-record-waveform-bg-color: #E3E8F0;
|
|
||||||
$voice-record-waveform-fg-color: $muted-fg-color;
|
|
||||||
$voice-record-waveform-incomplete-fg-color: #C1C6CD;
|
|
||||||
$voice-record-live-circle-color: #ff4b55;
|
$voice-record-live-circle-color: #ff4b55;
|
||||||
$voice-record-icon-color: $muted-fg-color;
|
$voice-record-stop-border-color: #E3E8F0;
|
||||||
|
$voice-record-waveform-bg-color: #E3E8F0;
|
||||||
|
$voice-record-waveform-fg-color: $secondary-fg-color;
|
||||||
|
$voice-record-waveform-incomplete-fg-color: #C1C6CD;
|
||||||
|
$voice-record-icon-color: $tertiary-fg-color;
|
||||||
$voice-playback-button-bg-color: $primary-bg-color;
|
$voice-playback-button-bg-color: $primary-bg-color;
|
||||||
$voice-playback-button-fg-color: $muted-fg-color;
|
$voice-playback-button-fg-color: $secondary-fg-color;
|
||||||
|
|
||||||
$roomtile-preview-color: #9e9e9e;
|
$roomtile-preview-color: #9e9e9e;
|
||||||
$roomtile-default-badge-bg-color: #61708b;
|
$roomtile-default-badge-bg-color: #61708b;
|
||||||
|
|
|
@ -182,15 +182,18 @@ $roomsublist-skeleton-ui-bg: linear-gradient(180deg, #ffffff 0%, #ffffff00 100%)
|
||||||
|
|
||||||
$groupFilterPanel-divider-color: $roomlist-header-color;
|
$groupFilterPanel-divider-color: $roomlist-header-color;
|
||||||
|
|
||||||
$voice-record-stop-border-color: #E3E8F0;
|
// These two don't change between themes. They are the $warning-color, but we don't
|
||||||
$voice-record-stop-symbol-color: #ff4b55; // $warning-color, but without letting people change it in themes
|
// want custom themes to affect them by accident.
|
||||||
$voice-record-waveform-bg-color: #E3E8F0;
|
$voice-record-stop-symbol-color: #ff4b55;
|
||||||
$voice-record-waveform-fg-color: $muted-fg-color;
|
$voice-record-live-circle-color: #ff4b55;
|
||||||
$voice-record-waveform-incomplete-fg-color: #C1C6CD;
|
|
||||||
$voice-record-live-circle-color: #ff4b55; // $warning-color, but without letting people change it in themes
|
$voice-record-stop-border-color: #E3E8F0; // "Separator"
|
||||||
$voice-record-icon-color: $muted-fg-color;
|
$voice-record-waveform-bg-color: #E3E8F0; // "Separator"
|
||||||
|
$voice-record-waveform-fg-color: $secondary-fg-color;
|
||||||
|
$voice-record-waveform-incomplete-fg-color: #C1C6CD; // "Quartary"
|
||||||
|
$voice-record-icon-color: $tertiary-fg-color;
|
||||||
$voice-playback-button-bg-color: $primary-bg-color;
|
$voice-playback-button-bg-color: $primary-bg-color;
|
||||||
$voice-playback-button-fg-color: $muted-fg-color;
|
$voice-playback-button-fg-color: $secondary-fg-color;
|
||||||
|
|
||||||
$roomtile-preview-color: $secondary-fg-color;
|
$roomtile-preview-color: $secondary-fg-color;
|
||||||
$roomtile-default-badge-bg-color: #61708b;
|
$roomtile-default-badge-bg-color: #61708b;
|
||||||
|
|
|
@ -15,12 +15,11 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {IRecordingUpdate, VoiceRecording} from "../../../voice/VoiceRecording";
|
import {IRecordingUpdate, RECORDING_PLAYBACK_SAMPLES, VoiceRecording} from "../../../voice/VoiceRecording";
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||||
import {arrayFastResample, arraySeed} from "../../../utils/arrays";
|
import {arrayFastResample, arraySeed} from "../../../utils/arrays";
|
||||||
import {percentageOf} from "../../../utils/numbers";
|
import {percentageOf} from "../../../utils/numbers";
|
||||||
import Waveform from "./Waveform";
|
import Waveform from "./Waveform";
|
||||||
import {PLAYBACK_WAVEFORM_SAMPLES} from "../../../voice/Playback";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
recorder: VoiceRecording;
|
recorder: VoiceRecording;
|
||||||
|
@ -38,14 +37,14 @@ export default class LiveRecordingWaveform extends React.PureComponent<IProps, I
|
||||||
public constructor(props) {
|
public constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {heights: arraySeed(0, PLAYBACK_WAVEFORM_SAMPLES)};
|
this.state = {heights: arraySeed(0, RECORDING_PLAYBACK_SAMPLES)};
|
||||||
this.props.recorder.liveData.onUpdate(this.onRecordingUpdate);
|
this.props.recorder.liveData.onUpdate(this.onRecordingUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRecordingUpdate = (update: IRecordingUpdate) => {
|
private onRecordingUpdate = (update: IRecordingUpdate) => {
|
||||||
// The waveform and the downsample target are pretty close, so we should be fine to
|
// The waveform and the downsample target are pretty close, so we should be fine to
|
||||||
// do this, despite the docs on arrayFastResample.
|
// do this, despite the docs on arrayFastResample.
|
||||||
const bars = arrayFastResample(Array.from(update.waveform), PLAYBACK_WAVEFORM_SAMPLES);
|
const bars = arrayFastResample(Array.from(update.waveform), RECORDING_PLAYBACK_SAMPLES);
|
||||||
this.setState({
|
this.setState({
|
||||||
// The incoming data is between zero and one, but typically even screaming into a
|
// The incoming data is between zero and one, but typically even screaming into a
|
||||||
// microphone won't send you over 0.6, so we artificially adjust the gain for the
|
// microphone won't send you over 0.6, so we artificially adjust the gain for the
|
||||||
|
|
|
@ -29,7 +29,7 @@ export enum PlaybackState {
|
||||||
Playing = "playing", // active progress through timeline
|
Playing = "playing", // active progress through timeline
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PLAYBACK_WAVEFORM_SAMPLES = 35;
|
export const PLAYBACK_WAVEFORM_SAMPLES = 38;
|
||||||
const DEFAULT_WAVEFORM = arraySeed(0, PLAYBACK_WAVEFORM_SAMPLES);
|
const DEFAULT_WAVEFORM = arraySeed(0, PLAYBACK_WAVEFORM_SAMPLES);
|
||||||
|
|
||||||
export class Playback extends EventEmitter implements IDestroyable {
|
export class Playback extends EventEmitter implements IDestroyable {
|
||||||
|
|
|
@ -33,6 +33,8 @@ const BITRATE = 24000; // 24kbps is pretty high quality for our use case in opus
|
||||||
const TARGET_MAX_LENGTH = 120; // 2 minutes in seconds. Somewhat arbitrary, though longer == larger files.
|
const TARGET_MAX_LENGTH = 120; // 2 minutes in seconds. Somewhat arbitrary, though longer == larger files.
|
||||||
const TARGET_WARN_TIME_LEFT = 10; // 10 seconds, also somewhat arbitrary.
|
const TARGET_WARN_TIME_LEFT = 10; // 10 seconds, also somewhat arbitrary.
|
||||||
|
|
||||||
|
export const RECORDING_PLAYBACK_SAMPLES = 43;
|
||||||
|
|
||||||
export interface IRecordingUpdate {
|
export interface IRecordingUpdate {
|
||||||
waveform: number[]; // floating points between 0 (low) and 1 (high).
|
waveform: number[]; // floating points between 0 (low) and 1 (high).
|
||||||
timeSeconds: number; // float
|
timeSeconds: number; // float
|
||||||
|
|
Loading…
Reference in a new issue