Merge pull request #6838 from SimonBrandner/task/room_settings-ts

pull/21833/head
Germain 2021-09-20 14:52:40 +01:00 committed by GitHub
commit e4e696f409
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 54 deletions

View File

@ -15,27 +15,43 @@ limitations under the License.
*/ */
import React, { createRef } from 'react'; import React, { createRef } from 'react';
import PropTypes from 'prop-types';
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import Field from "../elements/Field"; import Field from "../elements/Field";
import * as sdk from "../../../index";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import { mediaFromMxc } from "../../../customisations/Media"; import { mediaFromMxc } from "../../../customisations/Media";
import AccessibleButton from "../elements/AccessibleButton";
import AvatarSetting from "../settings/AvatarSetting";
interface IProps {
roomId: string;
}
interface IState {
originalDisplayName: string;
displayName: string;
originalAvatarUrl: string;
avatarUrl: string;
avatarFile: File;
originalTopic: string;
topic: string;
enableProfileSave: boolean;
canSetName: boolean;
canSetTopic: boolean;
canSetAvatar: boolean;
}
// TODO: Merge with ProfileSettings? // TODO: Merge with ProfileSettings?
@replaceableComponent("views.room_settings.RoomProfileSettings") @replaceableComponent("views.room_settings.RoomProfileSettings")
export default class RoomProfileSettings extends React.Component { export default class RoomProfileSettings extends React.Component<IProps, IState> {
static propTypes = { private avatarUpload = createRef<HTMLInputElement>();
roomId: PropTypes.string.isRequired,
};
constructor(props) { constructor(props: IProps) {
super(props); super(props);
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
const room = client.getRoom(props.roomId); const room = client.getRoom(props.roomId);
if (!room) throw new Error("Expected a room for ID: ", props.roomId); if (!room) throw new Error(`Expected a room for ID: ${props.roomId}`);
const avatarEvent = room.currentState.getStateEvents("m.room.avatar", ""); const avatarEvent = room.currentState.getStateEvents("m.room.avatar", "");
let avatarUrl = avatarEvent && avatarEvent.getContent() ? avatarEvent.getContent()["url"] : null; let avatarUrl = avatarEvent && avatarEvent.getContent() ? avatarEvent.getContent()["url"] : null;
@ -60,17 +76,15 @@ export default class RoomProfileSettings extends React.Component {
canSetTopic: room.currentState.maySendStateEvent('m.room.topic', client.getUserId()), canSetTopic: room.currentState.maySendStateEvent('m.room.topic', client.getUserId()),
canSetAvatar: room.currentState.maySendStateEvent('m.room.avatar', client.getUserId()), canSetAvatar: room.currentState.maySendStateEvent('m.room.avatar', client.getUserId()),
}; };
this._avatarUpload = createRef();
} }
_uploadAvatar = () => { private uploadAvatar = (): void => {
this._avatarUpload.current.click(); this.avatarUpload.current.click();
}; };
_removeAvatar = () => { private removeAvatar = (): void => {
// clear file upload field so same file can be selected // clear file upload field so same file can be selected
this._avatarUpload.current.value = ""; this.avatarUpload.current.value = "";
this.setState({ this.setState({
avatarUrl: null, avatarUrl: null,
avatarFile: null, avatarFile: null,
@ -78,7 +92,7 @@ export default class RoomProfileSettings extends React.Component {
}); });
}; };
_cancelProfileChanges = async (e) => { private cancelProfileChanges = async (e: React.MouseEvent): Promise<void> => {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
@ -92,7 +106,7 @@ export default class RoomProfileSettings extends React.Component {
}); });
}; };
_saveProfile = async (e) => { private saveProfile = async (e: React.FormEvent): Promise<void> => {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
@ -100,35 +114,46 @@ export default class RoomProfileSettings extends React.Component {
this.setState({ enableProfileSave: false }); this.setState({ enableProfileSave: false });
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
const newState = {};
let originalDisplayName: string;
let avatarUrl: string;
let originalAvatarUrl: string;
let originalTopic: string;
let avatarFile: File;
// TODO: What do we do about errors? // TODO: What do we do about errors?
const displayName = this.state.displayName.trim(); const displayName = this.state.displayName.trim();
if (this.state.originalDisplayName !== this.state.displayName) { if (this.state.originalDisplayName !== this.state.displayName) {
await client.setRoomName(this.props.roomId, displayName); await client.setRoomName(this.props.roomId, displayName);
newState.originalDisplayName = displayName; originalDisplayName = displayName;
newState.displayName = displayName;
} }
if (this.state.avatarFile) { if (this.state.avatarFile) {
const uri = await client.uploadContent(this.state.avatarFile); const uri = await client.uploadContent(this.state.avatarFile);
await client.sendStateEvent(this.props.roomId, 'm.room.avatar', { url: uri }, ''); await client.sendStateEvent(this.props.roomId, 'm.room.avatar', { url: uri }, '');
newState.avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96); avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96);
newState.originalAvatarUrl = newState.avatarUrl; originalAvatarUrl = avatarUrl;
newState.avatarFile = null; avatarFile = null;
} else if (this.state.originalAvatarUrl !== this.state.avatarUrl) { } else if (this.state.originalAvatarUrl !== this.state.avatarUrl) {
await client.sendStateEvent(this.props.roomId, 'm.room.avatar', {}, ''); await client.sendStateEvent(this.props.roomId, 'm.room.avatar', {}, '');
} }
if (this.state.originalTopic !== this.state.topic) { if (this.state.originalTopic !== this.state.topic) {
await client.setRoomTopic(this.props.roomId, this.state.topic); await client.setRoomTopic(this.props.roomId, this.state.topic);
newState.originalTopic = this.state.topic; originalTopic = this.state.topic;
} }
this.setState(newState); this.setState({
originalAvatarUrl,
avatarUrl,
originalDisplayName,
originalTopic,
displayName,
avatarFile,
});
}; };
_onDisplayNameChanged = (e) => { private onDisplayNameChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({ displayName: e.target.value }); this.setState({ displayName: e.target.value });
if (this.state.originalDisplayName === e.target.value) { if (this.state.originalDisplayName === e.target.value) {
this.setState({ enableProfileSave: false }); this.setState({ enableProfileSave: false });
@ -137,7 +162,7 @@ export default class RoomProfileSettings extends React.Component {
} }
}; };
_onTopicChanged = (e) => { private onTopicChanged = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {
this.setState({ topic: e.target.value }); this.setState({ topic: e.target.value });
if (this.state.originalTopic === e.target.value) { if (this.state.originalTopic === e.target.value) {
this.setState({ enableProfileSave: false }); this.setState({ enableProfileSave: false });
@ -146,7 +171,7 @@ export default class RoomProfileSettings extends React.Component {
} }
}; };
_onAvatarChanged = (e) => { private onAvatarChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
if (!e.target.files || !e.target.files.length) { if (!e.target.files || !e.target.files.length) {
this.setState({ this.setState({
avatarUrl: this.state.originalAvatarUrl, avatarUrl: this.state.originalAvatarUrl,
@ -160,7 +185,7 @@ export default class RoomProfileSettings extends React.Component {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (ev) => { reader.onload = (ev) => {
this.setState({ this.setState({
avatarUrl: ev.target.result, avatarUrl: String(ev.target.result),
avatarFile: file, avatarFile: file,
enableProfileSave: true, enableProfileSave: true,
}); });
@ -168,10 +193,7 @@ export default class RoomProfileSettings extends React.Component {
reader.readAsDataURL(file); reader.readAsDataURL(file);
}; };
render() { public render(): JSX.Element {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const AvatarSetting = sdk.getComponent('settings.AvatarSetting');
let profileSettingsButtons; let profileSettingsButtons;
if ( if (
this.state.canSetName || this.state.canSetName ||
@ -181,14 +203,14 @@ export default class RoomProfileSettings extends React.Component {
profileSettingsButtons = ( profileSettingsButtons = (
<div className="mx_ProfileSettings_buttons"> <div className="mx_ProfileSettings_buttons">
<AccessibleButton <AccessibleButton
onClick={this._cancelProfileChanges} onClick={this.cancelProfileChanges}
kind="link" kind="link"
disabled={!this.state.enableProfileSave} disabled={!this.state.enableProfileSave}
> >
{ _t("Cancel") } { _t("Cancel") }
</AccessibleButton> </AccessibleButton>
<AccessibleButton <AccessibleButton
onClick={this._saveProfile} onClick={this.saveProfile}
kind="primary" kind="primary"
disabled={!this.state.enableProfileSave} disabled={!this.state.enableProfileSave}
> >
@ -200,16 +222,16 @@ export default class RoomProfileSettings extends React.Component {
return ( return (
<form <form
onSubmit={this._saveProfile} onSubmit={this.saveProfile}
autoComplete="off" autoComplete="off"
noValidate={true} noValidate={true}
className="mx_ProfileSettings_profileForm" className="mx_ProfileSettings_profileForm"
> >
<input <input
type="file" type="file"
ref={this._avatarUpload} ref={this.avatarUpload}
className="mx_ProfileSettings_avatarUpload" className="mx_ProfileSettings_avatarUpload"
onChange={this._onAvatarChanged} onChange={this.onAvatarChanged}
accept="image/*" accept="image/*"
/> />
<div className="mx_ProfileSettings_profile"> <div className="mx_ProfileSettings_profile">
@ -219,7 +241,7 @@ export default class RoomProfileSettings extends React.Component {
type="text" type="text"
value={this.state.displayName} value={this.state.displayName}
autoComplete="off" autoComplete="off"
onChange={this._onDisplayNameChanged} onChange={this.onDisplayNameChanged}
disabled={!this.state.canSetName} disabled={!this.state.canSetName}
/> />
<Field <Field
@ -230,7 +252,7 @@ export default class RoomProfileSettings extends React.Component {
type="text" type="text"
value={this.state.topic} value={this.state.topic}
autoComplete="off" autoComplete="off"
onChange={this._onTopicChanged} onChange={this.onTopicChanged}
element="textarea" element="textarea"
/> />
</div> </div>
@ -238,8 +260,8 @@ export default class RoomProfileSettings extends React.Component {
avatarUrl={this.state.avatarUrl} avatarUrl={this.state.avatarUrl}
avatarName={this.state.displayName || this.props.roomId} avatarName={this.state.displayName || this.props.roomId}
avatarAltText={_t("Room avatar")} avatarAltText={_t("Room avatar")}
uploadAvatar={this.state.canSetAvatar ? this._uploadAvatar : undefined} uploadAvatar={this.state.canSetAvatar ? this.uploadAvatar : undefined}
removeAvatar={this.state.canSetAvatar ? this._removeAvatar : undefined} /> removeAvatar={this.state.canSetAvatar ? this.removeAvatar : undefined} />
</div> </div>
{ profileSettingsButtons } { profileSettingsButtons }
</form> </form>

View File

@ -18,8 +18,6 @@ limitations under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import * as sdk from "../../../index";
import { _t, _td } from '../../../languageHandler'; import { _t, _td } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
@ -27,21 +25,22 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import { SettingLevel } from "../../../settings/SettingLevel"; import { SettingLevel } from "../../../settings/SettingLevel";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import { Room } from "matrix-js-sdk/src/models/room";
import SettingsFlag from "../elements/SettingsFlag";
interface IProps {
room: Room;
}
@replaceableComponent("views.room_settings.UrlPreviewSettings") @replaceableComponent("views.room_settings.UrlPreviewSettings")
export default class UrlPreviewSettings extends React.Component { export default class UrlPreviewSettings extends React.Component<IProps> {
static propTypes = { private onClickUserSettings = (e: React.MouseEvent): void => {
room: PropTypes.object,
};
_onClickUserSettings = (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
dis.fire(Action.ViewUserSettings); dis.fire(Action.ViewUserSettings);
}; };
render() { public render(): JSX.Element {
const SettingsFlag = sdk.getComponent("elements.SettingsFlag");
const roomId = this.props.room.roomId; const roomId = this.props.room.roomId;
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId); const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
@ -54,18 +53,18 @@ export default class UrlPreviewSettings extends React.Component {
if (accountEnabled) { if (accountEnabled) {
previewsForAccount = ( previewsForAccount = (
_t("You have <a>enabled</a> URL previews by default.", {}, { _t("You have <a>enabled</a> URL previews by default.", {}, {
'a': (sub)=><a onClick={this._onClickUserSettings} href=''>{ sub }</a>, 'a': (sub)=><a onClick={this.onClickUserSettings} href=''>{ sub }</a>,
}) })
); );
} else { } else {
previewsForAccount = ( previewsForAccount = (
_t("You have <a>disabled</a> URL previews by default.", {}, { _t("You have <a>disabled</a> URL previews by default.", {}, {
'a': (sub)=><a onClick={this._onClickUserSettings} href=''>{ sub }</a>, 'a': (sub)=><a onClick={this.onClickUserSettings} href=''>{ sub }</a>,
}) })
); );
} }
if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, "room")) { if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, SettingLevel.ROOM)) {
previewsForRoom = ( previewsForRoom = (
<label> <label>
<SettingsFlag <SettingsFlag