diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 897367e7a2e..8e039c46bc9 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1613,6 +1613,10 @@ "messageformat": "Anyone who joins this call via the link will see your name, photo, and phone number.", "description": "Toast shown in call lobby before joining a call link call to inform user that profile info will be shared, when the phone number sharing account setting is enabled." }, + "icu:CallingLobby__CallLinkNotice--join-request-pending": { + "messageformat": "Waiting to be let in…", + "description": "Notice shown in call lobby after you requested to join a call link to indicate your request is pending approval." + }, "icu:CallingLobbyJoinButton--join": { "messageformat": "Join", "description": "Button label in the call lobby for joining a call" diff --git a/stylesheets/components/CallingLobby.scss b/stylesheets/components/CallingLobby.scss index 24c8ece364c..55adbdd580c 100644 --- a/stylesheets/components/CallingLobby.scss +++ b/stylesheets/components/CallingLobby.scss @@ -46,9 +46,19 @@ background: $color-black-alpha-60; color: $color-white; border-radius: 10px; + align-items: center; text-align: center; } +.CallingLobby__CallLinkNotice--join-request-pending { + @include font-body-1; + width: auto; +} + +.CallingLobby__CallLinkJoinRequestPendingSpinner { + margin-inline-end: 8px; +} + .CallingLobby__Footer { display: flex; width: 100%; diff --git a/stylesheets/components/SpinnerV2.scss b/stylesheets/components/SpinnerV2.scss new file mode 100644 index 00000000000..9b5e3bfe63a --- /dev/null +++ b/stylesheets/components/SpinnerV2.scss @@ -0,0 +1,33 @@ +// Copyright 2024 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +.SpinnerV2 { + animation: SpinnerV2-rotate 2s linear infinite; +} + +.SpinnerV2__Path { + stroke: $color-gray-15; + stroke-linecap: round; + animation: SpinnerV2-dash 1.5s ease-in-out infinite; +} + +@keyframes SpinnerV2-rotate { + 100% { + transform: rotate(360deg); + } +} + +@keyframes SpinnerV2-dash { + 0% { + stroke-dasharray: 2%, 300%; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 180%, 300%; + stroke-dashoffset: -70%; + } + 100% { + stroke-dasharray: 180%, 300%; + stroke-dashoffset: -248%; + } +} diff --git a/stylesheets/manifest.scss b/stylesheets/manifest.scss index 68c3e5ab0b8..f92aab6697f 100644 --- a/stylesheets/manifest.scss +++ b/stylesheets/manifest.scss @@ -147,6 +147,7 @@ @import './components/ShortcutGuide.scss'; @import './components/SignalConnectionsModal.scss'; @import './components/Slider.scss'; +@import './components/SpinnerV2.scss'; @import './components/StagedLinkPreview.scss'; @import './components/StickerManager.scss'; @import './components/Stories.scss'; diff --git a/ts/components/CallingLobby.stories.tsx b/ts/components/CallingLobby.stories.tsx index 1540ff468dc..983ee1c8355 100644 --- a/ts/components/CallingLobby.stories.tsx +++ b/ts/components/CallingLobby.stories.tsx @@ -67,7 +67,7 @@ const createProps = (overrideProps: Partial = {}): PropsType => { i18n, isAdhocAdminApprovalRequired: overrideProps.isAdhocAdminApprovalRequired ?? false, - isAdhocJoinRequestPending: false, + isAdhocJoinRequestPending: overrideProps.isAdhocJoinRequestPending ?? false, isConversationTooBigToRing: false, isCallFull: overrideProps.isCallFull ?? false, isSharingPhoneNumberWithEverybody: @@ -237,3 +237,12 @@ export function CallLinkAdminApproval(): JSX.Element { }); return ; } + +export function CallLinkJoinRequestPending(): JSX.Element { + const props = createProps({ + callMode: CallMode.Adhoc, + isAdhocAdminApprovalRequired: true, + isAdhocJoinRequestPending: true, + }); + return ; +} diff --git a/ts/components/CallingLobby.tsx b/ts/components/CallingLobby.tsx index c2838a62dda..da0abc4e6bf 100644 --- a/ts/components/CallingLobby.tsx +++ b/ts/components/CallingLobby.tsx @@ -28,6 +28,8 @@ import type { ConversationType } from '../state/ducks/conversations'; import { useCallingToasts } from './CallingToast'; import { CallingButtonToastsContainer } from './CallingToastManager'; import { isGroupOrAdhocCallMode } from '../util/isGroupOrAdhocCall'; +import { Button, ButtonVariant } from './Button'; +import { SpinnerV2 } from './SpinnerV2'; export type PropsType = { availableCameras: Array; @@ -211,6 +213,9 @@ export function CallingLobby({ } const canJoin = !isCallFull && !isCallConnecting && isOnline; + const canLeave = + (isAdhocAdminApprovalRequired && isCallConnecting) || + isAdhocJoinRequestPending; let callingLobbyJoinButtonVariant: CallingLobbyJoinButtonVariant; if (isCallFull) { @@ -306,7 +311,16 @@ export function CallingLobby({ {i18n('icu:calling__your-video-is-off')} - {callMode === CallMode.Adhoc && ( + {callMode === CallMode.Adhoc && isAdhocJoinRequestPending ? ( +
+ + {i18n('icu:CallingLobby__CallLinkNotice--join-request-pending')} +
+ ) : (
{isSharingPhoneNumberWithEverybody ? i18n('icu:CallingLobby__CallLinkNotice--phone-sharing') @@ -350,15 +364,25 @@ export function CallingLobby({ />
- { - setIsCallConnecting(true); - onJoinCall(); - }} - variant={callingLobbyJoinButtonVariant} - /> + {canLeave ? ( + + ) : ( + { + setIsCallConnecting(true); + onJoinCall(); + }} + variant={callingLobbyJoinButtonVariant} + /> + )}
diff --git a/ts/components/SpinnerV2.tsx b/ts/components/SpinnerV2.tsx new file mode 100644 index 00000000000..4cf51c952d4 --- /dev/null +++ b/ts/components/SpinnerV2.tsx @@ -0,0 +1,40 @@ +// Copyright 2024 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import React from 'react'; +import classNames from 'classnames'; + +export const SpinnerSvgSizes = ['small', 'normal'] as const; +export type SpinnerSvgSize = typeof SpinnerSvgSizes[number]; + +export type Props = { + className?: string; + size: number; + strokeWidth: number; +}; + +export function SpinnerV2({ + className, + size, + strokeWidth, +}: Props): JSX.Element { + return ( + + + + ); +}