Composer: Add silent post button and hide them on text (#5749)
This commit is contained in:
parent
440001b938
commit
7522a16188
@ -735,27 +735,26 @@ async function getFullChannelInfo(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateChatMutedState({
|
export function updateChatNotifySettings({
|
||||||
chat, isMuted, mutedUntil = 0,
|
chat, settings,
|
||||||
}: {
|
}: {
|
||||||
chat: ApiChat; isMuted?: boolean; mutedUntil?: number;
|
chat: ApiChat; settings: Partial<ApiPeerNotifySettings>;
|
||||||
}) {
|
}) {
|
||||||
if (isMuted && !mutedUntil) {
|
|
||||||
mutedUntil = MAX_INT_32;
|
|
||||||
}
|
|
||||||
invokeRequest(new GramJs.account.UpdateNotifySettings({
|
invokeRequest(new GramJs.account.UpdateNotifySettings({
|
||||||
peer: new GramJs.InputNotifyPeer({
|
peer: new GramJs.InputNotifyPeer({
|
||||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||||
}),
|
}),
|
||||||
settings: new GramJs.InputPeerNotifySettings({ muteUntil: mutedUntil }),
|
settings: new GramJs.InputPeerNotifySettings({
|
||||||
|
muteUntil: settings.mutedUntil,
|
||||||
|
showPreviews: settings.shouldShowPreviews,
|
||||||
|
silent: settings.isSilentPosting,
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
sendApiUpdate({
|
sendApiUpdate({
|
||||||
'@type': 'updateChatNotifySettings',
|
'@type': 'updateChatNotifySettings',
|
||||||
chatId: chat.id,
|
chatId: chat.id,
|
||||||
settings: {
|
settings,
|
||||||
mutedUntil,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
void requestChatUpdate({
|
void requestChatUpdate({
|
||||||
|
|||||||
@ -1271,6 +1271,18 @@
|
|||||||
"AriaOpenBotMenu" = "Open bot menu";
|
"AriaOpenBotMenu" = "Open bot menu";
|
||||||
"AriaOpenSymbolMenu" = "Choose emoji, sticker or GIF";
|
"AriaOpenSymbolMenu" = "Choose emoji, sticker or GIF";
|
||||||
"AriaComposerOpenScheduled" = "Open scheduled messages";
|
"AriaComposerOpenScheduled" = "Open scheduled messages";
|
||||||
|
"AriaComposerBotKeyboard" = "Show bot keyboard";
|
||||||
|
"AriaComposerSilentPostingEnable" = "Enable silent notifications.";
|
||||||
|
"AriaComposerSilentPostingDisable" = "Disable silent notifications.";
|
||||||
|
"ComposerSilentPostingEnabledTootlip" = "Subscribers will receive a silent notification.";
|
||||||
|
"ComposerSilentPostingDisabledTootlip" = "Subscribers will be notified when you post.";
|
||||||
|
"ComposerPlaceholder" = "Message";
|
||||||
|
"ComposerPlaceholderBroadcast" = "Broadcast";
|
||||||
|
"ComposerPlaceholderBroadcastSilent" = "Silent Broadcast";
|
||||||
|
"ComposerPlaceholderTopic" = "Message in {topic}";
|
||||||
|
"ComposerPlaceholderTopicGeneral" = "Message in General";
|
||||||
|
"ComposerStoryPlaceholderLocked" = "Replies restricted";
|
||||||
|
"ComposerPlaceholderNoText" = "Text not allowed";
|
||||||
"AriaComposerCancelVoice" = "Cancel voice recording";
|
"AriaComposerCancelVoice" = "Cancel voice recording";
|
||||||
"PreviewForwardedMessage_one" = "{count} forwarded message";
|
"PreviewForwardedMessage_one" = "{count} forwarded message";
|
||||||
"PreviewForwardedMessage_other" = "{count} forwarded messages";
|
"PreviewForwardedMessage_other" = "{count} forwarded messages";
|
||||||
|
|||||||
@ -292,6 +292,24 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.composer-action-buttons-container {
|
||||||
|
width: auto;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
+ .AttachMenu {
|
||||||
|
margin-left: var(--action-button-compact-fix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.composer-action-buttons {
|
||||||
|
display: flex;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-symbol-menu-button {
|
.mobile-symbol-menu-button {
|
||||||
@ -384,25 +402,32 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.message-input-wrapper {
|
.message-input-wrapper {
|
||||||
|
--action-button-size: var(--base-height, 3.5rem);
|
||||||
|
--action-button-compact-fix: -1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
--action-button-size: 2.875rem;
|
||||||
|
--action-button-compact-fix: -0.6875rem;
|
||||||
|
}
|
||||||
|
|
||||||
.input-scroller {
|
.input-scroller {
|
||||||
margin-right: 0.5rem;
|
--_scroller-right-gap: calc((var(--action-button-size) + var(--action-button-compact-fix) - 0.125rem));
|
||||||
padding-right: 0.25rem;
|
margin-right: calc(-1 * var(--_scroller-right-gap));
|
||||||
|
padding-right: var(--_scroller-right-gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
> .Spinner {
|
> .Spinner {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
--spinner-size: 1.5rem;
|
--spinner-size: 1.5rem;
|
||||||
margin-right: -0.5rem;
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .AttachMenu > .Button,
|
.composer-action-button {
|
||||||
> .Button {
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
background: none !important;
|
background: none !important;
|
||||||
width: var(--base-height, 3.5rem);
|
width: var(--action-button-size);
|
||||||
height: var(--base-height, 3.5rem);
|
height: var(--action-button-size);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
@ -411,17 +436,8 @@
|
|||||||
color: var(--color-composer-button);
|
color: var(--color-composer-button);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ .Button, + .AttachMenu {
|
+ .composer-action-button {
|
||||||
margin-left: -1rem;
|
margin-left: var(--action-button-compact-fix);
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
width: 2.875rem;
|
|
||||||
height: 2.875rem;
|
|
||||||
|
|
||||||
+ .Button, + .AttachMenu {
|
|
||||||
margin-left: -0.6875rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bot-menu {
|
&.bot-menu {
|
||||||
|
|||||||
@ -66,6 +66,7 @@ import {
|
|||||||
isSystemBot,
|
isSystemBot,
|
||||||
isUserId,
|
isUserId,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { getChatNotifySettings } from '../../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectBot,
|
selectBot,
|
||||||
selectCanPlayAnimatedEmojis,
|
selectCanPlayAnimatedEmojis,
|
||||||
@ -86,6 +87,8 @@ import {
|
|||||||
selectIsReactionPickerOpen,
|
selectIsReactionPickerOpen,
|
||||||
selectIsRightColumnShown,
|
selectIsRightColumnShown,
|
||||||
selectNewestMessageWithBotKeyboardButtons,
|
selectNewestMessageWithBotKeyboardButtons,
|
||||||
|
selectNotifyDefaults,
|
||||||
|
selectNotifyException,
|
||||||
selectNoWebPage,
|
selectNoWebPage,
|
||||||
selectPeerStory,
|
selectPeerStory,
|
||||||
selectPerformanceSettingsValue,
|
selectPerformanceSettingsValue,
|
||||||
@ -126,6 +129,7 @@ import useDerivedState from '../../hooks/useDerivedState';
|
|||||||
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
|
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
|
||||||
import useFlag from '../../hooks/useFlag';
|
import useFlag from '../../hooks/useFlag';
|
||||||
import useGetSelectionRange from '../../hooks/useGetSelectionRange';
|
import useGetSelectionRange from '../../hooks/useGetSelectionRange';
|
||||||
|
import useLang from '../../hooks/useLang';
|
||||||
import useLastCallback from '../../hooks/useLastCallback';
|
import useLastCallback from '../../hooks/useLastCallback';
|
||||||
import useOldLang from '../../hooks/useOldLang';
|
import useOldLang from '../../hooks/useOldLang';
|
||||||
import usePreviousDeprecated from '../../hooks/usePreviousDeprecated';
|
import usePreviousDeprecated from '../../hooks/usePreviousDeprecated';
|
||||||
@ -170,6 +174,7 @@ import ReactionSelector from '../middle/message/reactions/ReactionSelector';
|
|||||||
import Button from '../ui/Button';
|
import Button from '../ui/Button';
|
||||||
import ResponsiveHoverButton from '../ui/ResponsiveHoverButton';
|
import ResponsiveHoverButton from '../ui/ResponsiveHoverButton';
|
||||||
import Spinner from '../ui/Spinner';
|
import Spinner from '../ui/Spinner';
|
||||||
|
import Transition from '../ui/Transition';
|
||||||
import Avatar from './Avatar';
|
import Avatar from './Avatar';
|
||||||
import Icon from './icons/Icon';
|
import Icon from './icons/Icon';
|
||||||
import ReactionAnimatedEmoji from './reactions/ReactionAnimatedEmoji';
|
import ReactionAnimatedEmoji from './reactions/ReactionAnimatedEmoji';
|
||||||
@ -272,6 +277,7 @@ type StateProps =
|
|||||||
canPlayEffect?: boolean;
|
canPlayEffect?: boolean;
|
||||||
shouldPlayEffect?: boolean;
|
shouldPlayEffect?: boolean;
|
||||||
maxMessageLength: number;
|
maxMessageLength: number;
|
||||||
|
isSilentPosting?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MainButtonState {
|
enum MainButtonState {
|
||||||
@ -304,9 +310,6 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
canScheduleUntilOnline,
|
canScheduleUntilOnline,
|
||||||
isReady,
|
isReady,
|
||||||
isMobile,
|
isMobile,
|
||||||
onDropHide,
|
|
||||||
onFocus,
|
|
||||||
onBlur,
|
|
||||||
editingMessage,
|
editingMessage,
|
||||||
chatId,
|
chatId,
|
||||||
threadId,
|
threadId,
|
||||||
@ -376,7 +379,6 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
quickReplyMessages,
|
quickReplyMessages,
|
||||||
quickReplies,
|
quickReplies,
|
||||||
canSendQuickReplies,
|
canSendQuickReplies,
|
||||||
onForward,
|
|
||||||
webPagePreview,
|
webPagePreview,
|
||||||
noWebPage,
|
noWebPage,
|
||||||
isContactRequirePremium,
|
isContactRequirePremium,
|
||||||
@ -386,6 +388,11 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
canPlayEffect,
|
canPlayEffect,
|
||||||
shouldPlayEffect,
|
shouldPlayEffect,
|
||||||
maxMessageLength,
|
maxMessageLength,
|
||||||
|
isSilentPosting,
|
||||||
|
onDropHide,
|
||||||
|
onFocus,
|
||||||
|
onBlur,
|
||||||
|
onForward,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
sendMessage,
|
sendMessage,
|
||||||
@ -412,9 +419,11 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
saveEffectInDraft,
|
saveEffectInDraft,
|
||||||
setReactionEffect,
|
setReactionEffect,
|
||||||
hideEffectInComposer,
|
hideEffectInComposer,
|
||||||
|
updateChatSilentPosting,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const lang = useOldLang();
|
const oldLang = useOldLang();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const inputRef = useRef<HTMLDivElement>(null);
|
const inputRef = useRef<HTMLDivElement>(null);
|
||||||
@ -785,21 +794,21 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
const notificationNumber = customEmojiNotificationNumber.current;
|
const notificationNumber = customEmojiNotificationNumber.current;
|
||||||
if (!notificationNumber) {
|
if (!notificationNumber) {
|
||||||
showNotification({
|
showNotification({
|
||||||
message: lang('UnlockPremiumEmojiHint'),
|
message: oldLang('UnlockPremiumEmojiHint'),
|
||||||
action: {
|
action: {
|
||||||
action: 'openPremiumModal',
|
action: 'openPremiumModal',
|
||||||
payload: { initialSection: 'animated_emoji' },
|
payload: { initialSection: 'animated_emoji' },
|
||||||
},
|
},
|
||||||
actionText: lang('PremiumMore'),
|
actionText: oldLang('PremiumMore'),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
showNotification({
|
showNotification({
|
||||||
message: lang('UnlockPremiumEmojiHint2'),
|
message: oldLang('UnlockPremiumEmojiHint2'),
|
||||||
action: {
|
action: {
|
||||||
action: 'openChat',
|
action: 'openChat',
|
||||||
payload: { id: currentUserId, shouldReplaceHistory: true },
|
payload: { id: currentUserId, shouldReplaceHistory: true },
|
||||||
},
|
},
|
||||||
actionText: lang('Open'),
|
actionText: oldLang('Open'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
customEmojiNotificationNumber.current = Number(!notificationNumber);
|
customEmojiNotificationNumber.current = Number(!notificationNumber);
|
||||||
@ -910,7 +919,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
: slowMode.seconds - secondsSinceLastMessage!;
|
: slowMode.seconds - secondsSinceLastMessage!;
|
||||||
showDialog({
|
showDialog({
|
||||||
data: {
|
data: {
|
||||||
message: lang('SlowModeHint', formatMediaDuration(secondsRemaining)),
|
message: oldLang('SlowModeHint', formatMediaDuration(secondsRemaining)),
|
||||||
isSlowMode: true,
|
isSlowMode: true,
|
||||||
hasErrorKey: false,
|
hasErrorKey: false,
|
||||||
},
|
},
|
||||||
@ -942,6 +951,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
if (!currentMessageList && !storyId) {
|
if (!currentMessageList && !storyId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
isSilent = isSilent || isSilentPosting;
|
||||||
|
|
||||||
const { text, entities } = parseHtmlAsFormattedText(getHtml());
|
const { text, entities } = parseHtmlAsFormattedText(getHtml());
|
||||||
if (!text && !attachmentsToSend.length) {
|
if (!text && !attachmentsToSend.length) {
|
||||||
@ -1018,6 +1028,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSilent = isSilent || isSilentPosting;
|
||||||
|
|
||||||
let currentAttachments = attachments;
|
let currentAttachments = attachments;
|
||||||
|
|
||||||
if (activeVoiceRecording) {
|
if (activeVoiceRecording) {
|
||||||
@ -1129,7 +1141,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
threadId,
|
threadId,
|
||||||
queryId,
|
queryId,
|
||||||
scheduledAt,
|
scheduledAt,
|
||||||
isSilent,
|
isSilent: isSilent || isSilentPosting,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1197,6 +1209,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSilent = isSilent || isSilentPosting;
|
||||||
|
|
||||||
if (isInScheduledList || isScheduleRequested) {
|
if (isInScheduledList || isScheduleRequested) {
|
||||||
forceShowSymbolMenu();
|
forceShowSymbolMenu();
|
||||||
requestCalendar((scheduledAt) => {
|
requestCalendar((scheduledAt) => {
|
||||||
@ -1225,6 +1239,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSilent = isSilent || isSilentPosting;
|
||||||
|
|
||||||
sticker = {
|
sticker = {
|
||||||
...sticker,
|
...sticker,
|
||||||
isPreloadedGlobally: true,
|
isPreloadedGlobally: true,
|
||||||
@ -1261,6 +1277,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSilent = isSilent || isSilentPosting;
|
||||||
|
|
||||||
if (isInScheduledList || isScheduleRequested) {
|
if (isInScheduledList || isScheduleRequested) {
|
||||||
requestCalendar((scheduledAt) => {
|
requestCalendar((scheduledAt) => {
|
||||||
handleMessageSchedule({
|
handleMessageSchedule({
|
||||||
@ -1308,7 +1326,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
closePollModal();
|
closePollModal();
|
||||||
} else {
|
} else {
|
||||||
sendMessage({ messageList: currentMessageList, poll });
|
sendMessage({ messageList: currentMessageList, poll, isSilent: isSilentPosting });
|
||||||
closePollModal();
|
closePollModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1378,6 +1396,17 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleToggleSilentPosting = useLastCallback(() => {
|
||||||
|
const newValue = !isSilentPosting;
|
||||||
|
updateChatSilentPosting({ chatId, isEnabled: newValue });
|
||||||
|
|
||||||
|
showNotification({
|
||||||
|
localId: 'silentPosting',
|
||||||
|
icon: newValue ? 'mute' : 'unmute',
|
||||||
|
message: lang(`ComposerSilentPosting${newValue ? 'Enabled' : 'Disabled'}Tootlip`),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isRightColumnShown && isMobile) {
|
if (isRightColumnShown && isMobile) {
|
||||||
closeSymbolMenu();
|
closeSymbolMenu();
|
||||||
@ -1396,10 +1425,11 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
}
|
}
|
||||||
}, [isSelectModeActive, enableHover, disableHover, isReady]);
|
}, [isSelectModeActive, enableHover, disableHover, isReady]);
|
||||||
|
|
||||||
const withBotMenuButton = isChatWithBot && botMenuButton?.type === 'webApp' && !editingMessage;
|
const hasText = useDerivedState(() => Boolean(getHtml()), [getHtml]);
|
||||||
const isBotMenuButtonOpen = useDerivedState(() => {
|
|
||||||
return withBotMenuButton && !getHtml() && !activeVoiceRecording;
|
const withBotMenuButton = isChatWithBot && botMenuButton?.type === 'webApp' && !editingMessage
|
||||||
}, [withBotMenuButton, getHtml, activeVoiceRecording]);
|
&& messageListType === 'thread';
|
||||||
|
const isBotMenuButtonOpen = withBotMenuButton && !hasText && !activeVoiceRecording;
|
||||||
|
|
||||||
const [timedPlaceholderLangKey, timedPlaceholderDate] = useMemo(() => {
|
const [timedPlaceholderLangKey, timedPlaceholderDate] = useMemo(() => {
|
||||||
if (slowMode?.nextSendDate) {
|
if (slowMode?.nextSendDate) {
|
||||||
@ -1419,11 +1449,33 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
|| isCustomSendMenuOpen || Boolean(activeVoiceRecording) || attachments.length > 0 || isInputHasFocus;
|
|| isCustomSendMenuOpen || Boolean(activeVoiceRecording) || attachments.length > 0 || isInputHasFocus;
|
||||||
const isReactionSelectorOpen = isComposerHasFocus && !isReactionPickerOpen && isInStoryViewer && !isAttachMenuOpen
|
const isReactionSelectorOpen = isComposerHasFocus && !isReactionPickerOpen && isInStoryViewer && !isAttachMenuOpen
|
||||||
&& !isSymbolMenuOpen;
|
&& !isSymbolMenuOpen;
|
||||||
const placeholderForForumAsMessages = chat?.isForum && chat?.isForumAsMessages && threadId === MAIN_THREAD_ID
|
|
||||||
? (replyToTopic
|
const placeholder = useMemo(() => {
|
||||||
? lang('Chat.InputPlaceholderReplyInTopic', replyToTopic.title)
|
if (activeVoiceRecording && windowWidth <= SCREEN_WIDTH_TO_HIDE_PLACEHOLDER) {
|
||||||
: lang('Message.Placeholder.MessageInGeneral'))
|
return '';
|
||||||
: undefined;
|
}
|
||||||
|
|
||||||
|
if (!isComposerBlocked) {
|
||||||
|
if (botKeyboardPlaceholder) return botKeyboardPlaceholder;
|
||||||
|
if (inputPlaceholder) return inputPlaceholder;
|
||||||
|
if (chat?.isForum && chat?.isForumAsMessages && threadId === MAIN_THREAD_ID) {
|
||||||
|
return replyToTopic
|
||||||
|
? lang('ComposerPlaceholderTopic', { topic: replyToTopic.title })
|
||||||
|
: lang('ComposerPlaceholderTopicGeneral');
|
||||||
|
}
|
||||||
|
if (isChannel) {
|
||||||
|
return lang(isSilentPosting ? 'ComposerPlaceholderBroadcastSilent' : 'ComposerPlaceholderBroadcast');
|
||||||
|
}
|
||||||
|
return lang('ComposerPlaceholder');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInStoryViewer) return lang('ComposerStoryPlaceholderLocked');
|
||||||
|
|
||||||
|
return lang('ComposerPlaceholderNoText');
|
||||||
|
}, [
|
||||||
|
activeVoiceRecording, botKeyboardPlaceholder, chat, inputPlaceholder, isChannel, isComposerBlocked,
|
||||||
|
isInStoryViewer, isSilentPosting, lang, replyToTopic, threadId, windowWidth,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isComposerHasFocus) {
|
if (isComposerHasFocus) {
|
||||||
@ -1452,7 +1504,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
if (areVoiceMessagesNotAllowed) {
|
if (areVoiceMessagesNotAllowed) {
|
||||||
if (!canSendVoiceByPrivacy) {
|
if (!canSendVoiceByPrivacy) {
|
||||||
showNotification({
|
showNotification({
|
||||||
message: lang('VoiceMessagesRestrictedByPrivacy', chat?.title),
|
message: oldLang('VoiceMessagesRestrictedByPrivacy', chat?.title),
|
||||||
});
|
});
|
||||||
} else if (!canSendVoices) {
|
} else if (!canSendVoices) {
|
||||||
showAllowedMessageTypesNotification({ chatId });
|
showAllowedMessageTypesNotification({ chatId });
|
||||||
@ -1788,9 +1840,10 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
round
|
round
|
||||||
color="translucent"
|
color="translucent"
|
||||||
onClick={isSendAsMenuOpen ? closeSendAsMenu : handleSendAsMenuOpen}
|
onClick={isSendAsMenuOpen ? closeSendAsMenu : handleSendAsMenuOpen}
|
||||||
ariaLabel={lang('SendMessageAsTitle')}
|
ariaLabel={oldLang('SendMessageAsTitle')}
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
'send-as-button',
|
'send-as-button',
|
||||||
|
'composer-action-button',
|
||||||
shouldAnimateSendAsButtonRef.current && 'appear-animation',
|
shouldAnimateSendAsButtonRef.current && 'appear-animation',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@ -1840,13 +1893,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
isReady={isReady}
|
isReady={isReady}
|
||||||
isActive={!hasAttachments}
|
isActive={!hasAttachments}
|
||||||
getHtml={getHtml}
|
getHtml={getHtml}
|
||||||
placeholder={
|
placeholder={placeholder}
|
||||||
activeVoiceRecording && windowWidth <= SCREEN_WIDTH_TO_HIDE_PLACEHOLDER
|
|
||||||
? ''
|
|
||||||
: (!isComposerBlocked
|
|
||||||
? (botKeyboardPlaceholder || inputPlaceholder || lang(placeholderForForumAsMessages || 'Message'))
|
|
||||||
: isInStoryViewer ? lang('StoryRepliesLocked') : lang('Chat.PlaceholderTextNotAllowed'))
|
|
||||||
}
|
|
||||||
timedPlaceholderDate={timedPlaceholderDate}
|
timedPlaceholderDate={timedPlaceholderDate}
|
||||||
timedPlaceholderLangKey={timedPlaceholderLangKey}
|
timedPlaceholderLangKey={timedPlaceholderLangKey}
|
||||||
forcedPlaceholder={inlineBotHelp}
|
forcedPlaceholder={inlineBotHelp}
|
||||||
@ -1866,29 +1913,55 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
{isInlineBotLoading && Boolean(inlineBotId) && (
|
{isInlineBotLoading && Boolean(inlineBotId) && (
|
||||||
<Spinner color="gray" />
|
<Spinner color="gray" />
|
||||||
)}
|
)}
|
||||||
{withScheduledButton && (
|
<Transition
|
||||||
<Button
|
className="composer-action-buttons-container"
|
||||||
round
|
slideClassName="composer-action-buttons"
|
||||||
faded
|
activeKey={Number(hasText)}
|
||||||
className="scheduled-button"
|
direction="inverse"
|
||||||
color="translucent"
|
name="slideFadeAndroid"
|
||||||
onClick={handleAllScheduledClick}
|
>
|
||||||
ariaLabel="Open scheduled messages"
|
{!hasText && (
|
||||||
>
|
<>
|
||||||
<Icon name="schedule" />
|
{isChannel && (
|
||||||
</Button>
|
<Button
|
||||||
)}
|
round
|
||||||
{Boolean(botKeyboardMessageId) && !activeVoiceRecording && !editingMessage && (
|
faded
|
||||||
<ResponsiveHoverButton
|
className="composer-action-button"
|
||||||
className={isBotKeyboardOpen ? 'activated' : ''}
|
color="translucent"
|
||||||
round
|
onClick={handleToggleSilentPosting}
|
||||||
color="translucent"
|
ariaLabel={lang(
|
||||||
onActivate={openBotKeyboard}
|
isSilentPosting ? 'AriaComposerSilentPostingDisable' : 'AriaComposerSilentPostingEnable',
|
||||||
ariaLabel="Open bot command keyboard"
|
)}
|
||||||
>
|
>
|
||||||
<Icon name="bot-command" />
|
<Icon name={isSilentPosting ? 'mute' : 'unmute'} />
|
||||||
</ResponsiveHoverButton>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
{withScheduledButton && (
|
||||||
|
<Button
|
||||||
|
round
|
||||||
|
faded
|
||||||
|
className="composer-action-button scheduled-button"
|
||||||
|
color="translucent"
|
||||||
|
onClick={handleAllScheduledClick}
|
||||||
|
ariaLabel={lang('AriaComposerOpenScheduled')}
|
||||||
|
>
|
||||||
|
<Icon name="schedule" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{Boolean(botKeyboardMessageId) && !activeVoiceRecording && !editingMessage && (
|
||||||
|
<ResponsiveHoverButton
|
||||||
|
className={buildClassName('composer-action-button', isBotKeyboardOpen && 'activated')}
|
||||||
|
round
|
||||||
|
color="translucent"
|
||||||
|
onActivate={openBotKeyboard}
|
||||||
|
ariaLabel={lang('AriaComposerBotKeyboard')}
|
||||||
|
>
|
||||||
|
<Icon name="bot-command" />
|
||||||
|
</ResponsiveHoverButton>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Transition>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeVoiceRecording && Boolean(currentRecordTime) && (
|
{activeVoiceRecording && Boolean(currentRecordTime) && (
|
||||||
@ -1968,7 +2041,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
className={buildClassName('view-once', isViewOnceEnabled && 'active')}
|
className={buildClassName('view-once', isViewOnceEnabled && 'active')}
|
||||||
round
|
round
|
||||||
color="secondary"
|
color="secondary"
|
||||||
ariaLabel={lang('Chat.PlayOnceVoiceMessageTooltip')}
|
ariaLabel={oldLang('Chat.PlayOnceVoiceMessageTooltip')}
|
||||||
onClick={toogleViewOnceEnabled}
|
onClick={toogleViewOnceEnabled}
|
||||||
>
|
>
|
||||||
<Icon name="view-once" />
|
<Icon name="view-once" />
|
||||||
@ -1994,7 +2067,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
onClick={handleLikeStory}
|
onClick={handleLikeStory}
|
||||||
onContextMenu={handleStoryPickerContextMenu}
|
onContextMenu={handleStoryPickerContextMenu}
|
||||||
onMouseDown={handleBeforeStoryPickerContextMenu}
|
onMouseDown={handleBeforeStoryPickerContextMenu}
|
||||||
ariaLabel={lang('AccDescrLike')}
|
ariaLabel={oldLang('AccDescrLike')}
|
||||||
ref={storyReactionRef}
|
ref={storyReactionRef}
|
||||||
>
|
>
|
||||||
{sentStoryReaction && (
|
{sentStoryReaction && (
|
||||||
@ -2023,7 +2096,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
disabled={areVoiceMessagesNotAllowed}
|
disabled={areVoiceMessagesNotAllowed}
|
||||||
allowDisabledClick
|
allowDisabledClick
|
||||||
noFastClick
|
noFastClick
|
||||||
ariaLabel={lang(sendButtonAriaLabel)}
|
ariaLabel={oldLang(sendButtonAriaLabel)}
|
||||||
onClick={mainButtonHandler}
|
onClick={mainButtonHandler}
|
||||||
onContextMenu={
|
onContextMenu={
|
||||||
mainButtonState === MainButtonState.Send && canShowCustomSendMenu ? handleContextMenu : undefined
|
mainButtonState === MainButtonState.Send && canShowCustomSendMenu ? handleContextMenu : undefined
|
||||||
@ -2140,6 +2213,11 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const canSendQuickReplies = isChatWithUser && !isChatWithBot && !isInScheduledList && !isChatWithSelf;
|
const canSendQuickReplies = isChatWithUser && !isChatWithBot && !isInScheduledList && !isChatWithSelf;
|
||||||
|
|
||||||
const noWebPage = selectNoWebPage(global, chatId, threadId);
|
const noWebPage = selectNoWebPage(global, chatId, threadId);
|
||||||
|
const isSilentPosting = chat && getChatNotifySettings(
|
||||||
|
chat,
|
||||||
|
selectNotifyDefaults(global),
|
||||||
|
selectNotifyException(global, chatId),
|
||||||
|
)?.isSilentPosting;
|
||||||
|
|
||||||
const areEffectsSupported = isChatWithUser && !isChatWithBot
|
const areEffectsSupported = isChatWithUser && !isChatWithBot
|
||||||
&& !isInScheduledList && !isChatWithSelf && type !== 'story' && chatId !== SERVICE_NOTIFICATIONS_USER_ID;
|
&& !isInScheduledList && !isChatWithSelf && type !== 'story' && chatId !== SERVICE_NOTIFICATIONS_USER_ID;
|
||||||
@ -2227,6 +2305,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
canPlayEffect,
|
canPlayEffect,
|
||||||
shouldPlayEffect,
|
shouldPlayEffect,
|
||||||
maxMessageLength,
|
maxMessageLength,
|
||||||
|
isSilentPosting,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(Composer));
|
)(Composer));
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import {
|
|||||||
getMessageWebPagePhoto,
|
getMessageWebPagePhoto,
|
||||||
getMessageWebPageVideo,
|
getMessageWebPageVideo,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { getDebugLogs } from '../../../util/debugConsole';
|
import { getDebugLogs } from '../../../util/debugConsole';
|
||||||
import { validateFiles } from '../../../util/files';
|
import { validateFiles } from '../../../util/files';
|
||||||
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
||||||
@ -175,7 +176,7 @@ const AttachMenu: FC<OwnProps> = ({
|
|||||||
editingMessage && canEditMedia ? (
|
editingMessage && canEditMedia ? (
|
||||||
<ResponsiveHoverButton
|
<ResponsiveHoverButton
|
||||||
id="replace-menu-button"
|
id="replace-menu-button"
|
||||||
className={isAttachMenuOpen ? 'AttachMenu--button activated' : 'AttachMenu--button'}
|
className={buildClassName('AttachMenu--button composer-action-button', isAttachMenuOpen && 'activated')}
|
||||||
round
|
round
|
||||||
color="translucent"
|
color="translucent"
|
||||||
onActivate={handleToggleAttachMenu}
|
onActivate={handleToggleAttachMenu}
|
||||||
@ -189,7 +190,7 @@ const AttachMenu: FC<OwnProps> = ({
|
|||||||
<ResponsiveHoverButton
|
<ResponsiveHoverButton
|
||||||
id="attach-menu-button"
|
id="attach-menu-button"
|
||||||
disabled={Boolean(editingMessage)}
|
disabled={Boolean(editingMessage)}
|
||||||
className={isAttachMenuOpen ? 'AttachMenu--button activated' : 'AttachMenu--button'}
|
className={buildClassName('AttachMenu--button composer-action-button', isAttachMenuOpen && 'activated')}
|
||||||
round
|
round
|
||||||
color="translucent"
|
color="translucent"
|
||||||
onActivate={handleToggleAttachMenu}
|
onActivate={handleToggleAttachMenu}
|
||||||
|
|||||||
@ -46,7 +46,7 @@ const BotMenuButton: FC<OwnProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={buildClassName('bot-menu', isOpen && 'open')}
|
className={buildClassName('composer-action-button bot-menu', isOpen && 'open')}
|
||||||
round
|
round
|
||||||
color="translucent"
|
color="translucent"
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
|
|||||||
@ -92,7 +92,7 @@ const SymbolMenuButton: FC<OwnProps> = ({
|
|||||||
const [contextMenuAnchor, setContextMenuAnchor] = useState<IAnchorPosition | undefined>(undefined);
|
const [contextMenuAnchor, setContextMenuAnchor] = useState<IAnchorPosition | undefined>(undefined);
|
||||||
|
|
||||||
const symbolMenuButtonClassName = buildClassName(
|
const symbolMenuButtonClassName = buildClassName(
|
||||||
'mobile-symbol-menu-button',
|
'composer-action-button mobile-symbol-menu-button',
|
||||||
!isReady && 'not-ready',
|
!isReady && 'not-ready',
|
||||||
isSymbolMenuLoaded
|
isSymbolMenuLoaded
|
||||||
? (isSymbolMenuOpen && 'menu-opened')
|
? (isSymbolMenuOpen && 'menu-opened')
|
||||||
@ -157,7 +157,7 @@ const SymbolMenuButton: FC<OwnProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<ResponsiveHoverButton
|
<ResponsiveHoverButton
|
||||||
className={buildClassName('symbol-menu-button', isSymbolMenuOpen && 'activated')}
|
className={buildClassName('composer-action-button symbol-menu-button', isSymbolMenuOpen && 'activated')}
|
||||||
round
|
round
|
||||||
color="translucent"
|
color="translucent"
|
||||||
onActivate={handleActivateSymbolMenu}
|
onActivate={handleActivateSymbolMenu}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import {
|
|||||||
CHAT_LIST_LOAD_SLICE,
|
CHAT_LIST_LOAD_SLICE,
|
||||||
DEBUG,
|
DEBUG,
|
||||||
GLOBAL_SUGGESTED_CHANNELS_ID,
|
GLOBAL_SUGGESTED_CHANNELS_ID,
|
||||||
|
MAX_INT_32,
|
||||||
RE_TG_LINK,
|
RE_TG_LINK,
|
||||||
SAVED_FOLDER_ID,
|
SAVED_FOLDER_ID,
|
||||||
SERVICE_NOTIFICATIONS_USER_ID,
|
SERVICE_NOTIFICATIONS_USER_ID,
|
||||||
@ -625,13 +626,29 @@ addActionHandler('requestSavedDialogUpdate', async (global, actions, payload): P
|
|||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('updateChatMutedState', (global, actions, payload): ActionReturnType => {
|
addActionHandler('updateChatMutedState', (global, actions, payload): ActionReturnType => {
|
||||||
const { chatId, isMuted, mutedUntil } = payload;
|
const { chatId, isMuted } = payload;
|
||||||
|
let { mutedUntil } = payload;
|
||||||
|
|
||||||
|
const chat = selectChat(global, chatId);
|
||||||
|
if (!chat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isMuted && !mutedUntil) {
|
||||||
|
mutedUntil = MAX_INT_32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void callApi('updateChatNotifySettings', { chat, settings: { mutedUntil } });
|
||||||
|
});
|
||||||
|
|
||||||
|
addActionHandler('updateChatSilentPosting', (global, actions, payload): ActionReturnType => {
|
||||||
|
const { chatId, isEnabled } = payload;
|
||||||
|
|
||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
if (!chat) {
|
if (!chat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void callApi('updateChatMutedState', { chat, isMuted, mutedUntil });
|
void callApi('updateChatNotifySettings', { chat, settings: { isSilentPosting: isEnabled } });
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('updateTopicMutedState', (global, actions, payload): ActionReturnType => {
|
addActionHandler('updateTopicMutedState', (global, actions, payload): ActionReturnType => {
|
||||||
|
|||||||
@ -1051,6 +1051,10 @@ export interface ActionPayloads {
|
|||||||
isMuted?: boolean;
|
isMuted?: boolean;
|
||||||
mutedUntil?: number;
|
mutedUntil?: number;
|
||||||
};
|
};
|
||||||
|
updateChatSilentPosting: {
|
||||||
|
chatId: string;
|
||||||
|
isEnabled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
updateChat: {
|
updateChat: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
|
|||||||
14
src/types/language.d.ts
vendored
14
src/types/language.d.ts
vendored
@ -1087,6 +1087,17 @@ export interface LangPair {
|
|||||||
'AriaOpenBotMenu': undefined;
|
'AriaOpenBotMenu': undefined;
|
||||||
'AriaOpenSymbolMenu': undefined;
|
'AriaOpenSymbolMenu': undefined;
|
||||||
'AriaComposerOpenScheduled': undefined;
|
'AriaComposerOpenScheduled': undefined;
|
||||||
|
'AriaComposerBotKeyboard': undefined;
|
||||||
|
'AriaComposerSilentPostingEnable': undefined;
|
||||||
|
'AriaComposerSilentPostingDisable': undefined;
|
||||||
|
'ComposerSilentPostingEnabledTootlip': undefined;
|
||||||
|
'ComposerSilentPostingDisabledTootlip': undefined;
|
||||||
|
'ComposerPlaceholder': undefined;
|
||||||
|
'ComposerPlaceholderBroadcast': undefined;
|
||||||
|
'ComposerPlaceholderBroadcastSilent': undefined;
|
||||||
|
'ComposerPlaceholderTopicGeneral': undefined;
|
||||||
|
'ComposerStoryPlaceholderLocked': undefined;
|
||||||
|
'ComposerPlaceholderNoText': undefined;
|
||||||
'AriaComposerCancelVoice': undefined;
|
'AriaComposerCancelVoice': undefined;
|
||||||
'PreviewEditMessage': undefined;
|
'PreviewEditMessage': undefined;
|
||||||
'FileDropZoneTitle': undefined;
|
'FileDropZoneTitle': undefined;
|
||||||
@ -1706,6 +1717,9 @@ export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
|||||||
'MediaViewDownloading': {
|
'MediaViewDownloading': {
|
||||||
'count': V;
|
'count': V;
|
||||||
};
|
};
|
||||||
|
'ComposerPlaceholderTopic': {
|
||||||
|
'topic': V;
|
||||||
|
};
|
||||||
'ChannelManagementLinkDiscussion': {
|
'ChannelManagementLinkDiscussion': {
|
||||||
'group': V;
|
'group': V;
|
||||||
'channel': V;
|
'channel': V;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user