Merge branch 'develop' into export-conversations

This commit is contained in:
Jaiwanth 2021-09-29 19:32:05 +05:30
commit 208b914cb0
62 changed files with 936 additions and 678 deletions

View file

@ -163,7 +163,7 @@ export default class AppTile extends React.Component<IProps, IState> {
if (this.state.hasPermissionToLoad && !hasPermissionToLoad) {
// Force the widget to be non-persistent (able to be deleted/forgotten)
ActiveWidgetStore.destroyPersistentWidget(this.props.app.id);
ActiveWidgetStore.instance.destroyPersistentWidget(this.props.app.id);
PersistedElement.destroyElement(this.persistKey);
if (this.sgWidget) this.sgWidget.stop();
}
@ -198,8 +198,8 @@ export default class AppTile extends React.Component<IProps, IState> {
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
// if it's not remaining on screen, get rid of the PersistedElement container
if (!ActiveWidgetStore.getWidgetPersistence(this.props.app.id)) {
ActiveWidgetStore.destroyPersistentWidget(this.props.app.id);
if (!ActiveWidgetStore.instance.getWidgetPersistence(this.props.app.id)) {
ActiveWidgetStore.instance.destroyPersistentWidget(this.props.app.id);
PersistedElement.destroyElement(this.persistKey);
}
@ -282,7 +282,7 @@ export default class AppTile extends React.Component<IProps, IState> {
// Delete the widget from the persisted store for good measure.
PersistedElement.destroyElement(this.persistKey);
ActiveWidgetStore.destroyPersistentWidget(this.props.app.id);
ActiveWidgetStore.instance.destroyPersistentWidget(this.props.app.id);
if (this.sgWidget) this.sgWidget.stop({ forceDestroy: true });
}

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import RoomViewStore from '../../../stores/RoomViewStore';
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
import ActiveWidgetStore, { ActiveWidgetStoreEvent } from '../../../stores/ActiveWidgetStore';
import WidgetUtils from '../../../utils/WidgetUtils';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { replaceableComponent } from "../../../utils/replaceableComponent";
@ -39,13 +39,13 @@ export default class PersistentApp extends React.Component<{}, IState> {
this.state = {
roomId: RoomViewStore.getRoomId(),
persistentWidgetId: ActiveWidgetStore.getPersistentWidgetId(),
persistentWidgetId: ActiveWidgetStore.instance.getPersistentWidgetId(),
};
}
public componentDidMount(): void {
this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
ActiveWidgetStore.on('update', this.onActiveWidgetStoreUpdate);
ActiveWidgetStore.instance.on(ActiveWidgetStoreEvent.Update, this.onActiveWidgetStoreUpdate);
MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership);
}
@ -53,7 +53,7 @@ export default class PersistentApp extends React.Component<{}, IState> {
if (this.roomStoreToken) {
this.roomStoreToken.remove();
}
ActiveWidgetStore.removeListener('update', this.onActiveWidgetStoreUpdate);
ActiveWidgetStore.instance.removeListener(ActiveWidgetStoreEvent.Update, this.onActiveWidgetStoreUpdate);
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("Room.myMembership", this.onMyMembership);
}
@ -68,23 +68,23 @@ export default class PersistentApp extends React.Component<{}, IState> {
private onActiveWidgetStoreUpdate = (): void => {
this.setState({
persistentWidgetId: ActiveWidgetStore.getPersistentWidgetId(),
persistentWidgetId: ActiveWidgetStore.instance.getPersistentWidgetId(),
});
};
private onMyMembership = async (room: Room, membership: string): Promise<void> => {
const persistentWidgetInRoomId = ActiveWidgetStore.getRoomId(this.state.persistentWidgetId);
const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(this.state.persistentWidgetId);
if (membership !== "join") {
// we're not in the room anymore - delete
if (room .roomId === persistentWidgetInRoomId) {
ActiveWidgetStore.destroyPersistentWidget(this.state.persistentWidgetId);
ActiveWidgetStore.instance.destroyPersistentWidget(this.state.persistentWidgetId);
}
}
};
public render(): JSX.Element {
if (this.state.persistentWidgetId) {
const persistentWidgetInRoomId = ActiveWidgetStore.getRoomId(this.state.persistentWidgetId);
const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(this.state.persistentWidgetId);
const persistentWidgetInRoom = MatrixClientPeg.get().getRoom(persistentWidgetInRoomId);
@ -96,7 +96,7 @@ export default class PersistentApp extends React.Component<{}, IState> {
if (this.state.roomId !== persistentWidgetInRoomId && myMembership === "join") {
// get the widget data
const appEvent = WidgetUtils.getRoomWidgets(persistentWidgetInRoom).find((ev) => {
return ev.getStateKey() === ActiveWidgetStore.getPersistentWidgetId();
return ev.getStateKey() === ActiveWidgetStore.instance.getPersistentWidgetId();
});
const app = WidgetUtils.makeAppConfig(
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(),

View file

@ -16,6 +16,8 @@ limitations under the License.
*/
import React from 'react';
import classNames from 'classnames';
import { _t } from '../../../languageHandler';
import dis from '../../../dispatcher/dispatcher';
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
@ -35,6 +37,12 @@ import ReplyTile from "../rooms/ReplyTile";
import Pill from './Pill';
import { Room } from 'matrix-js-sdk/src/models/room';
/**
* This number is based on the previous behavior - if we have message of height
* over 60px then we want to show button that will allow to expand it.
*/
const SHOW_EXPAND_QUOTE_PIXELS = 60;
interface IProps {
// the latest event in this chain of replies
parentEv?: MatrixEvent;
@ -46,6 +54,8 @@ interface IProps {
// Whether to always show a timestamp
alwaysShowTimestamps?: boolean;
forExport?: boolean;
isQuoteExpanded?: boolean;
setQuoteExpanded: (isExpanded: boolean) => void;
}
interface IState {
@ -67,6 +77,7 @@ export default class ReplyThread extends React.Component<IProps, IState> {
static contextType = MatrixClientContext;
private unmounted = false;
private room: Room;
private blockquoteRef = React.createRef<HTMLElement>();
constructor(props, context) {
super(props, context);
@ -81,7 +92,7 @@ export default class ReplyThread extends React.Component<IProps, IState> {
this.room = this.context.getRoom(this.props.parentEv.getRoomId());
}
public static getParentEventId(ev: MatrixEvent): string {
public static getParentEventId(ev: MatrixEvent): string | undefined {
if (!ev || ev.isRedacted()) return;
// XXX: For newer relations (annotations, replacements, etc.), we now
@ -138,7 +149,7 @@ export default class ReplyThread extends React.Component<IProps, IState> {
public static getNestedReplyText(
ev: MatrixEvent,
permalinkCreator: RoomPermalinkCreator,
): { body: string, html: string } {
): { body: string, html: string } | null {
if (!ev) return null;
let { body, formatted_body: html } = ev.getContent();
@ -238,39 +249,38 @@ export default class ReplyThread extends React.Component<IProps, IState> {
return replyMixin;
}
public static makeThread(
parentEv: MatrixEvent,
onHeightChanged: () => void,
permalinkCreator: RoomPermalinkCreator,
ref: React.RefObject<ReplyThread>,
layout: Layout,
forExport: boolean,
alwaysShowTimestamps: boolean,
): JSX.Element {
if (!ReplyThread.getParentEventId(parentEv)) return null;
return <ReplyThread
parentEv={parentEv}
forExport={forExport}
onHeightChanged={onHeightChanged}
ref={ref}
permalinkCreator={permalinkCreator}
layout={layout}
alwaysShowTimestamps={alwaysShowTimestamps}
/>;
public static hasThreadReply(event: MatrixEvent) {
return Boolean(ReplyThread.getParentEventId(event));
}
componentDidMount() {
this.initialize();
this.trySetExpandableQuotes();
}
componentDidUpdate() {
this.props.onHeightChanged();
this.trySetExpandableQuotes();
}
componentWillUnmount() {
this.unmounted = true;
}
private trySetExpandableQuotes() {
if (this.props.isQuoteExpanded === undefined && this.blockquoteRef.current) {
const el: HTMLElement | null = this.blockquoteRef.current.querySelector('.mx_EventTile_body');
if (el) {
const code: HTMLElement | null = el.querySelector('code');
const isCodeEllipsisShown = code ? code.offsetHeight >= SHOW_EXPAND_QUOTE_PIXELS : false;
const isElipsisShown = el.offsetHeight >= SHOW_EXPAND_QUOTE_PIXELS || isCodeEllipsisShown;
if (isElipsisShown) {
this.props.setQuoteExpanded(false);
}
}
}
}
private async initialize(): Promise<void> {
const { parentEv } = this.props;
// at time of making this component we checked that props.parentEv has a parentEventId
@ -324,7 +334,7 @@ export default class ReplyThread extends React.Component<IProps, IState> {
this.initialize();
};
private onQuoteClick = async (): Promise<void> => {
private onQuoteClick = async (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>): Promise<void> => {
const events = [this.state.loadedEv, ...this.state.events];
let loadedEv = null;
@ -387,14 +397,26 @@ export default class ReplyThread extends React.Component<IProps, IState> {
header = <Spinner w={16} h={16} />;
}
const { isQuoteExpanded } = this.props;
const evTiles = this.state.events.map((ev) => {
return <blockquote className={`mx_ReplyThread ${this.getReplyThreadColorClass(ev)}`} key={ev.getId()}>
<ReplyTile
mxEvent={ev}
onHeightChanged={this.props.onHeightChanged}
permalinkCreator={this.props.permalinkCreator}
/>
</blockquote>;
const classname = classNames({
'mx_ReplyThread': true,
[this.getReplyThreadColorClass(ev)]: true,
// We don't want to add the class if it's undefined, it should only be expanded/collapsed when it's true/false
'mx_ReplyThread--expanded': isQuoteExpanded === true,
// We don't want to add the class if it's undefined, it should only be expanded/collapsed when it's true/false
'mx_ReplyThread--collapsed': isQuoteExpanded === false,
});
return (
<blockquote ref={this.blockquoteRef} className={classname} key={ev.getId()}>
<ReplyTile
mxEvent={ev}
onHeightChanged={this.props.onHeightChanged}
permalinkCreator={this.props.permalinkCreator}
toggleExpandedQuote={() => this.props.setQuoteExpanded(!this.props.isQuoteExpanded)}
/>
</blockquote>
);
});
return <div className="mx_ReplyThread_wrapper">