Merge branch 'develop' into weeman1337/mute-broadcast-notifications

This commit is contained in:
Michael Weimann 2023-01-03 16:54:05 +01:00 committed by GitHub
commit 804f0925df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 85 additions and 24 deletions

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { forwardRef, RefObject, useRef } from "react"; import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react";
import classNames from "classnames"; import classNames from "classnames";
import EditorStateTransfer from "../../../../utils/EditorStateTransfer"; import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
@ -24,16 +24,18 @@ import { useWysiwygEditActionHandler } from "./hooks/useWysiwygEditActionHandler
import { useEditing } from "./hooks/useEditing"; import { useEditing } from "./hooks/useEditing";
import { useInitialContent } from "./hooks/useInitialContent"; import { useInitialContent } from "./hooks/useInitialContent";
import { ComposerContext, getDefaultContextValue } from "./ComposerContext"; import { ComposerContext, getDefaultContextValue } from "./ComposerContext";
import { ComposerFunctions } from "./types";
interface ContentProps { interface ContentProps {
disabled: boolean; disabled?: boolean;
composerFunctions: ComposerFunctions;
} }
const Content = forwardRef<HTMLElement, ContentProps>(function Content( const Content = forwardRef<HTMLElement, ContentProps>(function Content(
{ disabled }: ContentProps, { disabled = false, composerFunctions }: ContentProps,
forwardRef: RefObject<HTMLElement>, forwardRef: ForwardedRef<HTMLElement>,
) { ) {
useWysiwygEditActionHandler(disabled, forwardRef); useWysiwygEditActionHandler(disabled, forwardRef as MutableRefObject<HTMLElement>, composerFunctions);
return null; return null;
}); });
@ -65,9 +67,9 @@ export default function EditWysiwygComposer({ editorStateTransfer, className, ..
onSend={editMessage} onSend={editMessage}
{...props} {...props}
> >
{(ref) => ( {(ref, composerFunctions) => (
<> <>
<Content disabled={props.disabled} ref={ref} /> <Content disabled={props.disabled} ref={ref} composerFunctions={composerFunctions} />
<EditionButtons <EditionButtons
onCancelClick={endEditing} onCancelClick={endEditing}
onSaveClick={editMessage} onSaveClick={editMessage}

View file

@ -22,8 +22,6 @@ import dis from "../../../../../dispatcher/dispatcher";
import { ComposerInsertPayload } from "../../../../../dispatcher/payloads/ComposerInsertPayload"; import { ComposerInsertPayload } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
import { Action } from "../../../../../dispatcher/actions"; import { Action } from "../../../../../dispatcher/actions";
import { useRoomContext } from "../../../../../contexts/RoomContext"; import { useRoomContext } from "../../../../../contexts/RoomContext";
import { useComposerContext } from "../ComposerContext";
import { setSelection } from "../utils/selection";
interface EmojiProps { interface EmojiProps {
menuPosition: AboveLeftOf; menuPosition: AboveLeftOf;
@ -31,19 +29,16 @@ interface EmojiProps {
export function Emoji({ menuPosition }: EmojiProps) { export function Emoji({ menuPosition }: EmojiProps) {
const roomContext = useRoomContext(); const roomContext = useRoomContext();
const composerContext = useComposerContext();
return ( return (
<EmojiButton <EmojiButton
menuPosition={menuPosition} menuPosition={menuPosition}
addEmoji={(emoji) => { addEmoji={(emoji) => {
setSelection(composerContext.selection).then(() => dis.dispatch<ComposerInsertPayload>({
dis.dispatch<ComposerInsertPayload>({ action: Action.ComposerInsert,
action: Action.ComposerInsert, text: emoji,
text: emoji, timelineRenderingType: roomContext.timelineRenderingType,
timelineRenderingType: roomContext.timelineRenderingType, });
}),
);
return true; return true;
}} }}
/> />

View file

@ -22,9 +22,18 @@ import { ActionPayload } from "../../../../../dispatcher/payloads";
import { TimelineRenderingType, useRoomContext } from "../../../../../contexts/RoomContext"; import { TimelineRenderingType, useRoomContext } from "../../../../../contexts/RoomContext";
import { useDispatcher } from "../../../../../hooks/useDispatcher"; import { useDispatcher } from "../../../../../hooks/useDispatcher";
import { focusComposer } from "./utils"; import { focusComposer } from "./utils";
import { ComposerType } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
import { ComposerFunctions } from "../types";
import { setSelection } from "../utils/selection";
import { useComposerContext } from "../ComposerContext";
export function useWysiwygEditActionHandler(disabled: boolean, composerElement: RefObject<HTMLElement>) { export function useWysiwygEditActionHandler(
disabled: boolean,
composerElement: RefObject<HTMLElement>,
composerFunctions: ComposerFunctions,
) {
const roomContext = useRoomContext(); const roomContext = useRoomContext();
const composerContext = useComposerContext();
const timeoutId = useRef<number | null>(null); const timeoutId = useRef<number | null>(null);
const handler = useCallback( const handler = useCallback(
@ -39,9 +48,17 @@ export function useWysiwygEditActionHandler(disabled: boolean, composerElement:
case Action.FocusEditMessageComposer: case Action.FocusEditMessageComposer:
focusComposer(composerElement, context, roomContext, timeoutId); focusComposer(composerElement, context, roomContext, timeoutId);
break; break;
case Action.ComposerInsert:
if (payload.timelineRenderingType !== roomContext.timelineRenderingType) break;
if (payload.composerType !== ComposerType.Edit) break;
if (payload.text) {
setSelection(composerContext.selection).then(() => composerFunctions.insertText(payload.text));
}
break;
} }
}, },
[disabled, composerElement, timeoutId, roomContext], [disabled, composerElement, composerFunctions, timeoutId, roomContext, composerContext],
); );
useDispatcher(defaultDispatcher, handler); useDispatcher(defaultDispatcher, handler);

View file

@ -24,6 +24,8 @@ import { useDispatcher } from "../../../../../hooks/useDispatcher";
import { focusComposer } from "./utils"; import { focusComposer } from "./utils";
import { ComposerFunctions } from "../types"; import { ComposerFunctions } from "../types";
import { ComposerType } from "../../../../../dispatcher/payloads/ComposerInsertPayload"; import { ComposerType } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
import { useComposerContext } from "../ComposerContext";
import { setSelection } from "../utils/selection";
export function useWysiwygSendActionHandler( export function useWysiwygSendActionHandler(
disabled: boolean, disabled: boolean,
@ -31,6 +33,7 @@ export function useWysiwygSendActionHandler(
composerFunctions: ComposerFunctions, composerFunctions: ComposerFunctions,
) { ) {
const roomContext = useRoomContext(); const roomContext = useRoomContext();
const composerContext = useComposerContext();
const timeoutId = useRef<number | null>(null); const timeoutId = useRef<number | null>(null);
const handler = useCallback( const handler = useCallback(
@ -59,12 +62,12 @@ export function useWysiwygSendActionHandler(
} else if (payload.event) { } else if (payload.event) {
// TODO insert quote message - see SendMessageComposer // TODO insert quote message - see SendMessageComposer
} else if (payload.text) { } else if (payload.text) {
composerFunctions.insertText(payload.text); setSelection(composerContext.selection).then(() => composerFunctions.insertText(payload.text));
} }
break; break;
} }
}, },
[disabled, composerElement, composerFunctions, timeoutId, roomContext], [disabled, composerElement, roomContext, composerFunctions, composerContext],
); );
useDispatcher(defaultDispatcher, handler); useDispatcher(defaultDispatcher, handler);

View file

@ -953,7 +953,6 @@
"Temporary implementation. Locations persist in room history.": "Temporary implementation. Locations persist in room history.", "Temporary implementation. Locations persist in room history.": "Temporary implementation. Locations persist in room history.",
"Favourite Messages": "Favourite Messages", "Favourite Messages": "Favourite Messages",
"Under active development.": "Under active development.", "Under active development.": "Under active development.",
"Under active development": "Under active development",
"Force 15s voice broadcast chunk length": "Force 15s voice broadcast chunk length", "Force 15s voice broadcast chunk length": "Force 15s voice broadcast chunk length",
"Use new session manager": "Use new session manager", "Use new session manager": "Use new session manager",
"New session manager": "New session manager", "New session manager": "New session manager",

View file

@ -459,7 +459,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
labsGroup: LabGroup.Messaging, labsGroup: LabGroup.Messaging,
supportedLevels: LEVELS_FEATURE, supportedLevels: LEVELS_FEATURE,
displayName: _td("Voice broadcast"), displayName: _td("Voice broadcast"),
description: _td("Under active development"),
default: false, default: false,
}, },
[Features.VoiceBroadcastForceSmallChunks]: { [Features.VoiceBroadcastForceSmallChunks]: {

View file

@ -26,6 +26,12 @@ import { IRoomState } from "../../../../../src/components/structures/RoomView";
import { createTestClient, flushPromises, getRoomContext, mkEvent, mkStubRoom } from "../../../../test-utils"; import { createTestClient, flushPromises, getRoomContext, mkEvent, mkStubRoom } from "../../../../test-utils";
import { EditWysiwygComposer } from "../../../../../src/components/views/rooms/wysiwyg_composer"; import { EditWysiwygComposer } from "../../../../../src/components/views/rooms/wysiwyg_composer";
import EditorStateTransfer from "../../../../../src/utils/EditorStateTransfer"; import EditorStateTransfer from "../../../../../src/utils/EditorStateTransfer";
import { Emoji } from "../../../../../src/components/views/rooms/wysiwyg_composer/components/Emoji";
import { ChevronFace } from "../../../../../src/components/structures/ContextMenu";
import dis from "../../../../../src/dispatcher/dispatcher";
import { ComposerInsertPayload, ComposerType } from "../../../../../src/dispatcher/payloads/ComposerInsertPayload";
import { ActionPayload } from "../../../../../src/dispatcher/payloads";
import * as EmojiButton from "../../../../../src/components/views/rooms/EmojiButton";
describe("EditWysiwygComposer", () => { describe("EditWysiwygComposer", () => {
afterEach(() => { afterEach(() => {
@ -269,4 +275,44 @@ describe("EditWysiwygComposer", () => {
// Then we don't get it because we are disabled // Then we don't get it because we are disabled
expect(screen.getByRole("textbox")).not.toHaveFocus(); expect(screen.getByRole("textbox")).not.toHaveFocus();
}); });
it("Should add emoji", async () => {
// When
// We are not testing here the emoji button (open modal, select emoji ...)
// Instead we are directly firing an emoji to make the test easier to write
jest.spyOn(EmojiButton, "EmojiButton").mockImplementation(
({ addEmoji }: { addEmoji: (emoji: string) => void }) => {
return (
<button aria-label="Emoji" type="button" onClick={() => addEmoji("🦫")}>
Emoji
</button>
);
},
);
render(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={defaultRoomContext}>
<EditWysiwygComposer editorStateTransfer={editorStateTransfer} />
<Emoji menuPosition={{ chevronFace: ChevronFace.Top }} />
</RoomContext.Provider>
</MatrixClientContext.Provider>,
);
// Same behavior as in RoomView.tsx
// RoomView is re-dispatching the composer messages.
// It adds the composerType fields where the value refers if the composer is in editing or not
// The listeners in the RTE ignore the message if the composerType is missing in the payload
const dispatcherRef = dis.register((payload: ActionPayload) => {
dis.dispatch<ComposerInsertPayload>({
...(payload as ComposerInsertPayload),
composerType: ComposerType.Edit,
});
});
screen.getByLabelText("Emoji").click();
// Then
await waitFor(() => expect(screen.getByRole("textbox")).toHaveTextContent(/🦫/));
dis.unregister(dispatcherRef);
});
}); });

View file

@ -294,7 +294,7 @@ describe("SendWysiwygComposer", () => {
}); });
const textNode = screen.getByRole("textbox").firstChild; const textNode = screen.getByRole("textbox").firstChild;
setSelection({ await setSelection({
anchorNode: textNode, anchorNode: textNode,
anchorOffset: 2, anchorOffset: 2,
focusNode: textNode, focusNode: textNode,