Merge branch 'develop' into gsouquet/threads-forceenablelabsflag
This commit is contained in:
commit
d4f247d1fe
97 changed files with 3280 additions and 1325 deletions
|
@ -58,6 +58,8 @@ import { SendWysiwygComposer, sendMessage, getConversionFunctions } from "./wysi
|
|||
import { MatrixClientProps, withMatrixClientHOC } from "../../../contexts/MatrixClientContext";
|
||||
import { setUpVoiceBroadcastPreRecording } from "../../../voice-broadcast/utils/setUpVoiceBroadcastPreRecording";
|
||||
import { SdkContextClass } from "../../../contexts/SDKContext";
|
||||
import { VoiceBroadcastInfoState } from "../../../voice-broadcast";
|
||||
import { createCantStartVoiceMessageBroadcastDialog } from "../dialogs/CantStartVoiceMessageBroadcastDialog";
|
||||
|
||||
let instanceCount = 0;
|
||||
|
||||
|
@ -445,6 +447,20 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
private onRecordStartEndClick = (): void => {
|
||||
const currentBroadcastRecording = SdkContextClass.instance.voiceBroadcastRecordingsStore.getCurrent();
|
||||
|
||||
if (currentBroadcastRecording && currentBroadcastRecording.getState() !== VoiceBroadcastInfoState.Stopped) {
|
||||
createCantStartVoiceMessageBroadcastDialog();
|
||||
} else {
|
||||
this.voiceRecordingButton.current?.onRecordStartEndClick();
|
||||
}
|
||||
|
||||
if (this.context.narrow) {
|
||||
this.toggleButtonMenu();
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
const hasE2EIcon = Boolean(!this.state.isWysiwygLabEnabled && this.props.e2eStatus);
|
||||
const e2eIcon = hasE2EIcon && (
|
||||
|
@ -588,12 +604,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
isStickerPickerOpen={this.state.isStickerPickerOpen}
|
||||
menuPosition={menuPosition}
|
||||
relation={this.props.relation}
|
||||
onRecordStartEndClick={() => {
|
||||
this.voiceRecordingButton.current?.onRecordStartEndClick();
|
||||
if (this.context.narrow) {
|
||||
this.toggleButtonMenu();
|
||||
}
|
||||
}}
|
||||
onRecordStartEndClick={this.onRecordStartEndClick}
|
||||
setStickerPickerOpen={this.setStickerPickerOpen}
|
||||
showLocationButton={!window.electron}
|
||||
showPollsButton={this.state.showPollsButton}
|
||||
|
|
|
@ -376,8 +376,8 @@ function ComposerModeButton({ isRichTextEnabled, onClick }: WysiwygToggleButtonP
|
|||
<CollapsibleButton
|
||||
className="mx_MessageComposer_button"
|
||||
iconClassName={classNames({
|
||||
mx_MessageComposer_plain_text: isRichTextEnabled,
|
||||
mx_MessageComposer_rich_text: !isRichTextEnabled,
|
||||
mx_MessageComposer_plain_text: !isRichTextEnabled,
|
||||
mx_MessageComposer_rich_text: isRichTextEnabled,
|
||||
})}
|
||||
onClick={onClick}
|
||||
title={title}
|
||||
|
|
|
@ -120,7 +120,7 @@ export function FormattingButtons({ composer, actionStates }: FormattingButtonsP
|
|||
<Button
|
||||
isActive={actionStates.link === "reversed"}
|
||||
label={_td("Link")}
|
||||
onClick={() => openLinkModal(composer, composerContext)}
|
||||
onClick={() => openLinkModal(composer, composerContext, actionStates.link === "reversed")}
|
||||
icon={<LinkIcon className="mx_FormattingButtons_Icon" />}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -17,17 +17,28 @@ limitations under the License.
|
|||
import { FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
|
||||
import React, { ChangeEvent, useState } from "react";
|
||||
|
||||
import { _td } from "../../../../../languageHandler";
|
||||
import { _t } from "../../../../../languageHandler";
|
||||
import Modal from "../../../../../Modal";
|
||||
import QuestionDialog from "../../../dialogs/QuestionDialog";
|
||||
import Field from "../../../elements/Field";
|
||||
import { ComposerContextState } from "../ComposerContext";
|
||||
import { isSelectionEmpty, setSelection } from "../utils/selection";
|
||||
import BaseDialog from "../../../dialogs/BaseDialog";
|
||||
import DialogButtons from "../../../elements/DialogButtons";
|
||||
|
||||
export function openLinkModal(composer: FormattingFunctions, composerContext: ComposerContextState) {
|
||||
export function openLinkModal(
|
||||
composer: FormattingFunctions,
|
||||
composerContext: ComposerContextState,
|
||||
isEditing: boolean,
|
||||
) {
|
||||
const modal = Modal.createDialog(
|
||||
LinkModal,
|
||||
{ composerContext, composer, onClose: () => modal.close(), isTextEnabled: isSelectionEmpty() },
|
||||
{
|
||||
composerContext,
|
||||
composer,
|
||||
onClose: () => modal.close(),
|
||||
isTextEnabled: isSelectionEmpty(),
|
||||
isEditing,
|
||||
},
|
||||
"mx_CompoundDialog",
|
||||
false,
|
||||
true,
|
||||
|
@ -43,48 +54,86 @@ interface LinkModalProps {
|
|||
isTextEnabled: boolean;
|
||||
onClose: () => void;
|
||||
composerContext: ComposerContextState;
|
||||
isEditing: boolean;
|
||||
}
|
||||
|
||||
export function LinkModal({ composer, isTextEnabled, onClose, composerContext }: LinkModalProps) {
|
||||
const [fields, setFields] = useState({ text: "", link: "" });
|
||||
const isSaveDisabled = (isTextEnabled && isEmpty(fields.text)) || isEmpty(fields.link);
|
||||
export function LinkModal({ composer, isTextEnabled, onClose, composerContext, isEditing }: LinkModalProps) {
|
||||
const [hasLinkChanged, setHasLinkChanged] = useState(false);
|
||||
const [fields, setFields] = useState({ text: "", link: isEditing ? composer.getLink() : "" });
|
||||
const hasText = !isEditing && isTextEnabled;
|
||||
const isSaveDisabled = !hasLinkChanged || (hasText && isEmpty(fields.text)) || isEmpty(fields.link);
|
||||
|
||||
return (
|
||||
<QuestionDialog
|
||||
<BaseDialog
|
||||
className="mx_LinkModal"
|
||||
title={_td("Create a link")}
|
||||
button={_td("Save")}
|
||||
buttonDisabled={isSaveDisabled}
|
||||
hasCancelButton={true}
|
||||
onFinished={async (isClickOnSave: boolean) => {
|
||||
if (isClickOnSave) {
|
||||
title={isEditing ? _t("Edit link") : _t("Create a link")}
|
||||
hasCancel={true}
|
||||
onFinished={onClose}
|
||||
>
|
||||
<form
|
||||
className="mx_LinkModal_content"
|
||||
onSubmit={async (evt) => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
onClose();
|
||||
|
||||
// When submitting is done when pressing enter when the link field has the focus,
|
||||
// The link field is getting back the focus (due to react-focus-lock)
|
||||
// So we are waiting that the focus stuff is done to play with the composer selection
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
await setSelection(composerContext.selection);
|
||||
composer.link(fields.link, isTextEnabled ? fields.text : undefined);
|
||||
}
|
||||
onClose();
|
||||
}}
|
||||
description={
|
||||
<div className="mx_LinkModal_content">
|
||||
{isTextEnabled && (
|
||||
<Field
|
||||
autoFocus={true}
|
||||
label={_td("Text")}
|
||||
value={fields.text}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
setFields((fields) => ({ ...fields, text: e.target.value }))
|
||||
}
|
||||
/>
|
||||
)}
|
||||
}}
|
||||
>
|
||||
{hasText && (
|
||||
<Field
|
||||
autoFocus={!isTextEnabled}
|
||||
label={_td("Link")}
|
||||
value={fields.link}
|
||||
required={true}
|
||||
autoFocus={true}
|
||||
label={_t("Text")}
|
||||
value={fields.text}
|
||||
className="mx_LinkModal_Field"
|
||||
placeholder=""
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
setFields((fields) => ({ ...fields, link: e.target.value }))
|
||||
setFields((fields) => ({ ...fields, text: e.target.value }))
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Field
|
||||
required={true}
|
||||
autoFocus={!hasText}
|
||||
label={_t("Link")}
|
||||
value={fields.link}
|
||||
className="mx_LinkModal_Field"
|
||||
placeholder=""
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
setFields((fields) => ({ ...fields, link: e.target.value }));
|
||||
setHasLinkChanged(true);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="mx_LinkModal_buttons">
|
||||
{isEditing && (
|
||||
<button
|
||||
type="button"
|
||||
className="danger"
|
||||
onClick={() => {
|
||||
composer.removeLinks();
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{_t("Remove")}
|
||||
</button>
|
||||
)}
|
||||
<DialogButtons
|
||||
primaryButton={_t("Save")}
|
||||
primaryDisabled={isSaveDisabled}
|
||||
primaryIsSubmit={true}
|
||||
onCancel={onClose}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</form>
|
||||
</BaseDialog>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue