Release Note Channel: Mute/Unmute UI, hide UI elements
Co-authored-by: yash-signal <yash@signal.org>
This commit is contained in:
parent
141cf2d482
commit
d93f488cbb
17 changed files with 305 additions and 150 deletions
|
@ -29,6 +29,8 @@
|
|||
padding-bottom: 8px;
|
||||
padding-top: 12px;
|
||||
user-select: text;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__title-contact-icon {
|
||||
|
|
30
stylesheets/components/SignalConversationMuteToggle.scss
Normal file
30
stylesheets/components/SignalConversationMuteToggle.scss
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
@use '../mixins';
|
||||
@use '../variables';
|
||||
|
||||
.SignalConversationMuteToggle {
|
||||
@include mixins.light-theme() {
|
||||
background-color: variables.$color-white;
|
||||
border-top: 0.5px solid variables.$color-black-alpha-16;
|
||||
}
|
||||
|
||||
@include mixins.dark-theme() {
|
||||
background-color: variables.$color-gray-95;
|
||||
border-top: 0.5px solid variables.$color-gray-65;
|
||||
}
|
||||
|
||||
height: variables.$header-height;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 14px;
|
||||
color: variables.$color-ultramarine-light;
|
||||
|
||||
&__text {
|
||||
@include mixins.button-reset;
|
||||
}
|
||||
}
|
|
@ -159,6 +159,7 @@
|
|||
@use 'components/SendStoryModal.scss';
|
||||
@use 'components/ShortcutGuide.scss';
|
||||
@use 'components/SignalConnectionsModal.scss';
|
||||
@use 'components/SignalConversationMuteToggle.scss';
|
||||
@use 'components/Slider.scss';
|
||||
@use 'components/SpinnerV2.scss';
|
||||
@use 'components/StagedLinkPreview.scss';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import { IMAGE_JPEG } from '../types/MIME';
|
||||
|
@ -125,6 +125,10 @@ export default {
|
|||
selectedMessageIds: undefined,
|
||||
toggleSelectMode: action('toggleSelectMode'),
|
||||
toggleForwardMessagesModal: action('toggleForwardMessagesModal'),
|
||||
// Signal Conversation
|
||||
isSignalConversation: false,
|
||||
isMuted: false,
|
||||
setMuteExpiration: action('setMuteExpiration'),
|
||||
},
|
||||
} satisfies Meta<Props>;
|
||||
|
||||
|
@ -263,3 +267,21 @@ export function NoFormattingMenu(args: Props): JSX.Element {
|
|||
<CompositionArea {...args} theme={theme} isFormattingEnabled={false} />
|
||||
);
|
||||
}
|
||||
|
||||
export function SignalConversationMuteToggle(args: Props): JSX.Element {
|
||||
const theme = useContext(StorybookThemeContext);
|
||||
const [isMuted, setIsMuted] = useState(true);
|
||||
|
||||
function setIsMutedByTime(_: string, muteExpiresAt: number) {
|
||||
setIsMuted(muteExpiresAt > Date.now());
|
||||
}
|
||||
return (
|
||||
<CompositionArea
|
||||
{...args}
|
||||
theme={theme}
|
||||
isSignalConversation
|
||||
isMuted={isMuted}
|
||||
setMuteExpiration={setIsMutedByTime}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ import type { ShowToastAction } from '../state/ducks/toast';
|
|||
import type { DraftEditMessageType } from '../model-types.d';
|
||||
import type { ForwardMessagesPayload } from '../state/ducks/globalModals';
|
||||
import { ForwardMessagesModalType } from './ForwardMessagesModal';
|
||||
import { SignalConversationMuteToggle } from './conversation/SignalConversationMuteToggle';
|
||||
|
||||
export type OwnProps = Readonly<{
|
||||
acceptedMessageRequest: boolean | null;
|
||||
|
@ -118,6 +119,7 @@ export type OwnProps = Readonly<{
|
|||
recordingState: RecordingState;
|
||||
messageCompositionId: string;
|
||||
shouldHidePopovers: boolean | null;
|
||||
isMuted: boolean;
|
||||
isSmsOnlyOrUnregistered: boolean | null;
|
||||
left: boolean | null;
|
||||
linkPreviewLoading: boolean;
|
||||
|
@ -130,6 +132,7 @@ export type OwnProps = Readonly<{
|
|||
conversationId: string;
|
||||
files: ReadonlyArray<File>;
|
||||
}) => unknown;
|
||||
setMuteExpiration(conversationId: string, muteExpiresAt: number): unknown;
|
||||
setMediaQualitySetting(conversationId: string, isHQ: boolean): unknown;
|
||||
sendStickerMessage(
|
||||
id: string,
|
||||
|
@ -239,6 +242,7 @@ export const CompositionArea = memo(function CompositionArea({
|
|||
imageToBlurHash,
|
||||
isDisabled,
|
||||
isSignalConversation,
|
||||
isMuted,
|
||||
isActive,
|
||||
lastEditableMessageId,
|
||||
messageCompositionId,
|
||||
|
@ -254,6 +258,7 @@ export const CompositionArea = memo(function CompositionArea({
|
|||
shouldHidePopovers,
|
||||
showToast,
|
||||
theme,
|
||||
setMuteExpiration,
|
||||
|
||||
// AttachmentList
|
||||
draftAttachments,
|
||||
|
@ -737,8 +742,14 @@ export const CompositionArea = memo(function CompositionArea({
|
|||
useEscapeHandling(handleEscape);
|
||||
|
||||
if (isSignalConversation) {
|
||||
// TODO DESKTOP-4547
|
||||
return <div />;
|
||||
return (
|
||||
<SignalConversationMuteToggle
|
||||
conversationId={conversationId}
|
||||
isMuted={isMuted}
|
||||
i18n={i18n}
|
||||
setMuteExpiration={setMuteExpiration}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (selectedMessageIds != null) {
|
||||
|
|
|
@ -47,6 +47,7 @@ function HeaderInfoTitle({
|
|||
type,
|
||||
i18n,
|
||||
isMe,
|
||||
isSignalConversation,
|
||||
headerRef,
|
||||
}: {
|
||||
name: string | null;
|
||||
|
@ -54,8 +55,18 @@ function HeaderInfoTitle({
|
|||
type: ConversationTypeType;
|
||||
i18n: LocalizerType;
|
||||
isMe: boolean;
|
||||
isSignalConversation: boolean;
|
||||
headerRef: React.RefObject<HTMLDivElement>;
|
||||
}) {
|
||||
if (isSignalConversation) {
|
||||
return (
|
||||
<div className="module-ConversationHeader__header__info__title">
|
||||
<UserText text={title} />
|
||||
<span className="ContactModal__official-badge" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isMe) {
|
||||
return (
|
||||
<div className="module-ConversationHeader__header__info__title">
|
||||
|
@ -294,6 +305,7 @@ export const ConversationHeader = memo(function ConversationHeader({
|
|||
theme={theme}
|
||||
onViewUserStories={onViewUserStories}
|
||||
onViewConversationDetails={onViewConversationDetails}
|
||||
isSignalConversation={isSignalConversation ?? false}
|
||||
/>
|
||||
{!isSmsOnlyOrUnregistered && !isSignalConversation && (
|
||||
<OutgoingCallButtons
|
||||
|
@ -415,6 +427,7 @@ function HeaderContent({
|
|||
i18n,
|
||||
sharedGroupNames,
|
||||
theme,
|
||||
isSignalConversation,
|
||||
onViewUserStories,
|
||||
onViewConversationDetails,
|
||||
}: {
|
||||
|
@ -425,6 +438,7 @@ function HeaderContent({
|
|||
i18n: LocalizerType;
|
||||
sharedGroupNames: ReadonlyArray<string>;
|
||||
theme: ThemeType;
|
||||
isSignalConversation: boolean;
|
||||
onViewUserStories: () => void;
|
||||
onViewConversationDetails: () => void;
|
||||
}) {
|
||||
|
@ -476,6 +490,7 @@ function HeaderContent({
|
|||
type={conversation.type}
|
||||
i18n={i18n}
|
||||
isMe={conversation.isMe}
|
||||
isSignalConversation={isSignalConversation}
|
||||
headerRef={headerRef}
|
||||
/>
|
||||
{(conversation.expireTimer != null || conversation.isVerified) && (
|
||||
|
|
34
ts/components/conversation/SignalConversationMuteToggle.tsx
Normal file
34
ts/components/conversation/SignalConversationMuteToggle.tsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import type { LocalizerType } from '../../types/I18N';
|
||||
|
||||
type Props = {
|
||||
isMuted: boolean;
|
||||
i18n: LocalizerType;
|
||||
setMuteExpiration: (conversationId: string, muteExpiresAt: number) => unknown;
|
||||
conversationId: string;
|
||||
};
|
||||
export function SignalConversationMuteToggle({
|
||||
isMuted,
|
||||
i18n,
|
||||
setMuteExpiration,
|
||||
conversationId,
|
||||
}: Props): JSX.Element {
|
||||
const onMuteToggleClicked = () => {
|
||||
setMuteExpiration(conversationId, isMuted ? 0 : Number.MAX_SAFE_INTEGER);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="SignalConversationMuteToggle">
|
||||
<button
|
||||
onClick={onMuteToggleClicked}
|
||||
type="button"
|
||||
className="SignalConversationMuteToggle__text"
|
||||
>
|
||||
{isMuted ? i18n('icu:unmute') : i18n('icu:mute')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -65,6 +65,7 @@ const createProps = (
|
|||
i18n,
|
||||
isAdmin: false,
|
||||
isGroup: true,
|
||||
isSignalConversation: false,
|
||||
leaveGroup: action('leaveGroup'),
|
||||
loadRecentMediaItems: action('loadRecentMediaItems'),
|
||||
memberships: times(32, i => ({
|
||||
|
@ -244,3 +245,11 @@ export function InAnotherCallIndividual(): JSX.Element {
|
|||
|
||||
return <ConversationDetails {...props} hasActiveCall isGroup={false} />;
|
||||
}
|
||||
|
||||
export function SignalConversation(): JSX.Element {
|
||||
const props = createProps();
|
||||
|
||||
return (
|
||||
<ConversationDetails {...props} isSignalConversation isGroup={false} />
|
||||
);
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ export type StateProps = {
|
|||
i18n: LocalizerType;
|
||||
isAdmin: boolean;
|
||||
isGroup: boolean;
|
||||
isSignalConversation: boolean;
|
||||
groupsInCommon: ReadonlyArray<ConversationType>;
|
||||
maxGroupSize: number;
|
||||
maxRecommendedGroupSize: number;
|
||||
|
@ -181,6 +182,7 @@ export function ConversationDetails({
|
|||
i18n,
|
||||
isAdmin,
|
||||
isGroup,
|
||||
isSignalConversation,
|
||||
leaveGroup,
|
||||
loadRecentMediaItems,
|
||||
memberships,
|
||||
|
@ -397,6 +399,7 @@ export function ConversationDetails({
|
|||
i18n={i18n}
|
||||
isMe={conversation.isMe}
|
||||
isGroup={isGroup}
|
||||
isSignalConversation={isSignalConversation}
|
||||
membersCount={conversation.membersCount ?? null}
|
||||
startEditing={(isGroupTitle: boolean) => {
|
||||
setModalState(
|
||||
|
@ -424,7 +427,7 @@ export function ConversationDetails({
|
|||
{i18n('icu:ConversationDetails__HeaderButton--Message')}
|
||||
</Button>
|
||||
)}
|
||||
{!conversation.isMe && (
|
||||
{!conversation.isMe && !isSignalConversation && (
|
||||
<>
|
||||
<ConversationDetailsCallButton
|
||||
hasActiveCall={hasActiveCall}
|
||||
|
@ -477,152 +480,157 @@ export function ConversationDetails({
|
|||
/>
|
||||
)}
|
||||
|
||||
<PanelSection>
|
||||
{!isGroup || canEditGroupInfo ? (
|
||||
<PanelRow
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n(
|
||||
'icu:ConversationDetails--disappearing-messages-label'
|
||||
)}
|
||||
icon={IconType.timer}
|
||||
/>
|
||||
}
|
||||
info={
|
||||
isGroup
|
||||
? i18n(
|
||||
'icu:ConversationDetails--disappearing-messages-info--group'
|
||||
)
|
||||
: i18n(
|
||||
'icu:ConversationDetails--disappearing-messages-info--direct'
|
||||
)
|
||||
}
|
||||
label={i18n('icu:ConversationDetails--disappearing-messages-label')}
|
||||
right={
|
||||
<DisappearingTimerSelect
|
||||
i18n={i18n}
|
||||
value={conversation.expireTimer || DurationInSeconds.ZERO}
|
||||
onChange={value =>
|
||||
setDisappearingMessages(conversation.id, value)
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{canHaveNicknameAndNote(conversation) && (
|
||||
<PanelRow
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:ConversationDetails--nickname-label')}
|
||||
icon={IconType.edit}
|
||||
/>
|
||||
}
|
||||
label={i18n('icu:ConversationDetails--nickname-label')}
|
||||
onClick={onOpenEditNicknameAndNoteModal}
|
||||
actions={
|
||||
(conversation.nicknameGivenName ||
|
||||
conversation.nicknameFamilyName ||
|
||||
conversation.note) && (
|
||||
<ContextMenu
|
||||
{!isSignalConversation && (
|
||||
<PanelSection>
|
||||
{!isGroup || canEditGroupInfo ? (
|
||||
<PanelRow
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n(
|
||||
'icu:ConversationDetails--disappearing-messages-label'
|
||||
)}
|
||||
icon={IconType.timer}
|
||||
/>
|
||||
}
|
||||
info={
|
||||
isGroup
|
||||
? i18n(
|
||||
'icu:ConversationDetails--disappearing-messages-info--group'
|
||||
)
|
||||
: i18n(
|
||||
'icu:ConversationDetails--disappearing-messages-info--direct'
|
||||
)
|
||||
}
|
||||
label={i18n(
|
||||
'icu:ConversationDetails--disappearing-messages-label'
|
||||
)}
|
||||
right={
|
||||
<DisappearingTimerSelect
|
||||
i18n={i18n}
|
||||
portalToRoot
|
||||
popperOptions={{
|
||||
placement: 'bottom',
|
||||
strategy: 'absolute',
|
||||
}}
|
||||
menuOptions={[
|
||||
{
|
||||
icon: 'ConversationDetails--nickname-actions--delete',
|
||||
label: i18n(
|
||||
'icu:ConversationDetails--nickname-actions--delete'
|
||||
),
|
||||
onClick: () => {
|
||||
setModalState(ModalState.ConfirmDeleteNicknameAndNote);
|
||||
value={conversation.expireTimer || DurationInSeconds.ZERO}
|
||||
onChange={value =>
|
||||
setDisappearingMessages(conversation.id, value)
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{canHaveNicknameAndNote(conversation) && (
|
||||
<PanelRow
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:ConversationDetails--nickname-label')}
|
||||
icon={IconType.edit}
|
||||
/>
|
||||
}
|
||||
label={i18n('icu:ConversationDetails--nickname-label')}
|
||||
onClick={onOpenEditNicknameAndNoteModal}
|
||||
actions={
|
||||
(conversation.nicknameGivenName ||
|
||||
conversation.nicknameFamilyName ||
|
||||
conversation.note) && (
|
||||
<ContextMenu
|
||||
i18n={i18n}
|
||||
portalToRoot
|
||||
popperOptions={{
|
||||
placement: 'bottom',
|
||||
strategy: 'absolute',
|
||||
}}
|
||||
menuOptions={[
|
||||
{
|
||||
icon: 'ConversationDetails--nickname-actions--delete',
|
||||
label: i18n(
|
||||
'icu:ConversationDetails--nickname-actions--delete'
|
||||
),
|
||||
onClick: () => {
|
||||
setModalState(
|
||||
ModalState.ConfirmDeleteNicknameAndNote
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
{({ onClick }) => {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="ConversationDetails--nickname-actions"
|
||||
onClick={onClick}
|
||||
>
|
||||
<span className="ConversationDetails--nickname-actions-label">
|
||||
{i18n('icu:ConversationDetails--nickname-actions')}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
]}
|
||||
>
|
||||
{({ onClick }) => {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="ConversationDetails--nickname-actions"
|
||||
onClick={onClick}
|
||||
>
|
||||
<span className="ConversationDetails--nickname-actions-label">
|
||||
{i18n('icu:ConversationDetails--nickname-actions')}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}}
|
||||
</ContextMenu>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{selectedNavTab === NavTab.Chats && (
|
||||
<PanelRow
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:showChatColorEditor')}
|
||||
icon={IconType.color}
|
||||
/>
|
||||
}
|
||||
label={i18n('icu:showChatColorEditor')}
|
||||
onClick={() => {
|
||||
pushPanelForConversation({
|
||||
type: PanelType.ChatColorEditor,
|
||||
});
|
||||
}}
|
||||
right={
|
||||
<div
|
||||
className={`ConversationDetails__chat-color ConversationDetails__chat-color--${conversation.conversationColor}`}
|
||||
style={{
|
||||
...getCustomColorStyle(conversation.customColor),
|
||||
}}
|
||||
</ContextMenu>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{selectedNavTab === NavTab.Chats && (
|
||||
<PanelRow
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:showChatColorEditor')}
|
||||
icon={IconType.color}
|
||||
/>
|
||||
}
|
||||
label={i18n('icu:showChatColorEditor')}
|
||||
onClick={() => {
|
||||
pushPanelForConversation({
|
||||
type: PanelType.ChatColorEditor,
|
||||
});
|
||||
}}
|
||||
right={
|
||||
<div
|
||||
className={`ConversationDetails__chat-color ConversationDetails__chat-color--${conversation.conversationColor}`}
|
||||
style={{
|
||||
...getCustomColorStyle(conversation.customColor),
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isGroup && (
|
||||
<PanelRow
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:ConversationDetails--notifications')}
|
||||
icon={IconType.notifications}
|
||||
/>
|
||||
}
|
||||
label={i18n('icu:ConversationDetails--notifications')}
|
||||
onClick={() =>
|
||||
pushPanelForConversation({
|
||||
type: PanelType.NotificationSettings,
|
||||
})
|
||||
}
|
||||
right={
|
||||
conversation.muteExpiresAt
|
||||
? getMutedUntilText(conversation.muteExpiresAt, i18n)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{!isGroup && !conversation.isMe && (
|
||||
<PanelRow
|
||||
onClick={() => toggleSafetyNumberModal(conversation.id)}
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:ConversationDetails__viewSafetyNumber')}
|
||||
icon={IconType.verify}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<div className="ConversationDetails__safety-number">
|
||||
{i18n('icu:ConversationDetails__viewSafetyNumber')}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</PanelSection>
|
||||
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isGroup && (
|
||||
<PanelRow
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:ConversationDetails--notifications')}
|
||||
icon={IconType.notifications}
|
||||
/>
|
||||
}
|
||||
label={i18n('icu:ConversationDetails--notifications')}
|
||||
onClick={() =>
|
||||
pushPanelForConversation({
|
||||
type: PanelType.NotificationSettings,
|
||||
})
|
||||
}
|
||||
right={
|
||||
conversation.muteExpiresAt
|
||||
? getMutedUntilText(conversation.muteExpiresAt, i18n)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{!isGroup && !conversation.isMe && (
|
||||
<PanelRow
|
||||
onClick={() => toggleSafetyNumberModal(conversation.id)}
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:ConversationDetails__viewSafetyNumber')}
|
||||
icon={IconType.verify}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<div className="ConversationDetails__safety-number">
|
||||
{i18n('icu:ConversationDetails__viewSafetyNumber')}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</PanelSection>
|
||||
)}
|
||||
{isGroup && (
|
||||
<ConversationDetailsMembershipList
|
||||
canAddNewMembers={canAddNewMembers}
|
||||
|
@ -705,7 +713,7 @@ export function ConversationDetails({
|
|||
showLightbox={showLightbox}
|
||||
/>
|
||||
|
||||
{!isGroup && !conversation.isMe && (
|
||||
{!isGroup && !conversation.isMe && !isSignalConversation && (
|
||||
<ConversationDetailsGroups
|
||||
contactId={conversation.id}
|
||||
i18n={i18n}
|
||||
|
|
|
@ -44,6 +44,7 @@ function Wrapper(overrideProps: Partial<Props>) {
|
|||
membersCount={0}
|
||||
isGroup
|
||||
isMe={false}
|
||||
isSignalConversation={false}
|
||||
theme={theme}
|
||||
toggleAboutContactModal={action('toggleAboutContactModal')}
|
||||
{...overrideProps}
|
||||
|
|
|
@ -25,6 +25,7 @@ export type Props = {
|
|||
i18n: LocalizerType;
|
||||
isGroup: boolean;
|
||||
isMe: boolean;
|
||||
isSignalConversation: boolean;
|
||||
membersCount: number | null;
|
||||
startEditing: (isGroupTitle: boolean) => void;
|
||||
toggleAboutContactModal: (contactId: string) => void;
|
||||
|
@ -44,6 +45,7 @@ export function ConversationDetailsHeader({
|
|||
i18n,
|
||||
isGroup,
|
||||
isMe,
|
||||
isSignalConversation,
|
||||
membersCount,
|
||||
startEditing,
|
||||
toggleAboutContactModal,
|
||||
|
@ -194,6 +196,13 @@ export function ConversationDetailsHeader({
|
|||
<span className="ContactModal__official-badge__large" />
|
||||
</div>
|
||||
);
|
||||
} else if (isSignalConversation) {
|
||||
title = (
|
||||
<div className="ConversationDetailsHeader__title">
|
||||
<UserText text={conversation.title} />
|
||||
<span className="ContactModal__official-badge__large" />
|
||||
</div>
|
||||
);
|
||||
} else if (isGroup) {
|
||||
title = (
|
||||
<div className="ConversationDetailsHeader__title">
|
||||
|
|
|
@ -396,6 +396,7 @@ export class ReleaseNotesFetcher {
|
|||
|
||||
await this.#scheduleForNextRun();
|
||||
this.setTimeoutForNextRun();
|
||||
window.SignalCI?.handleEvent('release_notes_fetcher_complete', {});
|
||||
} catch (error) {
|
||||
const errorString =
|
||||
error instanceof HTTPError
|
||||
|
|
|
@ -67,6 +67,7 @@ import { useToastActions } from '../ducks/toast';
|
|||
import { isShowingAnyModal } from '../selectors/globalModals';
|
||||
import { isConversationEverUnregistered } from '../../util/isConversationUnregistered';
|
||||
import { isDirectConversation } from '../../util/whatTypeOfConversation';
|
||||
import { isConversationMuted } from '../../util/isConversationMuted';
|
||||
|
||||
function renderSmartCompositionRecording(
|
||||
recProps: SmartCompositionRecordingProps
|
||||
|
@ -232,6 +233,7 @@ export const SmartCompositionArea = memo(function SmartCompositionArea({
|
|||
toggleSelectMode,
|
||||
scrollToMessage,
|
||||
setMessageToEdit,
|
||||
setMuteExpiration,
|
||||
showConversation,
|
||||
} = useConversationsActions();
|
||||
const { cancelRecording, completeRecording, startRecording, errorRecording } =
|
||||
|
@ -325,7 +327,6 @@ export const SmartCompositionArea = memo(function SmartCompositionArea({
|
|||
(isConversationSMSOnly(conversation) ||
|
||||
isConversationEverUnregistered(conversation))
|
||||
}
|
||||
isSignalConversation={isSignalConversation(conversation)}
|
||||
isFetchingUUID={conversation.isFetchingUUID ?? null}
|
||||
isMissingMandatoryProfileSharing={isMissingRequiredProfileSharing(
|
||||
conversation
|
||||
|
@ -335,6 +336,10 @@ export const SmartCompositionArea = memo(function SmartCompositionArea({
|
|||
blockConversation={blockConversation}
|
||||
reportSpam={reportSpam}
|
||||
deleteConversation={deleteConversation}
|
||||
// Signal Conversation
|
||||
isSignalConversation={isSignalConversation(conversation)}
|
||||
isMuted={isConversationMuted(conversation)}
|
||||
setMuteExpiration={setMuteExpiration}
|
||||
// Groups
|
||||
groupVersion={conversation.groupVersion ?? null}
|
||||
isGroupV1AndDisabled={conversation.isGroupV1AndDisabled ?? null}
|
||||
|
|
|
@ -40,6 +40,7 @@ import { useCallingActions } from '../ducks/calling';
|
|||
import { useSearchActions } from '../ducks/search';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||
import { useLightboxActions } from '../ducks/lightbox';
|
||||
import { isSignalConversation } from '../../util/isSignalConversation';
|
||||
|
||||
export type SmartConversationDetailsProps = {
|
||||
conversationId: string;
|
||||
|
@ -193,6 +194,7 @@ export const SmartConversationDetails = memo(function SmartConversationDetails({
|
|||
i18n={i18n}
|
||||
isAdmin={isAdmin}
|
||||
isGroup={isGroup}
|
||||
isSignalConversation={isSignalConversation(conversation)}
|
||||
leaveGroup={leaveGroup}
|
||||
loadRecentMediaItems={loadRecentMediaItems}
|
||||
maxGroupSize={maxGroupSize}
|
||||
|
|
|
@ -129,6 +129,10 @@ export class App extends EventEmitter {
|
|||
return this.#waitForEvent('receipts');
|
||||
}
|
||||
|
||||
public async waitForReleaseNotesFetcher(): Promise<void> {
|
||||
return this.#waitForEvent('release_notes_fetcher_complete');
|
||||
}
|
||||
|
||||
public async waitForStorageService(): Promise<StorageServiceInfoType> {
|
||||
return this.#waitForEvent('storageServiceComplete');
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ describe('release notes', function (this: Mocha.Suite) {
|
|||
it('shows release notes with an image and body ranges', async () => {
|
||||
const firstWindow = await app.getWindow();
|
||||
|
||||
await app.waitForReleaseNotesFetcher();
|
||||
await firstWindow.evaluate('window.SignalCI.resetReleaseNotesFetcher()');
|
||||
|
||||
await app.close();
|
||||
|
|
|
@ -11,7 +11,7 @@ export function isSignalConversation(conversation: {
|
|||
const { id, serviceId } = conversation;
|
||||
|
||||
if (serviceId) {
|
||||
return serviceId === SIGNAL_ACI;
|
||||
return isSignalServiceId(serviceId);
|
||||
}
|
||||
|
||||
return window.ConversationController.isSignalConversationId(id);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue