You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-03 00:33:22 +03:00 
			
		
		
		
	Merge pull request #6752 from matrix-org/revert-6682-gsouquet/compact-composer-18533
Revert "Create narrow mode for Composer"
This commit is contained in:
		@@ -237,15 +237,6 @@ limitations under the License.
 | 
			
		||||
    mask-image: url('$(res)/img/element-icons/room/composer/sticker.svg');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MessageComposer_buttonMenu::before {
 | 
			
		||||
    mask-image: url('$(res)/img/image-view/more.svg');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MessageComposer_closeButtonMenu::before {
 | 
			
		||||
    transform: rotate(90deg);
 | 
			
		||||
    transform-origin: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MessageComposer_sendMessage {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    position: relative;
 | 
			
		||||
@@ -365,8 +356,3 @@ limitations under the License.
 | 
			
		||||
        margin-right: 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MessageComposer_Menu .mx_CallContextMenu_item {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
import React, { createRef } from 'react';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
 | 
			
		||||
@@ -27,13 +27,7 @@ import { makeRoomPermalink, RoomPermalinkCreator } from '../../../utils/permalin
 | 
			
		||||
import ContentMessages from '../../../ContentMessages';
 | 
			
		||||
import E2EIcon from './E2EIcon';
 | 
			
		||||
import SettingsStore from "../../../settings/SettingsStore";
 | 
			
		||||
import {
 | 
			
		||||
    aboveLeftOf,
 | 
			
		||||
    ContextMenu,
 | 
			
		||||
    ContextMenuTooltipButton,
 | 
			
		||||
    useContextMenu,
 | 
			
		||||
    MenuItem,
 | 
			
		||||
} from "../../structures/ContextMenu";
 | 
			
		||||
import { aboveLeftOf, ContextMenu, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
 | 
			
		||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
 | 
			
		||||
import ReplyPreview from "./ReplyPreview";
 | 
			
		||||
import { UIFeature } from "../../../settings/UIFeature";
 | 
			
		||||
@@ -51,9 +45,6 @@ import { Action } from "../../../dispatcher/actions";
 | 
			
		||||
import EditorModel from "../../../editor/model";
 | 
			
		||||
import EmojiPicker from '../emojipicker/EmojiPicker';
 | 
			
		||||
import MemberStatusMessageAvatar from "../avatars/MemberStatusMessageAvatar";
 | 
			
		||||
import UIStore, { UI_EVENTS } from '../../../stores/UIStore';
 | 
			
		||||
 | 
			
		||||
const NARROW_MODE_BREAKPOINT = 500;
 | 
			
		||||
 | 
			
		||||
interface IComposerAvatarProps {
 | 
			
		||||
    me: object;
 | 
			
		||||
@@ -80,13 +71,13 @@ function SendButton(props: ISendButtonProps) {
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const EmojiButton = ({ addEmoji, menuPosition }) => {
 | 
			
		||||
const EmojiButton = ({ addEmoji }) => {
 | 
			
		||||
    const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
 | 
			
		||||
 | 
			
		||||
    let contextMenu;
 | 
			
		||||
    if (menuDisplayed) {
 | 
			
		||||
        const position = menuPosition ?? aboveLeftOf(button.current.getBoundingClientRect());
 | 
			
		||||
        contextMenu = <ContextMenu {...position} onFinished={closeMenu} managed={false}>
 | 
			
		||||
        const buttonRect = button.current.getBoundingClientRect();
 | 
			
		||||
        contextMenu = <ContextMenu {...aboveLeftOf(buttonRect)} onFinished={closeMenu} managed={false}>
 | 
			
		||||
            <EmojiPicker onChoose={addEmoji} showQuickReactions={true} />
 | 
			
		||||
        </ContextMenu>;
 | 
			
		||||
    }
 | 
			
		||||
@@ -205,9 +196,6 @@ interface IState {
 | 
			
		||||
    haveRecording: boolean;
 | 
			
		||||
    recordingTimeLeftSeconds?: number;
 | 
			
		||||
    me?: RoomMember;
 | 
			
		||||
    narrowMode?: boolean;
 | 
			
		||||
    isMenuOpen: boolean;
 | 
			
		||||
    showStickers: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@replaceableComponent("views.rooms.MessageComposer")
 | 
			
		||||
@@ -215,7 +203,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
    private dispatcherRef: string;
 | 
			
		||||
    private messageComposerInput: SendMessageComposer;
 | 
			
		||||
    private voiceRecordingButton: VoiceRecordComposerTile;
 | 
			
		||||
    private ref: React.RefObject<HTMLDivElement> = createRef();
 | 
			
		||||
 | 
			
		||||
    static defaultProps = {
 | 
			
		||||
        replyInThread: false,
 | 
			
		||||
@@ -233,8 +220,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
            isComposerEmpty: true,
 | 
			
		||||
            haveRecording: false,
 | 
			
		||||
            recordingTimeLeftSeconds: null, // when set to a number, shows a toast
 | 
			
		||||
            isMenuOpen: false,
 | 
			
		||||
            showStickers: false,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -242,21 +227,8 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
        this.dispatcherRef = dis.register(this.onAction);
 | 
			
		||||
        MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
 | 
			
		||||
        this.waitForOwnMember();
 | 
			
		||||
        UIStore.instance.trackElementDimensions("MessageComposer", this.ref.current);
 | 
			
		||||
        UIStore.instance.on("MessageComposer", this.onResize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onResize = (type: UI_EVENTS, entry: ResizeObserverEntry) => {
 | 
			
		||||
        if (type === UI_EVENTS.Resize) {
 | 
			
		||||
            const narrowMode = entry.contentRect.width <= NARROW_MODE_BREAKPOINT;
 | 
			
		||||
            this.setState({
 | 
			
		||||
                narrowMode,
 | 
			
		||||
                isMenuOpen: !narrowMode ? false : this.state.isMenuOpen,
 | 
			
		||||
                showStickers: false,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onAction = (payload: ActionPayload) => {
 | 
			
		||||
        if (payload.action === 'reply_to_event') {
 | 
			
		||||
            // add a timeout for the reply preview to be rendered, so
 | 
			
		||||
@@ -291,8 +263,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
        }
 | 
			
		||||
        VoiceRecordingStore.instance.off(UPDATE_EVENT, this.onVoiceStoreUpdate);
 | 
			
		||||
        dis.unregister(this.dispatcherRef);
 | 
			
		||||
        UIStore.instance.stopTrackingElementDimensions("MessageComposer");
 | 
			
		||||
        UIStore.instance.removeListener("MessageComposer", this.onResize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onRoomStateEvents = (ev, state) => {
 | 
			
		||||
@@ -399,96 +369,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private shouldShowStickerPicker = (): boolean => {
 | 
			
		||||
        return SettingsStore.getValue(UIFeature.Widgets)
 | 
			
		||||
        && SettingsStore.getValue("MessageComposerInput.showStickersButton")
 | 
			
		||||
        && !this.state.haveRecording;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private showStickers = (showStickers: boolean) => {
 | 
			
		||||
        this.setState({ showStickers });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private toggleButtonMenu = (): void => {
 | 
			
		||||
        this.setState({
 | 
			
		||||
            isMenuOpen: !this.state.isMenuOpen,
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private renderButtons(menuPosition): JSX.Element | JSX.Element[] {
 | 
			
		||||
        const buttons = new Map<string, JSX.Element>();
 | 
			
		||||
        if (!this.state.haveRecording) {
 | 
			
		||||
            buttons.set(
 | 
			
		||||
                _t("Send File"),
 | 
			
		||||
                <UploadButton key="controls_upload" roomId={this.props.room.roomId} />,
 | 
			
		||||
            );
 | 
			
		||||
            buttons.set(
 | 
			
		||||
                _t("Show Emojis"),
 | 
			
		||||
                <EmojiButton key="emoji_button" addEmoji={this.addEmoji} menuPosition={menuPosition} />,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        if (this.shouldShowStickerPicker()) {
 | 
			
		||||
            buttons.set(
 | 
			
		||||
                _t("Show Stickers"),
 | 
			
		||||
                <AccessibleTooltipButton
 | 
			
		||||
                    id='stickersButton'
 | 
			
		||||
                    key="controls_stickers"
 | 
			
		||||
                    className="mx_MessageComposer_button mx_MessageComposer_stickers"
 | 
			
		||||
                    onClick={() => this.showStickers(!this.state.showStickers)}
 | 
			
		||||
                    title={this.state.showStickers ? _t("Hide Stickers") : _t("Show Stickers")}
 | 
			
		||||
                />,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        if (!this.state.haveRecording && !this.state.narrowMode) {
 | 
			
		||||
            buttons.set(
 | 
			
		||||
                _t("Send voice message"),
 | 
			
		||||
                <AccessibleTooltipButton
 | 
			
		||||
                    className="mx_MessageComposer_button mx_MessageComposer_voiceMessage"
 | 
			
		||||
                    onClick={() => this.voiceRecordingButton?.onRecordStartEndClick()}
 | 
			
		||||
                    title={_t("Send voice message")}
 | 
			
		||||
                />,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.state.narrowMode) {
 | 
			
		||||
            return Array.from(buttons.values());
 | 
			
		||||
        } else {
 | 
			
		||||
            const classnames = classNames({
 | 
			
		||||
                mx_MessageComposer_button: true,
 | 
			
		||||
                mx_MessageComposer_buttonMenu: true,
 | 
			
		||||
                mx_MessageComposer_closeButtonMenu: this.state.isMenuOpen,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return <>
 | 
			
		||||
                { buttons[0] }
 | 
			
		||||
                <AccessibleTooltipButton
 | 
			
		||||
                    className={classnames}
 | 
			
		||||
                    onClick={this.toggleButtonMenu}
 | 
			
		||||
                    title={_t("Composer menu")}
 | 
			
		||||
                    tooltip={false}
 | 
			
		||||
                />
 | 
			
		||||
                { this.state.isMenuOpen && (
 | 
			
		||||
                    <ContextMenu
 | 
			
		||||
                        onFinished={this.toggleButtonMenu}
 | 
			
		||||
                        {...menuPosition}
 | 
			
		||||
                        menuPaddingRight={10}
 | 
			
		||||
                        menuPaddingTop={5}
 | 
			
		||||
                        menuPaddingBottom={5}
 | 
			
		||||
                        menuWidth={150}
 | 
			
		||||
                        wrapperClassName="mx_MessageComposer_Menu"
 | 
			
		||||
                    >
 | 
			
		||||
                        { Array.from(buttons).slice(1).map(([label, button]) => (
 | 
			
		||||
                            <MenuItem className="mx_CallContextMenu_item" key={label} onClick={this.toggleButtonMenu}>
 | 
			
		||||
                                { button }
 | 
			
		||||
                                { label }
 | 
			
		||||
                            </MenuItem>
 | 
			
		||||
                        )) }
 | 
			
		||||
                    </ContextMenu>
 | 
			
		||||
                ) }
 | 
			
		||||
            </>;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const controls = [
 | 
			
		||||
            this.state.me && !this.props.compact ? <ComposerAvatar key="controls_avatar" me={this.state.me} /> : null,
 | 
			
		||||
@@ -497,12 +377,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
                null,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        let menuPosition;
 | 
			
		||||
        if (this.ref.current) {
 | 
			
		||||
            const contentRect = this.ref.current.getBoundingClientRect();
 | 
			
		||||
            menuPosition = aboveLeftOf(contentRect);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.state.tombstone && this.state.canSendMessages) {
 | 
			
		||||
            controls.push(
 | 
			
		||||
                <SendMessageComposer
 | 
			
		||||
@@ -518,10 +392,33 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
                />,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            if (!this.state.haveRecording) {
 | 
			
		||||
                controls.push(
 | 
			
		||||
                    <UploadButton key="controls_upload" roomId={this.props.room.roomId} />,
 | 
			
		||||
                    <EmojiButton key="emoji_button" addEmoji={this.addEmoji} />,
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (SettingsStore.getValue(UIFeature.Widgets) &&
 | 
			
		||||
                SettingsStore.getValue("MessageComposerInput.showStickersButton") &&
 | 
			
		||||
                !this.state.haveRecording) {
 | 
			
		||||
                controls.push(<Stickerpicker key="stickerpicker_controls_button" room={this.props.room} />);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            controls.push(<VoiceRecordComposerTile
 | 
			
		||||
                key="controls_voice_record"
 | 
			
		||||
                ref={c => this.voiceRecordingButton = c}
 | 
			
		||||
                room={this.props.room} />);
 | 
			
		||||
 | 
			
		||||
            if (!this.state.isComposerEmpty || this.state.haveRecording) {
 | 
			
		||||
                controls.push(
 | 
			
		||||
                    <SendButton
 | 
			
		||||
                        key="controls_send"
 | 
			
		||||
                        onClick={this.sendMessage}
 | 
			
		||||
                        title={this.state.haveRecording ? _t("Send voice message") : undefined}
 | 
			
		||||
                    />,
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        } else if (this.state.tombstone) {
 | 
			
		||||
            const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
 | 
			
		||||
 | 
			
		||||
@@ -562,15 +459,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
                yOffset={-50}
 | 
			
		||||
            />;
 | 
			
		||||
        }
 | 
			
		||||
        controls.push(
 | 
			
		||||
            <Stickerpicker
 | 
			
		||||
                room={this.props.room}
 | 
			
		||||
                showStickers={this.state.showStickers}
 | 
			
		||||
                setShowStickers={this.showStickers}
 | 
			
		||||
                menuPosition={menuPosition} />,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const showSendButton = !this.state.isComposerEmpty || this.state.haveRecording;
 | 
			
		||||
 | 
			
		||||
        const classes = classNames({
 | 
			
		||||
            "mx_MessageComposer": true,
 | 
			
		||||
@@ -579,7 +467,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <div className={classes} ref={this.ref}>
 | 
			
		||||
            <div className={classes}>
 | 
			
		||||
                { recordingTooltip }
 | 
			
		||||
                <div className="mx_MessageComposer_wrapper">
 | 
			
		||||
                    { this.props.showReplyPreview && (
 | 
			
		||||
@@ -587,14 +475,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
                    ) }
 | 
			
		||||
                    <div className="mx_MessageComposer_row">
 | 
			
		||||
                        { controls }
 | 
			
		||||
                        { this.renderButtons(menuPosition) }
 | 
			
		||||
                        { showSendButton && (
 | 
			
		||||
                            <SendButton
 | 
			
		||||
                                key="controls_send"
 | 
			
		||||
                                onClick={this.sendMessage}
 | 
			
		||||
                                title={this.state.haveRecording ? _t("Send voice message") : undefined}
 | 
			
		||||
                            />
 | 
			
		||||
                        ) }
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { Room } from 'matrix-js-sdk/src/models/room';
 | 
			
		||||
import { _t, _td } from '../../../languageHandler';
 | 
			
		||||
import AppTile from '../elements/AppTile';
 | 
			
		||||
@@ -26,6 +27,7 @@ import { IntegrationManagers } from "../../../integrations/IntegrationManagers";
 | 
			
		||||
import SettingsStore from "../../../settings/SettingsStore";
 | 
			
		||||
import { ChevronFace, ContextMenu } from "../../structures/ContextMenu";
 | 
			
		||||
import { WidgetType } from "../../../widgets/WidgetType";
 | 
			
		||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
 | 
			
		||||
import { Action } from "../../../dispatcher/actions";
 | 
			
		||||
import { WidgetMessagingStore } from "../../../stores/widgets/WidgetMessagingStore";
 | 
			
		||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
 | 
			
		||||
@@ -42,12 +44,10 @@ const PERSISTED_ELEMENT_KEY = "stickerPicker";
 | 
			
		||||
 | 
			
		||||
interface IProps {
 | 
			
		||||
    room: Room;
 | 
			
		||||
    showStickers: boolean;
 | 
			
		||||
    menuPosition?: any;
 | 
			
		||||
    setShowStickers: (showStickers: boolean) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IState {
 | 
			
		||||
    showStickers: boolean;
 | 
			
		||||
    imError: string;
 | 
			
		||||
    stickerpickerX: number;
 | 
			
		||||
    stickerpickerY: number;
 | 
			
		||||
@@ -72,6 +72,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
    constructor(props: IProps) {
 | 
			
		||||
        super(props);
 | 
			
		||||
        this.state = {
 | 
			
		||||
            showStickers: false,
 | 
			
		||||
            imError: null,
 | 
			
		||||
            stickerpickerX: null,
 | 
			
		||||
            stickerpickerY: null,
 | 
			
		||||
@@ -113,7 +114,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
            console.warn('No widget ID specified, not disabling assets');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.props.setShowStickers(false);
 | 
			
		||||
        this.setState({ showStickers: false });
 | 
			
		||||
        WidgetUtils.removeStickerpickerWidgets().then(() => {
 | 
			
		||||
            this.forceUpdate();
 | 
			
		||||
        }).catch((e) => {
 | 
			
		||||
@@ -145,15 +146,15 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public componentDidUpdate(prevProps: IProps, prevState: IState): void {
 | 
			
		||||
        this.sendVisibilityToWidget(this.props.showStickers);
 | 
			
		||||
        this.sendVisibilityToWidget(this.state.showStickers);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private imError(errorMsg: string, e: Error): void {
 | 
			
		||||
        console.error(errorMsg, e);
 | 
			
		||||
        this.setState({
 | 
			
		||||
            showStickers: false,
 | 
			
		||||
            imError: _t(errorMsg),
 | 
			
		||||
        });
 | 
			
		||||
        this.props.setShowStickers(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private updateWidget = (): void => {
 | 
			
		||||
@@ -193,12 +194,12 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
                this.forceUpdate();
 | 
			
		||||
                break;
 | 
			
		||||
            case "stickerpicker_close":
 | 
			
		||||
                this.props.setShowStickers(false);
 | 
			
		||||
                this.setState({ showStickers: false });
 | 
			
		||||
                break;
 | 
			
		||||
            case Action.AfterRightPanelPhaseChange:
 | 
			
		||||
            case "show_left_panel":
 | 
			
		||||
            case "hide_left_panel":
 | 
			
		||||
                this.props.setShowStickers(false);
 | 
			
		||||
                this.setState({ showStickers: false });
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
@@ -337,8 +338,8 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
 | 
			
		||||
        const y = (buttonRect.top + (buttonRect.height / 2) + window.pageYOffset) - 19;
 | 
			
		||||
 | 
			
		||||
        this.props.setShowStickers(true);
 | 
			
		||||
        this.setState({
 | 
			
		||||
            showStickers: true,
 | 
			
		||||
            stickerpickerX: x,
 | 
			
		||||
            stickerpickerY: y,
 | 
			
		||||
            stickerpickerChevronOffset,
 | 
			
		||||
@@ -350,8 +351,8 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
     * @param  {Event} ev Event that triggered the function call
 | 
			
		||||
     */
 | 
			
		||||
    private onHideStickersClick = (ev: React.MouseEvent): void => {
 | 
			
		||||
        if (this.props.showStickers) {
 | 
			
		||||
            this.props.setShowStickers(false);
 | 
			
		||||
        if (this.state.showStickers) {
 | 
			
		||||
            this.setState({ showStickers: false });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -359,8 +360,8 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
     * Called when the window is resized
 | 
			
		||||
     */
 | 
			
		||||
    private onResize = (): void => {
 | 
			
		||||
        if (this.props.showStickers) {
 | 
			
		||||
            this.props.setShowStickers(false);
 | 
			
		||||
        if (this.state.showStickers) {
 | 
			
		||||
            this.setState({ showStickers: false });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -368,8 +369,8 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
     * The stickers picker was hidden
 | 
			
		||||
     */
 | 
			
		||||
    private onFinished = (): void => {
 | 
			
		||||
        if (this.props.showStickers) {
 | 
			
		||||
            this.props.setShowStickers(false);
 | 
			
		||||
        if (this.state.showStickers) {
 | 
			
		||||
            this.setState({ showStickers: false });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -394,23 +395,54 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    public render(): JSX.Element {
 | 
			
		||||
        if (!this.props.showStickers) return null;
 | 
			
		||||
        let stickerPicker;
 | 
			
		||||
        let stickersButton;
 | 
			
		||||
        const className = classNames(
 | 
			
		||||
            "mx_MessageComposer_button",
 | 
			
		||||
            "mx_MessageComposer_stickers",
 | 
			
		||||
            "mx_Stickers_hideStickers",
 | 
			
		||||
            "mx_MessageComposer_button_highlight",
 | 
			
		||||
        );
 | 
			
		||||
        if (this.state.showStickers) {
 | 
			
		||||
            // Show hide-stickers button
 | 
			
		||||
            stickersButton =
 | 
			
		||||
                <AccessibleButton
 | 
			
		||||
                    id='stickersButton'
 | 
			
		||||
                    key="controls_hide_stickers"
 | 
			
		||||
                    className={className}
 | 
			
		||||
                    onClick={this.onHideStickersClick}
 | 
			
		||||
                    title={_t("Hide Stickers")}
 | 
			
		||||
                />;
 | 
			
		||||
 | 
			
		||||
        return <ContextMenu
 | 
			
		||||
            chevronOffset={this.state.stickerpickerChevronOffset}
 | 
			
		||||
            chevronFace={ChevronFace.Bottom}
 | 
			
		||||
            left={this.state.stickerpickerX}
 | 
			
		||||
            top={this.state.stickerpickerY}
 | 
			
		||||
            menuWidth={this.popoverWidth}
 | 
			
		||||
            menuHeight={this.popoverHeight}
 | 
			
		||||
            onFinished={this.onFinished}
 | 
			
		||||
            menuPaddingTop={0}
 | 
			
		||||
            menuPaddingLeft={0}
 | 
			
		||||
            menuPaddingRight={0}
 | 
			
		||||
            zIndex={STICKERPICKER_Z_INDEX}
 | 
			
		||||
            {...this.props.menuPosition}
 | 
			
		||||
        >
 | 
			
		||||
            <GenericElementContextMenu element={this.getStickerpickerContent()} onResize={this.onFinished} />
 | 
			
		||||
        </ContextMenu>;
 | 
			
		||||
            stickerPicker = <ContextMenu
 | 
			
		||||
                chevronOffset={this.state.stickerpickerChevronOffset}
 | 
			
		||||
                chevronFace={ChevronFace.Bottom}
 | 
			
		||||
                left={this.state.stickerpickerX}
 | 
			
		||||
                top={this.state.stickerpickerY}
 | 
			
		||||
                menuWidth={this.popoverWidth}
 | 
			
		||||
                menuHeight={this.popoverHeight}
 | 
			
		||||
                onFinished={this.onFinished}
 | 
			
		||||
                menuPaddingTop={0}
 | 
			
		||||
                menuPaddingLeft={0}
 | 
			
		||||
                menuPaddingRight={0}
 | 
			
		||||
                zIndex={STICKERPICKER_Z_INDEX}
 | 
			
		||||
            >
 | 
			
		||||
                <GenericElementContextMenu element={this.getStickerpickerContent()} onResize={this.onFinished} />
 | 
			
		||||
            </ContextMenu>;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Show show-stickers button
 | 
			
		||||
            stickersButton =
 | 
			
		||||
                <AccessibleTooltipButton
 | 
			
		||||
                    id='stickersButton'
 | 
			
		||||
                    key="controls_show_stickers"
 | 
			
		||||
                    className="mx_MessageComposer_button mx_MessageComposer_stickers"
 | 
			
		||||
                    onClick={this.onShowStickersClick}
 | 
			
		||||
                    title={_t("Show Stickers")}
 | 
			
		||||
                />;
 | 
			
		||||
        }
 | 
			
		||||
        return <React.Fragment>
 | 
			
		||||
            { stickersButton }
 | 
			
		||||
            { stickerPicker }
 | 
			
		||||
        </React.Fragment>;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import React, { ReactNode } from "react";
 | 
			
		||||
import { IUpload, RecordingState, VoiceRecording } from "../../../audio/VoiceRecording";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
import LiveRecordingWaveform from "../audio_messages/LiveRecordingWaveform";
 | 
			
		||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
 | 
			
		||||
import LiveRecordingClock from "../audio_messages/LiveRecordingClock";
 | 
			
		||||
@@ -136,7 +137,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
 | 
			
		||||
        await this.disposeRecording();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    public onRecordStartEndClick = async () => {
 | 
			
		||||
    private onRecordStartEndClick = async () => {
 | 
			
		||||
        if (this.state.recorder) {
 | 
			
		||||
            await this.state.recorder.stop();
 | 
			
		||||
            return;
 | 
			
		||||
@@ -214,23 +215,27 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public render(): ReactNode {
 | 
			
		||||
        if (!this.state.recordingPhase) return null;
 | 
			
		||||
 | 
			
		||||
        let stopBtn;
 | 
			
		||||
        let stopOrRecordBtn;
 | 
			
		||||
        let deleteButton;
 | 
			
		||||
        if (this.state.recordingPhase === RecordingState.Started) {
 | 
			
		||||
        if (!this.state.recordingPhase || this.state.recordingPhase === RecordingState.Started) {
 | 
			
		||||
            const classes = classNames({
 | 
			
		||||
                'mx_MessageComposer_button': !this.state.recorder,
 | 
			
		||||
                'mx_MessageComposer_voiceMessage': !this.state.recorder,
 | 
			
		||||
                'mx_VoiceRecordComposerTile_stop': this.state.recorder?.isRecording,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            let tooltip = _t("Send voice message");
 | 
			
		||||
            if (!!this.state.recorder) {
 | 
			
		||||
                tooltip = _t("Stop recording");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            stopBtn = <AccessibleTooltipButton
 | 
			
		||||
                className="mx_VoiceRecordComposerTile_stop"
 | 
			
		||||
            stopOrRecordBtn = <AccessibleTooltipButton
 | 
			
		||||
                className={classes}
 | 
			
		||||
                onClick={this.onRecordStartEndClick}
 | 
			
		||||
                title={tooltip}
 | 
			
		||||
            />;
 | 
			
		||||
            if (this.state.recorder && !this.state.recorder?.isRecording) {
 | 
			
		||||
                stopBtn = null;
 | 
			
		||||
                stopOrRecordBtn = null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -259,10 +264,13 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
 | 
			
		||||
            </span>;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // The record button (mic icon) is meant to be on the right edge, but we also want the
 | 
			
		||||
        // stop button to be left of the waveform area. Luckily, none of the surrounding UI is
 | 
			
		||||
        // rendered when we're not recording, so the record button ends up in the correct spot.
 | 
			
		||||
        return (<>
 | 
			
		||||
            { uploadIndicator }
 | 
			
		||||
            { deleteButton }
 | 
			
		||||
            { stopBtn }
 | 
			
		||||
            { stopOrRecordBtn }
 | 
			
		||||
            { this.renderWaveformArea() }
 | 
			
		||||
        </>);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1564,12 +1564,7 @@
 | 
			
		||||
    "Send a reply…": "Send a reply…",
 | 
			
		||||
    "Send an encrypted message…": "Send an encrypted message…",
 | 
			
		||||
    "Send a message…": "Send a message…",
 | 
			
		||||
    "Send File": "Send File",
 | 
			
		||||
    "Show Emojis": "Show Emojis",
 | 
			
		||||
    "Show Stickers": "Show Stickers",
 | 
			
		||||
    "Hide Stickers": "Hide Stickers",
 | 
			
		||||
    "Send voice message": "Send voice message",
 | 
			
		||||
    "Composer menu": "Composer menu",
 | 
			
		||||
    "The conversation continues here.": "The conversation continues here.",
 | 
			
		||||
    "This room has been replaced and is no longer active.": "This room has been replaced and is no longer active.",
 | 
			
		||||
    "You do not have permission to post to this room": "You do not have permission to post to this room",
 | 
			
		||||
@@ -1730,6 +1725,8 @@
 | 
			
		||||
    "You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled",
 | 
			
		||||
    "Add some now": "Add some now",
 | 
			
		||||
    "Stickerpack": "Stickerpack",
 | 
			
		||||
    "Hide Stickers": "Hide Stickers",
 | 
			
		||||
    "Show Stickers": "Show Stickers",
 | 
			
		||||
    "Failed to revoke invite": "Failed to revoke invite",
 | 
			
		||||
    "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.",
 | 
			
		||||
    "Admin Tools": "Admin Tools",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user