Merge branch 'develop' into johannes/find-myself

This commit is contained in:
Johannes Marbach 2023-02-08 16:42:14 +01:00 committed by GitHub
commit f842e319de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 707 additions and 271 deletions

View file

@ -39,7 +39,7 @@ const ZoomButtons: React.FC<Props> = ({ map }) => {
<div className="mx_ZoomButtons">
<AccessibleButton
onClick={onZoomIn}
data-test-id="map-zoom-in-button"
data-testid="map-zoom-in-button"
title={_t("Zoom in")}
className="mx_ZoomButtons_button"
>
@ -47,7 +47,7 @@ const ZoomButtons: React.FC<Props> = ({ map }) => {
</AccessibleButton>
<AccessibleButton
onClick={onZoomOut}
data-test-id="map-zoom-out-button"
data-testid="map-zoom-out-button"
title={_t("Zoom out")}
className="mx_ZoomButtons_button"
>

View file

@ -0,0 +1,109 @@
/*
Copyright 2023 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.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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, { useEffect, useState, useContext } from "react";
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
import { logger } from "matrix-js-sdk/src/logger";
import { Icon as PollIcon } from "../../../../res/img/element-icons/room/composer/poll.svg";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { textForEvent } from "../../../TextForEvent";
import { IBodyProps } from "./IBodyProps";
import MPollBody from "./MPollBody";
const getRelatedPollStartEventId = (event: MatrixEvent): string | undefined => {
const relation = event.getRelation();
return relation?.event_id;
};
/**
* Attempt to retrieve the related poll start event for this end event
* If the event already exists in the rooms timeline, return it
* Otherwise try to fetch the event from the server
* @param event
* @returns
*/
const usePollStartEvent = (event: MatrixEvent): { pollStartEvent?: MatrixEvent; isLoadingPollStartEvent: boolean } => {
const matrixClient = useContext(MatrixClientContext);
const [pollStartEvent, setPollStartEvent] = useState<MatrixEvent>();
const [isLoadingPollStartEvent, setIsLoadingPollStartEvent] = useState(false);
const pollStartEventId = getRelatedPollStartEventId(event);
useEffect(() => {
const room = matrixClient.getRoom(event.getRoomId());
const fetchPollStartEvent = async (roomId: string, pollStartEventId: string): Promise<void> => {
setIsLoadingPollStartEvent(true);
try {
const startEventJson = await matrixClient.fetchRoomEvent(roomId, pollStartEventId);
const startEvent = new MatrixEvent(startEventJson);
// add the poll to the room polls state
room?.processPollEvents([startEvent, event]);
// end event is not a valid end to the related start event
// if not sent by the same user
if (startEvent.getSender() === event.getSender()) {
setPollStartEvent(startEvent);
}
} catch (error) {
logger.error("Failed to fetch related poll start event", error);
} finally {
setIsLoadingPollStartEvent(false);
}
};
if (pollStartEvent || !room || !pollStartEventId) {
return;
}
const timelineSet = room.getUnfilteredTimelineSet();
const localEvent = timelineSet
?.getTimelineForEvent(pollStartEventId)
?.getEvents()
.find((e) => e.getId() === pollStartEventId);
if (localEvent) {
// end event is not a valid end to the related start event
// if not sent by the same user
if (localEvent.getSender() === event.getSender()) {
setPollStartEvent(localEvent);
}
} else {
// pollStartEvent is not in the current timeline,
// fetch it
fetchPollStartEvent(room.roomId, pollStartEventId);
}
}, [event, pollStartEventId, pollStartEvent, matrixClient]);
return { pollStartEvent, isLoadingPollStartEvent };
};
export const MPollEndBody = React.forwardRef<any, IBodyProps>(({ mxEvent, ...props }, ref) => {
const { pollStartEvent, isLoadingPollStartEvent } = usePollStartEvent(mxEvent);
if (!pollStartEvent) {
const pollEndFallbackMessage = M_TEXT.findIn(mxEvent.getContent()) || textForEvent(mxEvent);
return (
<>
<PollIcon className="mx_MPollEndBody_icon" />
{!isLoadingPollStartEvent && pollEndFallbackMessage}
</>
);
}
return <MPollBody mxEvent={pollStartEvent} {...props} />;
});

View file

@ -18,7 +18,7 @@ import React, { createRef } from "react";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { M_LOCATION } from "matrix-js-sdk/src/@types/location";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_POLL_END, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import SettingsStore from "../../../settings/SettingsStore";
@ -37,6 +37,7 @@ import MVoiceOrAudioBody from "./MVoiceOrAudioBody";
import MVideoBody from "./MVideoBody";
import MStickerBody from "./MStickerBody";
import MPollBody from "./MPollBody";
import { MPollEndBody } from "./MPollEndBody";
import MLocationBody from "./MLocationBody";
import MjolnirBody from "./MjolnirBody";
import MBeaconBody from "./MBeaconBody";
@ -73,6 +74,8 @@ const baseEvTypes = new Map<string, React.ComponentType<Partial<IBodyProps>>>([
[EventType.Sticker, MStickerBody],
[M_POLL_START.name, MPollBody],
[M_POLL_START.altName, MPollBody],
[M_POLL_END.name, MPollEndBody],
[M_POLL_END.altName, MPollEndBody],
[M_BEACON_INFO.name, MBeaconBody],
[M_BEACON_INFO.altName, MBeaconBody],
]);

View file

@ -1,6 +1,7 @@
/*
Copyright 2020 Nurjin Jafar
Copyright 2020 Nordeck IT + Consulting GmbH.
Copyright 2023 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.
@ -86,7 +87,7 @@ export default class Confetti implements ICanvasEffect {
private particles: Array<ConfettiParticle> = [];
private waveAngle = 0;
public isRunning: boolean;
public isRunning = false;
public start = async (canvas: HTMLCanvasElement, timeout = 3000): Promise<void> => {
if (!canvas) {

View file

@ -1,6 +1,7 @@
/*
Copyright 2020 Nurjin Jafar
Copyright 2020 Nordeck IT + Consulting GmbH.
Copyright 2023 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.
@ -69,7 +70,7 @@ export default class Fireworks implements ICanvasEffect {
private context: CanvasRenderingContext2D | null = null;
private supportsAnimationFrame = window.requestAnimationFrame;
private particles: Array<FireworksParticle> = [];
public isRunning: boolean;
public isRunning = false;
public start = async (canvas: HTMLCanvasElement, timeout = 3000): Promise<void> => {
if (!canvas) {
@ -94,7 +95,7 @@ export default class Fireworks implements ICanvasEffect {
if (this.particles.length < this.options.maxCount && this.isRunning) {
this.createFirework();
}
const alive = [];
const alive: FireworksParticle[] = [];
for (let i = 0; i < this.particles.length; i++) {
if (this.move(this.particles[i])) {
alive.push(this.particles[i]);

View file

@ -1,5 +1,5 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Copyright 2021 - 2023 The Matrix.org Foundation C.I.C.
Copyright 2022 Arseny Uskov
Licensed under the Apache License, Version 2.0 (the "License");
@ -65,7 +65,7 @@ export default class Hearts implements ICanvasEffect {
private context: CanvasRenderingContext2D | null = null;
private particles: Array<Heart> = [];
private lastAnimationTime: number;
private lastAnimationTime = 0;
private colours = [
"rgba(194,210,224,1)",
@ -82,7 +82,7 @@ export default class Hearts implements ICanvasEffect {
"rgba(252,116,183,1)",
];
public isRunning: boolean;
public isRunning = false;
public start = async (canvas: HTMLCanvasElement, timeout = 3000): Promise<void> => {
if (!canvas) {

View file

@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020 - 2023 The Matrix.org Foundation C.I.C.
Copyright 2021 Josias Allestad
Licensed under the Apache License, Version 2.0 (the "License");
@ -52,9 +52,9 @@ export default class Rainfall implements ICanvasEffect {
private context: CanvasRenderingContext2D | null = null;
private particles: Array<Raindrop> = [];
private lastAnimationTime: number;
private lastAnimationTime = 0;
public isRunning: boolean;
public isRunning = false;
public start = async (canvas: HTMLCanvasElement, timeout = 3000): Promise<void> => {
if (!canvas) {

View file

@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020 - 2023 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.
@ -57,9 +57,9 @@ export default class Snowfall implements ICanvasEffect {
private context: CanvasRenderingContext2D | null = null;
private particles: Array<Snowflake> = [];
private lastAnimationTime: number;
private lastAnimationTime = 0;
public isRunning: boolean;
public isRunning = false;
public start = async (canvas: HTMLCanvasElement, timeout = 3000): Promise<void> => {
if (!canvas) {

View file

@ -1,5 +1,5 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Copyright 2021 - 2023 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.
@ -51,9 +51,9 @@ export default class SpaceInvaders implements ICanvasEffect {
private context: CanvasRenderingContext2D | null = null;
private particles: Array<Invader> = [];
private lastAnimationTime: number;
private lastAnimationTime = 0;
public isRunning: boolean;
public isRunning = false;
public start = async (canvas: HTMLCanvasElement, timeout = 3000): Promise<void> => {
if (!canvas) {

View file

@ -18,7 +18,7 @@ import React from "react";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
import { Optional } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_POLL_END, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { GroupCallIntent } from "matrix-js-sdk/src/webrtc/groupCall";
@ -99,6 +99,8 @@ const EVENT_TILE_TYPES = new Map<string, Factory>([
[EventType.Sticker, MessageEventFactory],
[M_POLL_START.name, MessageEventFactory],
[M_POLL_START.altName, MessageEventFactory],
[M_POLL_END.name, MessageEventFactory],
[M_POLL_END.altName, MessageEventFactory],
[EventType.KeyVerificationCancel, KeyVerificationConclFactory],
[EventType.KeyVerificationDone, KeyVerificationConclFactory],
[EventType.CallInvite, LegacyCallEventFactory], // note that this requires a special factory type
@ -412,7 +414,11 @@ export function renderReplyTile(
// XXX: this'll eventually be dynamic based on the fields once we have extensible event types
const messageTypes = [EventType.RoomMessage, EventType.Sticker];
export function isMessageEvent(ev: MatrixEvent): boolean {
return messageTypes.includes(ev.getType() as EventType) || M_POLL_START.matches(ev.getType());
return (
messageTypes.includes(ev.getType() as EventType) ||
M_POLL_START.matches(ev.getType()) ||
M_POLL_END.matches(ev.getType())
);
}
export function haveRendererForEvent(mxEvent: MatrixEvent, showHiddenEvents: boolean): boolean {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_POLL_END, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { MatrixEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
@ -26,7 +26,7 @@ import { VoiceBroadcastInfoEventType } from "../../voice-broadcast/types";
* If an event is not forwardable return null
*/
export const getForwardableEvent = (event: MatrixEvent, cli: MatrixClient): MatrixEvent | null => {
if (M_POLL_START.matches(event.getType())) {
if (M_POLL_START.matches(event.getType()) || M_POLL_END.matches(event.getType())) {
return null;
}

View file

@ -16,7 +16,7 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_POLL_END, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { IContent } from "matrix-js-sdk/src/matrix";
@ -41,6 +41,7 @@ const calcIsInfoMessage = (
eventType !== EventType.Sticker &&
eventType !== EventType.RoomCreate &&
!M_POLL_START.matches(eventType) &&
!M_POLL_END.matches(eventType) &&
!M_BEACON_INFO.matches(eventType) &&
!(eventType === VoiceBroadcastInfoEventType && content?.state === VoiceBroadcastInfoState.Started)
);

View file

@ -18,7 +18,7 @@ import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, EVENT_VISIBILITY_CHANGE_TYPE, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { logger } from "matrix-js-sdk/src/logger";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_POLL_END, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_LOCATION } from "matrix-js-sdk/src/@types/location";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
@ -57,6 +57,7 @@ export function isContentActionable(mxEvent: MatrixEvent): boolean {
} else if (
mxEvent.getType() === "m.sticker" ||
M_POLL_START.matches(mxEvent.getType()) ||
M_POLL_END.matches(mxEvent.getType()) ||
M_BEACON_INFO.matches(mxEvent.getType()) ||
(mxEvent.getType() === VoiceBroadcastInfoEventType &&
mxEvent.getContent()?.state === VoiceBroadcastInfoState.Started)