diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md index 19b4d8545876..df1b48ce5cce 100644 --- a/ACKNOWLEDGMENTS.md +++ b/ACKNOWLEDGMENTS.md @@ -5,55 +5,6 @@ Signal Desktop makes use of the following open source projects. -## @evanhahn/lottie-web-light - - The MIT License (MIT) - - Copyright (c) 2022 Evan Hahn - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - ************ - - Original lottie-web license: - The MIT License (MIT) - - Copyright (c) 2015 Bodymovin - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - ## @popperjs/core License: MIT diff --git a/package.json b/package.json index a86db026612a..713317cbae7d 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,6 @@ "fs-xattr": "0.3.0" }, "dependencies": { - "@evanhahn/lottie-web-light": "5.8.1", "@popperjs/core": "2.9.2", "@react-spring/web": "9.4.1", "@signalapp/libsignal-client": "0.16.0", diff --git a/stylesheets/components/CallingAudioIndicator.scss b/stylesheets/components/CallingAudioIndicator.scss index ea6e54fcb2ed..650095499767 100644 --- a/stylesheets/components/CallingAudioIndicator.scss +++ b/stylesheets/components/CallingAudioIndicator.scss @@ -18,15 +18,15 @@ } &__content { - $size: 16px; + $size: 14px; width: $size; height: $size; + /* Center Lottie animation */ + display: flex; + align-items: center; + justify-content: center; &--muted { - $size: 14px; - width: $size; - height: $size; - @include color-svg( '../images/icons/v2/mic-off-solid-28.svg', $color-white diff --git a/ts/components/CallingAudioIndicator.stories.tsx b/ts/components/CallingAudioIndicator.stories.tsx index 08a0e0a20395..bacf97d764e9 100644 --- a/ts/components/CallingAudioIndicator.stories.tsx +++ b/ts/components/CallingAudioIndicator.stories.tsx @@ -1,17 +1,53 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { storiesOf } from '@storybook/react'; -import { boolean, select } from '@storybook/addon-knobs'; +import { boolean } from '@storybook/addon-knobs'; import { CallingAudioIndicator } from './CallingAudioIndicator'; +import { AUDIO_LEVEL_INTERVAL_MS } from '../calling/constants'; const story = storiesOf('Components/CallingAudioIndicator', module); -story.add('Default', () => ( - -)); +story.add('Extreme', () => { + const [audioLevel, setAudioLevel] = useState(1); + + useEffect(() => { + const timer = setTimeout(() => { + setAudioLevel(1 - audioLevel); + }, 2 * AUDIO_LEVEL_INTERVAL_MS); + + return () => { + clearTimeout(timer); + }; + }, [audioLevel, setAudioLevel]); + + return ( + + ); +}); + +story.add('Random', () => { + const [audioLevel, setAudioLevel] = useState(1); + + useEffect(() => { + const timer = setTimeout(() => { + setAudioLevel(Math.random()); + }, AUDIO_LEVEL_INTERVAL_MS); + + return () => { + clearTimeout(timer); + }; + }, [audioLevel, setAudioLevel]); + + return ( + + ); +}); diff --git a/ts/components/CallingAudioIndicator.tsx b/ts/components/CallingAudioIndicator.tsx index 179c0fe53938..cac86276956c 100644 --- a/ts/components/CallingAudioIndicator.tsx +++ b/ts/components/CallingAudioIndicator.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames'; import { noop } from 'lodash'; import type { ReactElement } from 'react'; -import React, { useEffect, useCallback, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useSpring, animated } from '@react-spring/web'; import { AUDIO_LEVEL_INTERVAL_MS } from '../calling/constants'; @@ -20,11 +20,11 @@ const SIDE_SCALE_FACTOR = 0.75; const MAX_CENTRAL_BAR_DELTA = 9; /* Should match css */ -const CONTENT_WIDTH = 16; -const CONTENT_HEIGHT = 16; +const CONTENT_WIDTH = 14; +const CONTENT_HEIGHT = 14; const BAR_WIDTH = 2; -const CONTENT_PADDING = 2; +const CONTENT_PADDING = 1; enum BarPosition { Left, @@ -37,13 +37,15 @@ function generateBarPath(position: BarPosition, audioLevel: number): string { if (position === BarPosition.Left) { x = CONTENT_PADDING; } else if (position === BarPosition.Center) { - x = CONTENT_WIDTH / 2 - CONTENT_PADDING + BAR_WIDTH / 2; + x = CONTENT_WIDTH / 2 - BAR_WIDTH / 2; } else if (position === BarPosition.Right) { x = CONTENT_WIDTH - CONTENT_PADDING - BAR_WIDTH; } else { throw missingCaseError(position); } + x = Math.round(x); + let height: number; if (position === BarPosition.Left || position === BarPosition.Right) { height = @@ -58,37 +60,34 @@ function generateBarPath(position: BarPosition, audioLevel: number): string { height -= 2; const y = (CONTENT_HEIGHT - height) / 2; - const top = y; - const bottom = top + height; + const left = x; + const right = x + BAR_WIDTH; + const top = y.toFixed(2); + const bottom = (y + height).toFixed(2); return ( - `M ${x} ${top} ` + - `L ${x} ${bottom} ` + - `A 0.5 0.5 0 0 0 ${x + BAR_WIDTH} ${bottom} ` + - `L ${x + BAR_WIDTH} ${top} ` + - `A 0.5 0.5 0 0 0 ${x} ${top}` + `M ${left} ${top} ` + + `L ${left} ${bottom} ` + + `A 0.5 0.5 0 0 0 ${right} ${bottom} ` + + `L ${right} ${top} ` + + `A 0.5 0.5 0 0 0 ${left} ${top}` ); } -function Bar({ - position, - audioLevel, -}: { - position: BarPosition; - audioLevel: number; -}): ReactElement { +function generateCombinedPath(audioLevel: number): string { + return ( + `${generateBarPath(BarPosition.Left, audioLevel)} ` + + `${generateBarPath(BarPosition.Center, audioLevel)} ` + + `${generateBarPath(BarPosition.Right, audioLevel)} ` + ); +} + +function Bars({ audioLevel }: { audioLevel: number }): ReactElement { const animatedProps = useSpring({ from: { audioLevel: 0 }, config: { duration: AUDIO_LEVEL_INTERVAL_MS }, }); - const levelToPath = useCallback( - (animatedLevel: number): string => { - return generateBarPath(position, animatedLevel); - }, - [position] - ); - useEffect(() => { animatedProps.audioLevel.stop(); animatedProps.audioLevel.start(audioLevel); @@ -96,7 +95,7 @@ function Bar({ return ( ); @@ -148,10 +147,15 @@ export function CallingAudioIndicator({ `${BASE_CLASS_NAME}--with-content` )} > - - - - + + ); diff --git a/ts/components/Lottie.stories.tsx b/ts/components/Lottie.stories.tsx deleted file mode 100644 index 1c64c35e63eb..000000000000 --- a/ts/components/Lottie.stories.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2022 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import React from 'react'; -import { storiesOf } from '@storybook/react'; - -import { Lottie } from './Lottie'; - -import testAnimationData from '../../fixtures/lottie-loader-by-lucas-bariani.json'; - -const STORYBOOK_CONTAINER_CLASS_NAME = 'lottie-test-storybook-container'; - -const story = storiesOf('Components/Lottie', module); - -story.add('Default', () => ( - -)); diff --git a/ts/components/Lottie.tsx b/ts/components/Lottie.tsx deleted file mode 100644 index 44e3a2f33227..000000000000 --- a/ts/components/Lottie.tsx +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2022 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import type { CSSProperties, ReactElement } from 'react'; -import React, { useEffect, useRef } from 'react'; -import lottie from '@evanhahn/lottie-web-light'; - -import { lottieNoopAudioFactory } from '../util/lottieNoopAudioFactory'; - -export function Lottie({ - animationData, - className, - style, -}: Readonly<{ - animationData: unknown; - className?: string; - style?: CSSProperties; -}>): ReactElement { - const containerRef = useRef(null); - - useEffect(() => { - const container = containerRef.current; - if (!container) { - return; - } - - const animationItem = lottie.loadAnimation({ - container, - renderer: 'svg', - loop: true, - autoplay: true, - animationData, - audioFactory: lottieNoopAudioFactory, - }); - - return () => { - animationItem.destroy(); - }; - }, [animationData]); - - return
; -} diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index 6d78be2b32f1..d6ce5aae2a50 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -132,41 +132,6 @@ "reasonCategory": "falseMatch", "updated": "2021-04-05T20:48:36.065Z" }, - { - "rule": "jQuery-append(", - "path": "node_modules/@evanhahn/lottie-web-light/index.js", - "line": " this._elementHelper.append(img);", - "reasonCategory": "falseMatch", - "updated": "2022-01-27T20:06:59.988Z" - }, - { - "rule": "jQuery-insertBefore(", - "path": "node_modules/@evanhahn/lottie-web-light/index.js", - "line": " this.layerElement.insertBefore(newElement, nextElement);", - "reasonCategory": "falseMatch", - "updated": "2022-01-27T20:06:59.988Z" - }, - { - "rule": "jQuery-insertBefore(", - "path": "node_modules/@evanhahn/lottie-web-light/index.js", - "line": " parentNode.insertBefore(useElem, nextChild);", - "reasonCategory": "falseMatch", - "updated": "2022-01-27T20:06:59.988Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/@evanhahn/lottie-web-light/index.js", - "line": " _workerSelf.assetLoader.load(", - "reasonCategory": "falseMatch", - "updated": "2022-01-27T20:06:59.988Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/@evanhahn/lottie-web-light/index.js", - "line": " _workerSelf.assetLoader.load(", - "reasonCategory": "falseMatch", - "updated": "2022-01-27T20:06:59.988Z" - }, { "rule": "jQuery-load(", "path": "node_modules/@malept/flatpak-bundler/node_modules/debug/src/browser.js", @@ -652,6 +617,30 @@ "reasonCategory": "falseMatch", "updated": "2022-02-11T21:58:24.827Z" }, + { + "rule": "jQuery-load(", + "path": "node_modules/agentkeepalive/node_modules/debug/src/browser.js", + "line": "function load() {", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, + { + "rule": "jQuery-load(", + "path": "node_modules/agentkeepalive/node_modules/debug/src/common.js", + "line": "\tcreateDebug.enable(createDebug.load());", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, + { + "rule": "jQuery-load(", + "path": "node_modules/agentkeepalive/node_modules/debug/src/node.js", + "line": "function load() {", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, { "rule": "jQuery-wrap(", "path": "node_modules/asar/node_modules/commander/index.js", @@ -4470,6 +4459,30 @@ "reasonCategory": "falseMatch", "updated": "2019-03-09T00:08:44.242Z" }, + { + "rule": "jQuery-load(", + "path": "node_modules/make-fetch-happen/node_modules/debug/src/browser.js", + "line": "function load() {", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, + { + "rule": "jQuery-load(", + "path": "node_modules/make-fetch-happen/node_modules/debug/src/common.js", + "line": "\tcreateDebug.enable(createDebug.load());", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, + { + "rule": "jQuery-load(", + "path": "node_modules/make-fetch-happen/node_modules/debug/src/node.js", + "line": "function load() {", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, { "rule": "eval", "path": "node_modules/micro/node_modules/depd/index.js", @@ -4501,6 +4514,46 @@ "updated": "2020-09-11T17:24:56.124Z", "reasonDetail": "Read, not write" }, + { + "rule": "jQuery-append(", + "path": "node_modules/minipass-fetch/lib/headers.js", + "line": " this.append(headerName, value)", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, + { + "rule": "jQuery-append(", + "path": "node_modules/minipass-fetch/lib/headers.js", + "line": " this.append(pair[0], pair[1])", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, + { + "rule": "jQuery-append(", + "path": "node_modules/minipass-fetch/lib/headers.js", + "line": " this.append(key, init[key])", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, + { + "rule": "jQuery-append(", + "path": "node_modules/minipass-fetch/lib/request.js", + "line": " headers.append('Content-Type', contentType)", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, + { + "rule": "jQuery-append(", + "path": "node_modules/minipass-fetch/lib/response.js", + "line": " headers.append('Content-Type', contentType)", + "reasonCategory": "falseMatch", + "updated": "2022-04-08T07:10:10.677Z", + "reasonDetail": "node-gyp dependency" + }, { "rule": "jQuery-$(", "path": "node_modules/moment/min/moment-with-locales.min.js", @@ -7564,14 +7617,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-10-11T21:21:08.188Z" }, - { - "rule": "React-useRef", - "path": "ts/components/Lottie.tsx", - "line": " const containerRef = useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2022-01-27T20:06:59.988Z", - "reasonDetail": "Doesn't manipulate the DOM." - }, { "rule": "React-useRef", "path": "ts/components/Modal.tsx", @@ -8096,93 +8141,5 @@ "line": " message.innerHTML = window.SignalContext.i18n('optimizingApplication');", "reasonCategory": "usageTrusted", "updated": "2021-09-17T21:02:59.414Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/agentkeepalive/node_modules/debug/src/browser.js", - "line": "function load() {", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/agentkeepalive/node_modules/debug/src/common.js", - "line": "\tcreateDebug.enable(createDebug.load());", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/agentkeepalive/node_modules/debug/src/node.js", - "line": "function load() {", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/make-fetch-happen/node_modules/debug/src/browser.js", - "line": "function load() {", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/make-fetch-happen/node_modules/debug/src/common.js", - "line": "\tcreateDebug.enable(createDebug.load());", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/make-fetch-happen/node_modules/debug/src/node.js", - "line": "function load() {", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/minipass-fetch/lib/headers.js", - "line": " this.append(headerName, value)", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/minipass-fetch/lib/headers.js", - "line": " this.append(pair[0], pair[1])", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/minipass-fetch/lib/headers.js", - "line": " this.append(key, init[key])", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/minipass-fetch/lib/request.js", - "line": " headers.append('Content-Type', contentType)", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/minipass-fetch/lib/response.js", - "line": " headers.append('Content-Type', contentType)", - "reasonCategory": "falseMatch", - "updated": "2022-04-08T07:10:10.677Z", - "reasonDetail": "node-gyp dependency" } ] diff --git a/ts/util/lottieNoopAudioFactory.ts b/ts/util/lottieNoopAudioFactory.ts deleted file mode 100644 index e84a55dd659b..000000000000 --- a/ts/util/lottieNoopAudioFactory.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2022 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import { noop } from 'lodash'; -import type { AnimationConfig } from '@evanhahn/lottie-web-light'; - -type LottieAudioFactory = NonNullable; -type LottieAudio = ReturnType; - -const lottieNoopAudio: LottieAudio = { - play: noop, - seek: noop, - playing: noop, - rate: noop, - setVolume: noop, -}; - -export const lottieNoopAudioFactory: LottieAudioFactory = () => lottieNoopAudio; diff --git a/yarn.lock b/yarn.lock index b22d8cbfb629..4ac6378d0890 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1185,11 +1185,6 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.3.tgz#dfa0c92efe44a1d1a7974fb49ffeb40ef2da5a27" integrity sha512-zVgvPwGK7c1aVdUVc9Qv7SqepOGRDrqCw7KZPSZziWGxSlbII3gmvGLPzLX4d0n0BMbamBacUrN22zOMyFFEkQ== -"@evanhahn/lottie-web-light@5.8.1": - version "5.8.1" - resolved "https://registry.yarnpkg.com/@evanhahn/lottie-web-light/-/lottie-web-light-5.8.1.tgz#9154f9301479ec16745da925d44bd721efa04cbb" - integrity sha512-U0G1tt3/UEYnyCNNslWPi1dB7X1xQ9aoSip+B3GTKO/Bns8yz/p39vBkRSN9d25nkbHuCsbjky2coQftj5YVKw== - "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"