Merge branch 'develop' into export-conversations
This commit is contained in:
commit
208b914cb0
62 changed files with 936 additions and 678 deletions
|
@ -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 });
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue