hide thread events from the timeline

This commit is contained in:
Germain Souquet 2021-08-17 11:10:02 +01:00
parent e5024c4b71
commit d1dbfbd014
7 changed files with 110 additions and 11 deletions

View file

@ -173,6 +173,8 @@ interface IProps {
onUnfillRequest?(backwards: boolean, scrollToken: string): void;
getRelationsForEvent?(eventId: string, relationType: string, eventType: string): Relations;
hideThreadedMessages?: boolean;
}
interface IState {
@ -443,6 +445,11 @@ export default class MessagePanel extends React.Component<IProps, IState> {
// Always show highlighted event
if (this.props.highlightedEventId === mxEv.getId()) return true;
const threadingEnabled = SettingsStore.getValue("feature_threading");
if (threadingEnabled && mxEv.replyEventId && this.props.hideThreadedMessages === true) {
return false;
}
return !shouldHideEvent(mxEv, this.context);
}

View file

@ -24,9 +24,11 @@ import { replaceableComponent } from "../../utils/replaceableComponent";
import { MatrixClientPeg } from '../../MatrixClientPeg';
import ResizeNotifier from '../../utils/ResizeNotifier';
import EventTile from '../views/rooms/EventTile';
import EventTile, { TileShape } from '../views/rooms/EventTile';
import MessageComposer from '../views/rooms/MessageComposer';
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
import { Layout } from '../../settings/Layout';
import TimelinePanel from './TimelinePanel';
interface IProps {
roomId: string;
@ -37,6 +39,7 @@ interface IProps {
}
interface IState {
replyToEvent?: MatrixEvent;
}
/*
@ -65,6 +68,7 @@ class ThreadView extends React.Component<IProps, IState> {
mxEvent={event}
enableFlair={false}
showReadReceipts={false}
tileShape={TileShape.FileGrid}
as="div"
/>;
}
@ -77,19 +81,24 @@ class ThreadView extends React.Component<IProps, IState> {
className="mx_ThreadView"
onClose={this.props.onClose}
previousPhase={RightPanelPhases.RoomSummary}
withoutScrollContainer={true}
>
{ this.renderEventTile(this.props.mxEvent) }
{ thread && (
thread.eventTimeline.map((event: MatrixEvent) => {
return this.renderEventTile(event);
})
) }
<TimelinePanel
manageReadReceipts={false}
manageReadMarkers={false}
timelineSet={thread.timelineSet}
showUrlPreview={false}
tileShape={TileShape.Notif}
empty={<div>empty</div>}
alwaysShowTimestamps={true}
layout={Layout.Group}
hideThreadedMessages={false}
/>
<MessageComposer
room={room}
resizeNotifier={this.props.resizeNotifier}
replyToEvent={this.props.mxEvent}
replyToEvent={thread?.replyToEvent}
showReplyPreview={false}
permalinkCreator={this.props.permalinkCreator}
/>
</BaseCard>

View file

@ -126,6 +126,8 @@ interface IProps {
// callback which is called when we wish to paginate the timeline window.
onPaginationRequest?(timelineWindow: TimelineWindow, direction: string, size: number): Promise<boolean>;
hideThreadedMessages?: boolean;
}
interface IState {
@ -214,6 +216,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
timelineCap: Number.MAX_VALUE,
className: 'mx_RoomView_messagePanel',
sendReadReceiptOnLoad: true,
hideThreadedMessages: true,
};
private lastRRSentEventId: string = undefined;
@ -1511,6 +1514,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
showReactions={this.props.showReactions}
layout={this.props.layout}
enableFlair={SettingsStore.getValue(UIFeature.Flair)}
hideThreadedMessages={this.props.hideThreadedMessages}
/>
);
}

View file

@ -55,6 +55,7 @@ import ReadReceiptMarker from "./ReadReceiptMarker";
import MessageActionBar from "../messages/MessageActionBar";
import ReactionsRow from '../messages/ReactionsRow';
import { getEventDisplayInfo } from '../../../utils/EventUtils';
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
const eventTileTypes = {
[EventType.RoomMessage]: 'messages.MessageEvent',
@ -299,6 +300,9 @@ interface IProps {
// whether or not to display the sender
hideSender?: boolean;
// whether or not to display thread info
showThreadInfo?: boolean;
}
interface IState {
@ -451,6 +455,7 @@ export default class EventTile extends React.Component<IProps, IState> {
client.on("Room.receipt", this.onRoomReceipt);
this.isListeningForReceipts = true;
}
this.props.mxEvent.on("Thread.update", this.forceUpdate);
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
@ -491,6 +496,38 @@ export default class EventTile extends React.Component<IProps, IState> {
}
}
private renderThreadInfo(): React.ReactNode {
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
const thread = room.getThread(this.props.mxEvent.getId());
if (!thread || this.props.showThreadInfo === false) {
return null;
}
const avatars = Array.from(thread.participants).map((mxId: string) => {
const member = room.getMember(mxId);
return <MemberAvatar key={member.userId} member={member} width={14} height={14} />;
});
return (
<div
onClick={() => {
dis.dispatch({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.ThreadView,
refireParams: {
event: this.props.mxEvent,
},
});
}}
>
<span className="mx_EventListSummary_avatars">
{ avatars }
</span>
{ thread.length } { thread.length === 1 ? 'reply' : 'replies' }
</div>
);
}
private onRoomReceipt = (ev, room) => {
// ignore events for other rooms
const tileRoom = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
@ -1167,6 +1204,7 @@ export default class EventTile extends React.Component<IProps, IState> {
{ keyRequestInfo }
{ actionBar }
{ this.props.layout === Layout.IRC && (reactionsRow) }
{ this.renderThreadInfo() }
</div>
{ this.props.layout !== Layout.IRC && (reactionsRow) }
{ msgOption }

View file

@ -183,6 +183,7 @@ interface IProps {
resizeNotifier: ResizeNotifier;
permalinkCreator: RoomPermalinkCreator;
replyToEvent?: MatrixEvent;
showReplyPreview?: boolean;
e2eStatus?: E2EStatus;
}
@ -201,6 +202,10 @@ export default class MessageComposer extends React.Component<IProps, IState> {
private messageComposerInput: SendMessageComposer;
private voiceRecordingButton: VoiceRecordComposerTile;
static defaultProps = {
showReplyPreview: true,
};
constructor(props) {
super(props);
VoiceRecordingStore.instance.on(UPDATE_EVENT, this.onVoiceStoreUpdate);
@ -454,7 +459,9 @@ export default class MessageComposer extends React.Component<IProps, IState> {
<div className="mx_MessageComposer mx_GroupLayout">
{ recordingTooltip }
<div className="mx_MessageComposer_wrapper">
<ReplyPreview permalinkCreator={this.props.permalinkCreator} />
{ this.props.showReplyPreview && (
<ReplyPreview permalinkCreator={this.props.permalinkCreator} />
) }
<div className="mx_MessageComposer_row">
{ controls }
</div>