Merge branch 'develop' into gsouquet/compact-composer-18533
This commit is contained in:
commit
6d80976eae
43 changed files with 683 additions and 391 deletions
|
@ -43,11 +43,6 @@ import QuestionDialog from "../dialogs/QuestionDialog";
|
|||
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
|
||||
function eventIsReply(mxEvent: MatrixEvent): boolean {
|
||||
const relatesTo = mxEvent.getContent()["m.relates_to"];
|
||||
return !!(relatesTo && relatesTo["m.in_reply_to"]);
|
||||
}
|
||||
|
||||
function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
|
||||
const html = mxEvent.getContent().formatted_body;
|
||||
if (!html) {
|
||||
|
@ -72,7 +67,7 @@ function createEditContent(model: EditorModel, editedEvent: MatrixEvent): IConte
|
|||
if (isEmote) {
|
||||
model = stripEmoteCommand(model);
|
||||
}
|
||||
const isReply = eventIsReply(editedEvent);
|
||||
const isReply = !!editedEvent.replyEventId;
|
||||
let plainPrefix = "";
|
||||
let htmlPrefix = "";
|
||||
|
||||
|
|
|
@ -243,6 +243,7 @@ interface IProps {
|
|||
// opaque readreceipt info for each userId; used by ReadReceiptMarker
|
||||
// to manage its animations. Should be an empty object when the room
|
||||
// first loads
|
||||
// TODO: Proper typing for RR info
|
||||
readReceiptMap?: any;
|
||||
|
||||
// A function which is used to check if the parent panel is being
|
||||
|
|
|
@ -14,11 +14,18 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { _t } from '../../../languageHandler';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default (props) => {
|
||||
interface IProps {
|
||||
numUnreadMessages: number;
|
||||
highlight: boolean;
|
||||
onScrollToBottomClick: (e: React.MouseEvent) => void;
|
||||
}
|
||||
|
||||
const JumpToBottomButton: React.FC<IProps> = (props) => {
|
||||
const className = classNames({
|
||||
'mx_JumpToBottomButton': true,
|
||||
'mx_JumpToBottomButton_highlight': props.highlight,
|
||||
|
@ -36,3 +43,5 @@ export default (props) => {
|
|||
{ badge }
|
||||
</div>);
|
||||
};
|
||||
|
||||
export default JumpToBottomButton;
|
|
@ -192,6 +192,7 @@ interface IProps {
|
|||
resizeNotifier: ResizeNotifier;
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
replyToEvent?: MatrixEvent;
|
||||
replyInThread?: boolean;
|
||||
showReplyPreview?: boolean;
|
||||
e2eStatus?: E2EStatus;
|
||||
compact?: boolean;
|
||||
|
@ -217,6 +218,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
private ref: React.RefObject<HTMLDivElement> = createRef();
|
||||
|
||||
static defaultProps = {
|
||||
replyInThread: false,
|
||||
showReplyPreview: true,
|
||||
compact: false,
|
||||
};
|
||||
|
@ -498,6 +500,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
room={this.props.room}
|
||||
placeholder={this.renderPlaceholderText()}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
replyInThread={this.props.replyInThread}
|
||||
replyToEvent={this.props.replyToEvent}
|
||||
onChange={this.onChange}
|
||||
disabled={this.state.haveRecording}
|
||||
|
|
|
@ -15,62 +15,75 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { createRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { createRef, RefObject } from 'react';
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { formatDate } from '../../../DateUtils';
|
||||
import NodeAnimator from "../../../NodeAnimator";
|
||||
import * as sdk from "../../../index";
|
||||
import { toPx } from "../../../utils/units";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
|
||||
import MemberAvatar from '../avatars/MemberAvatar';
|
||||
|
||||
interface IProps {
|
||||
// the RoomMember to show the RR for
|
||||
member?: RoomMember;
|
||||
// userId to fallback the avatar to
|
||||
// if the member hasn't been loaded yet
|
||||
fallbackUserId: string;
|
||||
|
||||
// number of pixels to offset the avatar from the right of its parent;
|
||||
// typically a negative value.
|
||||
leftOffset?: number;
|
||||
|
||||
// true to hide the avatar (it will still be animated)
|
||||
hidden?: boolean;
|
||||
|
||||
// don't animate this RR into position
|
||||
suppressAnimation?: boolean;
|
||||
|
||||
// an opaque object for storing information about this user's RR in
|
||||
// this room
|
||||
// TODO: proper typing for RR info
|
||||
readReceiptInfo: any;
|
||||
|
||||
// A function which is used to check if the parent panel is being
|
||||
// unmounted, to avoid unnecessary work. Should return true if we
|
||||
// are being unmounted.
|
||||
checkUnmounting?: () => boolean;
|
||||
|
||||
// callback for clicks on this RR
|
||||
onClick?: (e: React.MouseEvent) => void;
|
||||
|
||||
// Timestamp when the receipt was read
|
||||
timestamp?: number;
|
||||
|
||||
// True to show twelve hour format, false otherwise
|
||||
showTwelveHour?: boolean;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
suppressDisplay: boolean;
|
||||
startStyles?: IReadReceiptMarkerStyle[];
|
||||
}
|
||||
|
||||
interface IReadReceiptMarkerStyle {
|
||||
top: number;
|
||||
left: number;
|
||||
}
|
||||
|
||||
@replaceableComponent("views.rooms.ReadReceiptMarker")
|
||||
export default class ReadReceiptMarker extends React.PureComponent {
|
||||
static propTypes = {
|
||||
// the RoomMember to show the RR for
|
||||
member: PropTypes.object,
|
||||
// userId to fallback the avatar to
|
||||
// if the member hasn't been loaded yet
|
||||
fallbackUserId: PropTypes.string.isRequired,
|
||||
|
||||
// number of pixels to offset the avatar from the right of its parent;
|
||||
// typically a negative value.
|
||||
leftOffset: PropTypes.number,
|
||||
|
||||
// true to hide the avatar (it will still be animated)
|
||||
hidden: PropTypes.bool,
|
||||
|
||||
// don't animate this RR into position
|
||||
suppressAnimation: PropTypes.bool,
|
||||
|
||||
// an opaque object for storing information about this user's RR in
|
||||
// this room
|
||||
readReceiptInfo: PropTypes.object,
|
||||
|
||||
// A function which is used to check if the parent panel is being
|
||||
// unmounted, to avoid unnecessary work. Should return true if we
|
||||
// are being unmounted.
|
||||
checkUnmounting: PropTypes.func,
|
||||
|
||||
// callback for clicks on this RR
|
||||
onClick: PropTypes.func,
|
||||
|
||||
// Timestamp when the receipt was read
|
||||
timestamp: PropTypes.number,
|
||||
|
||||
// True to show twelve hour format, false otherwise
|
||||
showTwelveHour: PropTypes.bool,
|
||||
};
|
||||
export default class ReadReceiptMarker extends React.PureComponent<IProps, IState> {
|
||||
private avatar: React.RefObject<HTMLDivElement | HTMLImageElement | HTMLSpanElement> = createRef();
|
||||
|
||||
static defaultProps = {
|
||||
leftOffset: 0,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this._avatar = createRef();
|
||||
|
||||
this.state = {
|
||||
// if we are going to animate the RR, we don't show it on first render,
|
||||
// and instead just add a placeholder to the DOM; once we've been
|
||||
|
@ -80,7 +93,7 @@ export default class ReadReceiptMarker extends React.PureComponent {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
// before we remove the rr, store its location in the map, so that if
|
||||
// it reappears, it can be animated from the right place.
|
||||
const rrInfo = this.props.readReceiptInfo;
|
||||
|
@ -95,29 +108,29 @@ export default class ReadReceiptMarker extends React.PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
const avatarNode = this._avatar.current;
|
||||
const avatarNode = this.avatar.current;
|
||||
rrInfo.top = avatarNode.offsetTop;
|
||||
rrInfo.left = avatarNode.offsetLeft;
|
||||
rrInfo.parent = avatarNode.offsetParent;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
if (!this.state.suppressDisplay) {
|
||||
// we've already done our display - nothing more to do.
|
||||
return;
|
||||
}
|
||||
this._animateMarker();
|
||||
this.animateMarker();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
public componentDidUpdate(prevProps: IProps): void {
|
||||
const differentLeftOffset = prevProps.leftOffset !== this.props.leftOffset;
|
||||
const visibilityChanged = prevProps.hidden !== this.props.hidden;
|
||||
if (differentLeftOffset || visibilityChanged) {
|
||||
this._animateMarker();
|
||||
this.animateMarker();
|
||||
}
|
||||
}
|
||||
|
||||
_animateMarker() {
|
||||
private animateMarker(): void {
|
||||
// treat new RRs as though they were off the top of the screen
|
||||
let oldTop = -15;
|
||||
|
||||
|
@ -126,7 +139,7 @@ export default class ReadReceiptMarker extends React.PureComponent {
|
|||
oldTop = oldInfo.top + oldInfo.parent.getBoundingClientRect().top;
|
||||
}
|
||||
|
||||
const newElement = this._avatar.current;
|
||||
const newElement = this.avatar.current;
|
||||
let startTopOffset;
|
||||
if (!newElement.offsetParent) {
|
||||
// this seems to happen sometimes for reasons I don't understand
|
||||
|
@ -156,10 +169,9 @@ export default class ReadReceiptMarker extends React.PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||
public render(): JSX.Element {
|
||||
if (this.state.suppressDisplay) {
|
||||
return <div ref={this._avatar} />;
|
||||
return <div ref={this.avatar as RefObject<HTMLDivElement>} />;
|
||||
}
|
||||
|
||||
const style = {
|
||||
|
@ -198,7 +210,7 @@ export default class ReadReceiptMarker extends React.PureComponent {
|
|||
style={style}
|
||||
title={title}
|
||||
onClick={this.props.onClick}
|
||||
inputRef={this._avatar}
|
||||
inputRef={this.avatar as RefObject<HTMLImageElement>}
|
||||
/>
|
||||
</NodeAnimator>
|
||||
);
|
|
@ -14,41 +14,38 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as sdk from '../../../index';
|
||||
import dis from '../../../dispatcher/dispatcher';
|
||||
import React from 'react';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Room } from 'matrix-js-sdk/src';
|
||||
import classNames from 'classnames';
|
||||
import dis from '../../../dispatcher/dispatcher';
|
||||
import { _t } from '../../../languageHandler';
|
||||
|
||||
import { roomShape } from './RoomDetailRow';
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import RoomDetailRow from "./RoomDetailRow";
|
||||
|
||||
interface IProps {
|
||||
rooms?: Room[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@replaceableComponent("views.rooms.RoomDetailList")
|
||||
export default class RoomDetailList extends React.Component {
|
||||
static propTypes = {
|
||||
rooms: PropTypes.arrayOf(roomShape),
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
getRows() {
|
||||
export default class RoomDetailList extends React.Component<IProps> {
|
||||
private getRows(): JSX.Element[] {
|
||||
if (!this.props.rooms) return [];
|
||||
|
||||
const RoomDetailRow = sdk.getComponent('rooms.RoomDetailRow');
|
||||
return this.props.rooms.map((room, index) => {
|
||||
return <RoomDetailRow key={index} room={room} onClick={this.onDetailsClick} />;
|
||||
});
|
||||
}
|
||||
|
||||
onDetailsClick = (ev, room) => {
|
||||
private onDetailsClick = (ev: React.MouseEvent, room: Room): void => {
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: room.roomId,
|
||||
room_alias: room.canonicalAlias || (room.aliases || [])[0],
|
||||
room_alias: room.getCanonicalAlias() || (room.getAltAliases() || [])[0],
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
public render(): JSX.Element {
|
||||
const rows = this.getRows();
|
||||
let rooms;
|
||||
if (rows.length === 0) {
|
|
@ -195,7 +195,7 @@ export default class RoomHeader extends React.Component<IProps> {
|
|||
videoCallButton =
|
||||
<AccessibleTooltipButton
|
||||
className="mx_RoomHeader_button mx_RoomHeader_videoCallButton"
|
||||
onClick={(ev) => ev.shiftKey ?
|
||||
onClick={(ev: React.MouseEvent<Element>) => ev.shiftKey ?
|
||||
this.displayInfoDialogAboutScreensharing() : this.props.onCallPlaced(PlaceCallType.Video)}
|
||||
title={_t("Video call")} />;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2018-2020 New Vector Ltd
|
||||
Copyright 2018-2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -15,41 +15,43 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as sdk from '../../../index';
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import { RoomState } from 'matrix-js-sdk/src/models/room-state';
|
||||
|
||||
import Modal from '../../../Modal';
|
||||
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import RoomUpgradeDialog from '../dialogs/RoomUpgradeDialog';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
upgraded?: boolean;
|
||||
}
|
||||
|
||||
@replaceableComponent("views.rooms.RoomUpgradeWarningBar")
|
||||
export default class RoomUpgradeWarningBar extends React.PureComponent {
|
||||
static propTypes = {
|
||||
room: PropTypes.object.isRequired,
|
||||
recommendation: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, IState> {
|
||||
public componentDidMount(): void {
|
||||
const tombstone = this.props.room.currentState.getStateEvents("m.room.tombstone", "");
|
||||
this.setState({ upgraded: tombstone && tombstone.getContent().replacement_room });
|
||||
|
||||
MatrixClientPeg.get().on("RoomState.events", this._onStateEvents);
|
||||
MatrixClientPeg.get().on("RoomState.events", this.onStateEvents);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
const cli = MatrixClientPeg.get();
|
||||
if (cli) {
|
||||
cli.removeListener("RoomState.events", this._onStateEvents);
|
||||
cli.removeListener("RoomState.events", this.onStateEvents);
|
||||
}
|
||||
}
|
||||
|
||||
_onStateEvents = (event, state) => {
|
||||
private onStateEvents = (event: MatrixEvent, state: RoomState): void => {
|
||||
if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
|
||||
return;
|
||||
}
|
||||
|
@ -60,14 +62,11 @@ export default class RoomUpgradeWarningBar extends React.PureComponent {
|
|||
this.setState({ upgraded: tombstone && tombstone.getContent().replacement_room });
|
||||
};
|
||||
|
||||
onUpgradeClick = () => {
|
||||
const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
|
||||
private onUpgradeClick = (): void => {
|
||||
Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, { room: this.props.room });
|
||||
};
|
||||
|
||||
render() {
|
||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||
|
||||
public render(): JSX.Element {
|
||||
let doUpgradeWarnings = (
|
||||
<div>
|
||||
<div className="mx_RoomUpgradeWarningBar_body">
|
|
@ -57,15 +57,16 @@ import { ActionPayload } from "../../../dispatcher/payloads";
|
|||
|
||||
function addReplyToMessageContent(
|
||||
content: IContent,
|
||||
repliedToEvent: MatrixEvent,
|
||||
replyToEvent: MatrixEvent,
|
||||
replyInThread: boolean,
|
||||
permalinkCreator: RoomPermalinkCreator,
|
||||
): void {
|
||||
const replyContent = ReplyThread.makeReplyMixIn(repliedToEvent);
|
||||
const replyContent = ReplyThread.makeReplyMixIn(replyToEvent, replyInThread);
|
||||
Object.assign(content, replyContent);
|
||||
|
||||
// Part of Replies fallback support - prepend the text we're sending
|
||||
// with the text we're replying to
|
||||
const nestedReply = ReplyThread.getNestedReplyText(repliedToEvent, permalinkCreator);
|
||||
const nestedReply = ReplyThread.getNestedReplyText(replyToEvent, permalinkCreator);
|
||||
if (nestedReply) {
|
||||
if (content.formatted_body) {
|
||||
content.formatted_body = nestedReply.html + content.formatted_body;
|
||||
|
@ -77,8 +78,9 @@ function addReplyToMessageContent(
|
|||
// exported for tests
|
||||
export function createMessageContent(
|
||||
model: EditorModel,
|
||||
permalinkCreator: RoomPermalinkCreator,
|
||||
replyToEvent: MatrixEvent,
|
||||
replyInThread: boolean,
|
||||
permalinkCreator: RoomPermalinkCreator,
|
||||
): IContent {
|
||||
const isEmote = containsEmote(model);
|
||||
if (isEmote) {
|
||||
|
@ -101,7 +103,7 @@ export function createMessageContent(
|
|||
}
|
||||
|
||||
if (replyToEvent) {
|
||||
addReplyToMessageContent(content, replyToEvent, permalinkCreator);
|
||||
addReplyToMessageContent(content, replyToEvent, replyInThread, permalinkCreator);
|
||||
}
|
||||
|
||||
return content;
|
||||
|
@ -129,6 +131,7 @@ interface IProps {
|
|||
room: Room;
|
||||
placeholder?: string;
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
replyInThread?: boolean;
|
||||
replyToEvent?: MatrixEvent;
|
||||
disabled?: boolean;
|
||||
onChange?(model: EditorModel): void;
|
||||
|
@ -357,7 +360,12 @@ export default class SendMessageComposer extends React.Component<IProps> {
|
|||
if (cmd.category === CommandCategories.messages) {
|
||||
content = await this.runSlashCommand(cmd, args);
|
||||
if (replyToEvent) {
|
||||
addReplyToMessageContent(content, replyToEvent, this.props.permalinkCreator);
|
||||
addReplyToMessageContent(
|
||||
content,
|
||||
replyToEvent,
|
||||
this.props.replyInThread,
|
||||
this.props.permalinkCreator,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.runSlashCommand(cmd, args);
|
||||
|
@ -400,7 +408,12 @@ export default class SendMessageComposer extends React.Component<IProps> {
|
|||
const startTime = CountlyAnalytics.getTimestamp();
|
||||
const { roomId } = this.props.room;
|
||||
if (!content) {
|
||||
content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent);
|
||||
content = createMessageContent(
|
||||
this.model,
|
||||
replyToEvent,
|
||||
this.props.replyInThread,
|
||||
this.props.permalinkCreator,
|
||||
);
|
||||
}
|
||||
// don't bother sending an empty message
|
||||
if (!content.body.trim()) return;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
Copyright 2016-2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -15,23 +15,21 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
|
||||
interface IProps {
|
||||
title?: string;
|
||||
// `src` to an image. Optional.
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
/*
|
||||
* A stripped-down room header used for things like the user settings
|
||||
* and room directory.
|
||||
*/
|
||||
@replaceableComponent("views.rooms.SimpleRoomHeader")
|
||||
export default class SimpleRoomHeader extends React.Component {
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
|
||||
// `src` to an image. Optional.
|
||||
icon: PropTypes.string,
|
||||
};
|
||||
|
||||
render() {
|
||||
export default class SimpleRoomHeader extends React.PureComponent<IProps> {
|
||||
public render(): JSX.Element {
|
||||
let icon;
|
||||
if (this.props.icon) {
|
||||
icon = <img
|
|
@ -1,7 +1,5 @@
|
|||
/*
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2019 New Vector Ltd
|
||||
Copyright 2016 - 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -17,19 +15,18 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
|
||||
@replaceableComponent("views.rooms.TopUnreadMessagesBar")
|
||||
export default class TopUnreadMessagesBar extends React.Component {
|
||||
static propTypes = {
|
||||
onScrollUpClick: PropTypes.func,
|
||||
onCloseClick: PropTypes.func,
|
||||
};
|
||||
interface IProps {
|
||||
onScrollUpClick?: (e: React.MouseEvent) => void;
|
||||
onCloseClick?: (e: React.MouseEvent) => void;
|
||||
}
|
||||
|
||||
render() {
|
||||
@replaceableComponent("views.rooms.TopUnreadMessagesBar")
|
||||
export default class TopUnreadMessagesBar extends React.PureComponent<IProps> {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className="mx_TopUnreadMessagesBar">
|
||||
<AccessibleButton
|
|
@ -179,7 +179,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
|
||||
try {
|
||||
// stop any noises which might be happening
|
||||
await PlaybackManager.instance.playOnly(null);
|
||||
await PlaybackManager.instance.pauseAllExcept(null);
|
||||
|
||||
const recorder = VoiceRecordingStore.instance.startRecording();
|
||||
await recorder.start();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue