From 670da5722abca36653eb5fe2e781f568d984eea5 Mon Sep 17 00:00:00 2001 From: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com> Date: Wed, 17 Jan 2024 12:29:44 -0800 Subject: [PATCH] Top level Reaction/Raise Hand buttons and remove More Options --- _locales/en/messages.json | 4 + stylesheets/_modules.scss | 1 + stylesheets/_variables.scss | 4 +- stylesheets/components/CallControls.scss | 47 +----- stylesheets/components/CallingButton.scss | 24 ++- ts/components/CallScreen.tsx | 187 ++++++++++------------ ts/components/CallingButton.tsx | 15 ++ ts/util/lint/exceptions.json | 10 +- 8 files changed, 141 insertions(+), 151 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 09527b5c4146..0e5e2d92961d 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1748,6 +1748,10 @@ "messageformat": "Stop presenting", "description": "Button tooltip label for stopping screen sharing" }, + "icu:calling__button--react": { + "messageformat": "React", + "description": "Button tooltip label to send a reaction during a call" + }, "icu:calling__button--ring__disabled-because-group-is-too-large": { "messageformat": "Group is too large to ring the participants.", "description": "Button tooltip label when you can't ring because the group is too large" diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index b5660a83f9bb..22acd780c502 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -4114,6 +4114,7 @@ button.module-image__border-overlay:focus { &__footer { bottom: 0; display: flex; + flex-direction: row-reverse; justify-content: space-between; width: 100%; z-index: $z-index-above-base; diff --git a/stylesheets/_variables.scss b/stylesheets/_variables.scss index 3423900524ca..310ca22931c2 100644 --- a/stylesheets/_variables.scss +++ b/stylesheets/_variables.scss @@ -293,5 +293,5 @@ $NavTabs__Item__blockPadding: 2px; $NavTabs__Toggle__blockPadding: 8px; $NavTabs__ItemButton__blockPadding: 10px; $CallControls__height: 80px; -$CallControls__max-width: 600px; -$CallControls__initial-width: 440px; +$CallControls__max-width: 640px; +$CallControls__initial-width: 480px; diff --git a/stylesheets/components/CallControls.scss b/stylesheets/components/CallControls.scss index 2312e9daefa6..da328f396ba2 100644 --- a/stylesheets/components/CallControls.scss +++ b/stylesheets/components/CallControls.scss @@ -110,7 +110,7 @@ margin-block: -5px; } -.CallControls__MoreOptionsButtonContainer--menu-shown .module-tooltip { +.CallControls__ReactButtonContainer--menu-shown .module-tooltip { opacity: 0; } @@ -120,14 +120,12 @@ flex-basis: calc($local-preview-width + 16px); } -.CallControls__MoreOptionsContainer { +.CallControls__ReactionPickerContainer { position: absolute; - inset-inline-start: min(48%, 40vw); + inset-inline-start: min(44%, 32vw); inset-block-end: 70px; z-index: $z-index-toast; -} -.CallControls__MoreOptionsMenu { display: flex; flex-direction: column; max-height: calc(100vh - 155px); @@ -136,48 +134,13 @@ pointer-events: auto; } -.CallControls__MoreOptionsMenu .module-emoji-picker { +.CallControls__ReactionPickerContainer .module-emoji-picker { margin-bottom: auto; max-width: calc(100vw / 2 + 20px); } -.CallControls__MoreOptionsMenu - .module-emoji-picker - + .CallControls__MenuItemRaiseHand { - display: none; -} - -.CallControls__MoreOptionsMenu .module-ReactionPickerPicker { +.CallControls__ReactionPickerContainer .module-ReactionPickerPicker { @media (prefers-reduced-motion: no-preference) { animation-duration: 200ms; } } - -.CallControls__MenuItemRaiseHand { - @include button-reset; - display: flex; - min-width: 290px; - padding-block: 12px; - padding-inline: 12px; - margin-block-start: 8px; - border-radius: 10px; - align-items: center; - text-align: start; - background-color: $color-gray-75; - color: $color-white; - filter: drop-shadow(0px 4px 3px $color-black-alpha-20); -} - -.CallControls__MenuItemRaiseHand:hover { - background-color: $color-gray-65; -} - -.CallControls__MenuItemRaiseHandIcon { - @include color-svg( - '../images/icons/v3/raise_hand/raise_hand-light.svg', - $color-gray-15 - ); - height: 16px; - width: 16px; - margin-inline: 2px 12px; -} diff --git a/stylesheets/components/CallingButton.scss b/stylesheets/components/CallingButton.scss index fdfc7710129d..8c3b5d19bbf2 100644 --- a/stylesheets/components/CallingButton.scss +++ b/stylesheets/components/CallingButton.scss @@ -31,8 +31,8 @@ div { @include color-svg($icon, $icon-color); - height: 22px; - width: 22px; + height: 20px; + width: 20px; } } @@ -88,6 +88,26 @@ ); } + &--raise-hand { + $icon: '../images/icons/v3/raise_hand/raise_hand-light.svg'; + &--on { + @include calling-button-icon-highlighted($icon); + } + &--off { + @include calling-button-icon-regular($icon); + } + } + + &--react { + $icon: '../images/icons/v3/heart/heart-plus.svg'; + &--on { + @include calling-button-icon-highlighted($icon); + } + &--off { + @include calling-button-icon-regular($icon); + } + } + &--ring { $icon: '../images/icons/v3/bell/bell-slash-fill.svg'; &--on { diff --git a/ts/components/CallScreen.tsx b/ts/components/CallScreen.tsx index 0eff5fe59593..9e8998139162 100644 --- a/ts/components/CallScreen.tsx +++ b/ts/components/CallScreen.tsx @@ -72,7 +72,6 @@ import { useCallingToasts, } from './CallingToast'; import { Spinner } from './Spinner'; -import { handleOutsideClick } from '../util/handleOutsideClick'; import type { Props as ReactionPickerProps } from './conversation/ReactionPicker'; import type { SmartReactionPicker } from '../state/smart/ReactionPicker'; import { Emoji } from './emoji/Emoji'; @@ -250,12 +249,12 @@ export function CallScreen({ hangUpActiveCall('button click'); }, [hangUpActiveCall]); - const moreOptionsMenuRef = React.useRef(null); - const moreOptionsButtonRef = React.useRef(null); + const reactButtonRef = React.useRef(null); const reactionPickerRef = React.useRef(null); - const [showMoreOptions, setShowMoreOptions] = useState(false); - const toggleMoreOptions = useCallback(() => { - setShowMoreOptions(prevValue => !prevValue); + const reactionPickerContainerRef = React.useRef(null); + const [showReactionPicker, setShowReactionPicker] = useState(false); + const toggleReactionPicker = useCallback(() => { + setShowReactionPicker(prevValue => !prevValue); }, []); const [showRaisedHandsList, setShowRaisedHandsList] = useState(false); @@ -285,14 +284,19 @@ export function CallScreen({ }, [setLocalPreview, setRendererCanvas]); useEffect(() => { - if (!showControls || showMoreOptions || stickyControls || controlsHover) { + if ( + !showControls || + showReactionPicker || + stickyControls || + controlsHover + ) { return noop; } const timer = setTimeout(() => { setShowControls(false); }, 5000); return clearTimeout.bind(null, timer); - }, [showControls, showMoreOptions, stickyControls, controlsHover]); + }, [showControls, showReactionPicker, stickyControls, controlsHover]); useEffect(() => { const handleKeyDown = (event: KeyboardEvent): void => { @@ -321,22 +325,6 @@ export function CallScreen({ }; }, [toggleAudio, toggleVideo]); - useEffect(() => { - if (!showMoreOptions) { - return noop; - } - return handleOutsideClick( - () => { - setShowMoreOptions(false); - return true; - }, - { - containerElements: [moreOptionsButtonRef, moreOptionsMenuRef], - name: 'CallScreen.moreOptions', - } - ); - }, [showMoreOptions]); - useScreenSharingStoppedToast({ activeCall, i18n }); useViewModeChangedToast({ activeCall, i18n }); @@ -468,8 +456,6 @@ export function CallScreen({ }); const isGroupCall = activeCall.callMode === CallMode.Group; - const isMoreOptionsButtonEnabled = - isGroupCall && (isGroupCallRaiseHandEnabled || isGroupCallReactionsEnabled); let presentingButtonType: CallingButtonType; if (presentingSource) { @@ -518,6 +504,17 @@ export function CallScreen({ ] ); + let raiseHandButtonType: CallingButtonType | undefined; + let reactButtonType: CallingButtonType | undefined; + if (isGroupCall) { + raiseHandButtonType = localHandRaised + ? CallingButtonType.RAISE_HAND_ON + : CallingButtonType.RAISE_HAND_OFF; + reactButtonType = showReactionPicker + ? CallingButtonType.REACT_ON + : CallingButtonType.REACT_OFF; + } + const renderRaisedHandsToast = React.useCallback( (hands: Array) => { // Sort "You" to the front. @@ -793,8 +790,27 @@ export function CallScreen({ renderRaisedHandsToast={renderRaisedHandsToast} i18n={i18n} /> + {/* We render the local preview first and set the footer flex direction to row-reverse + to ensure the preview is visible at low viewport widths. */}
-
+ {localPreviewNode ? ( +
+ {localPreviewNode} + {!isSendingVideo && ( +
+ )} + + {syncedLocalHandRaised && ( +
+ )} +
+ ) : ( +
+ )}
{callStatus}
- {showMoreOptions && ( -
-
- {isGroupCallReactionsEnabled && - renderReactionPicker({ - ref: reactionPickerRef, - onClose: () => setShowMoreOptions(false), - onPick: emoji => { - setShowMoreOptions(false); - sendGroupCallReaction({ - conversationId: conversation.id, - value: emoji, - }); - }, - renderEmojiPicker, - })} - {isGroupCallRaiseHandEnabled && ( - - )} -
+ {showReactionPicker && ( +
+ {isGroupCallReactionsEnabled && + renderReactionPicker({ + ref: reactionPickerRef, + onClose: () => setShowReactionPicker(false), + onPick: emoji => { + setShowReactionPicker(false); + sendGroupCallReaction({ + conversationId: conversation.id, + value: emoji, + }); + }, + renderEmojiPicker, + })}
)}
- - {isMoreOptionsButtonEnabled && ( + + {isGroupCallRaiseHandEnabled && raiseHandButtonType && ( + toggleRaiseHand()} + tooltipDirection={TooltipPlacement.Top} + /> + )} + {isGroupCallReactionsEnabled && reactButtonType && (
@@ -908,24 +914,7 @@ export function CallScreen({
- {localPreviewNode ? ( -
- {localPreviewNode} - {!isSendingVideo && ( -
- )} - - {syncedLocalHandRaised && ( -
- )} -
- ) : ( -
- )} +
); diff --git a/ts/components/CallingButton.tsx b/ts/components/CallingButton.tsx index 3ea68d4354c6..f448e7c95f30 100644 --- a/ts/components/CallingButton.tsx +++ b/ts/components/CallingButton.tsx @@ -16,6 +16,10 @@ export enum CallingButtonType { PRESENTING_DISABLED = 'PRESENTING_DISABLED', PRESENTING_OFF = 'PRESENTING_OFF', PRESENTING_ON = 'PRESENTING_ON', + RAISE_HAND_OFF = 'RAISE_HAND_OFF', + RAISE_HAND_ON = 'RAISE_HAND_ON', + REACT_OFF = 'REACT_OFF', + REACT_ON = 'REACT_ON', RING_DISABLED = 'RING_DISABLED', RING_OFF = 'RING_OFF', RING_ON = 'RING_ON', @@ -75,6 +79,17 @@ export function CallingButton({ tooltipContent = i18n( 'icu:calling__button--ring__disabled-because-group-is-too-large' ); + } else if (buttonType === CallingButtonType.REACT_OFF) { + classNameSuffix = 'react--off'; + tooltipContent = i18n('icu:calling__button--react'); + } else if (buttonType === CallingButtonType.REACT_ON) { + classNameSuffix = 'react--on'; + } else if (buttonType === CallingButtonType.RAISE_HAND_OFF) { + classNameSuffix = 'raise-hand--off'; + tooltipContent = i18n('icu:CallControls__MenuItemRaiseHand'); + } else if (buttonType === CallingButtonType.RAISE_HAND_ON) { + classNameSuffix = 'raise-hand--on'; + tooltipContent = i18n('icu:CallControls__MenuItemRaiseHand--lower'); } else if (buttonType === CallingButtonType.RING_OFF) { classNameSuffix = 'ring--off'; tooltipContent = i18n('icu:CallingButton--ring-on'); diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index ba1229639607..524ec2f4238a 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -2827,18 +2827,16 @@ { "rule": "React-useRef", "path": "ts/components/CallScreen.tsx", - "line": " const moreOptionsMenuRef = React.useRef(null);", + "line": " const reactButtonRef = React.useRef(null);", "reasonCategory": "usageTrusted", - "updated": "2023-11-14T23:29:51.425Z", - "reasonDetail": "Used to detect clicks outside of the Calling More Options button menu" + "updated": "2024-01-16T22:59:06.336Z" }, { "rule": "React-useRef", "path": "ts/components/CallScreen.tsx", - "line": " const moreOptionsButtonRef = React.useRef(null);", + "line": " const reactionPickerContainerRef = React.useRef(null);", "reasonCategory": "usageTrusted", - "updated": "2023-11-14T23:29:51.425Z", - "reasonDetail": "Used to detect clicks outside of the Calling More Options button menu and ensures clicking the button does not re-open the menu." + "updated": "2024-01-16T22:59:06.336Z" }, { "rule": "React-useRef",