Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Show invite reasons
Browse files Browse the repository at this point in the history
Displays the reason for invitation in the invitation dialog, requiring a
click to reveal the message.

Signed-off-by: Robin Townsend <robin@robin.town>
  • Loading branch information
robintown committed Feb 26, 2021
1 parent 667c94b commit 6b3c374
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 31 deletions.
29 changes: 29 additions & 0 deletions res/css/views/rooms/_RoomPreviewBar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,35 @@ limitations under the License.
word-break: break-word;
}

.mx_RoomPreviewBar_reason {
text-align: left;
background-color: $primary-bg-color;
border: 1px solid $invite-reason-border-color;
border-radius: 10px;
padding: 0 16px 12px 16px;
margin: 5px 0 20px 0;

div {
pointer-events: none;
}

.mx_EventTile_msgOption {
display: none;
}

.mx_MatrixChat_useCompactLayout & {
padding-top: 9px;
}

&.mx_EventTilePreview_faded {
cursor: pointer;

.mx_SenderProfile, .mx_EventTile_avatar {
opacity: 0.3;
}
}
}

.mx_Spinner {
width: auto;
height: auto;
Expand Down
2 changes: 2 additions & 0 deletions res/themes/dark/css/_dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ $user-tile-hover-bg-color: $header-panel-bg-color;
// Appearance tab colors
$appearance-tab-border-color: $room-highlight-color;

$invite-reason-border-color: $room-highlight-color;

// blur amounts for left left panel (only for element theme, used in _mods.scss)
$roomlist-background-blur-amount: 60px;
$groupFilterPanel-background-blur-amount: 30px;
Expand Down
2 changes: 2 additions & 0 deletions res/themes/legacy-dark/css/_legacy-dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ $user-tile-hover-bg-color: $header-panel-bg-color;
// Appearance tab colors
$appearance-tab-border-color: $room-highlight-color;

$invite-reason-border-color: $room-highlight-color;

$composer-shadow-color: tranparent;

// ***** Mixins! *****
Expand Down
2 changes: 2 additions & 0 deletions res/themes/legacy-light/css/_legacy-light.scss
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ $user-tile-hover-bg-color: $header-panel-bg-color;
// FontSlider colors
$appearance-tab-border-color: $input-darker-bg-color;

$invite-reason-border-color: $input-darker-bg-color;

$composer-shadow-color: tranparent;

// ***** Mixins! *****
Expand Down
2 changes: 2 additions & 0 deletions res/themes/light/css/_light.scss
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ $user-tile-hover-bg-color: $header-panel-bg-color;
// FontSlider colors
$appearance-tab-border-color: $input-darker-bg-color;

$invite-reason-border-color: $input-darker-bg-color;

// blur amounts for left left panel (only for element theme, used in _mods.scss)
$roomlist-background-blur-amount: 40px;
$groupFilterPanel-background-blur-amount: 20px;
Expand Down
86 changes: 55 additions & 31 deletions src/components/views/elements/EventTilePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import classnames from 'classnames';
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';

import * as Avatar from '../../../Avatar';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import EventTile from '../rooms/EventTile';
import SettingsStore from "../../../settings/SettingsStore";
import {Layout} from "../../../settings/Layout";
Expand All @@ -40,61 +39,84 @@ interface IProps {
* classnames to apply to the wrapper of the preview
*/
className: string;

/**
* The ID of the displayed user
*/
userId: string;

/**
* The display name of the displayed user
*/
displayName?: string;

/**
* The mxc:// avatar URL of the displayed user
*/
avatarUrl?: string;

/**
* Whether the EventTile should appear faded
*/
faded?: boolean;

/**
* Callback for when the component is clicked
*/
onClick?: () => void;
}

/* eslint-disable camelcase */
interface IState {
userId: string;
displayname: string;
avatar_url: string;
message: string;
faded: boolean;
eventTileKey: number;
}
/* eslint-enable camelcase */

const AVATAR_SIZE = 32;

export default class EventTilePreview extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);

this.state = {
userId: "@erim:fink.fink",
displayname: "Erimayas Fink",
avatar_url: null,
message: props.message,
faded: !!props.faded,
eventTileKey: 0,
};
}

async componentDidMount() {
// Fetch current user data
const client = MatrixClientPeg.get();
const userId = client.getUserId();
const profileInfo = await client.getProfileInfo(userId);
const avatarUrl = Avatar.avatarUrlForUser(
{avatarUrl: profileInfo.avatar_url},
AVATAR_SIZE, AVATAR_SIZE, "crop");

changeMessage(message: string) {
this.setState({
userId,
displayname: profileInfo.displayname,
avatar_url: avatarUrl,
message,
// Change the EventTile key to force React to create a new instance
eventTileKey: this.state.eventTileKey + 1,
});
}

private fakeEvent({userId, displayname, avatar_url: avatarUrl}: IState) {
unfade() {
this.setState({ faded: false });
}

private fakeEvent({message}: IState) {
const avatarUrl = Avatar.avatarUrlForUser(
{ avatarUrl: this.props.avatarUrl },
AVATAR_SIZE, AVATAR_SIZE, "crop",
);

// Fake it till we make it
/* eslint-disable quote-props */
const rawEvent = {
type: "m.room.message",
sender: userId,
sender: this.props.userId,
content: {
"m.new_content": {
msgtype: "m.text",
body: this.props.message,
displayname: displayname,
body: message,
displayname: this.props.displayName,
avatar_url: avatarUrl,
},
msgtype: "m.text",
body: this.props.message,
displayname: displayname,
body: message,
displayname: this.props.displayName,
avatar_url: avatarUrl,
},
unsigned: {
Expand All @@ -108,8 +130,8 @@ export default class EventTilePreview extends React.Component<IProps, IState> {

// Fake it more
event.sender = {
name: displayname,
userId: userId,
name: this.props.displayName,
userId: this.props.userId,
getAvatarUrl: (..._) => {
return avatarUrl;
},
Expand All @@ -124,10 +146,12 @@ export default class EventTilePreview extends React.Component<IProps, IState> {
const className = classnames(this.props.className, {
"mx_IRCLayout": this.props.layout == Layout.IRC,
"mx_GroupLayout": this.props.layout == Layout.Group,
"mx_EventTilePreview_faded": this.state.faded,
});

return <div className={className}>
return <div className={className} onClick={this.props.onClick}>
<EventTile
key={this.state.eventTileKey}
mxEvent={event}
layout={this.props.layout}
enableFlair={SettingsStore.getValue(UIFeature.Flair)}
Expand Down
27 changes: 27 additions & 0 deletions src/components/views/rooms/RoomPreviewBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import classNames from 'classnames';
import { _t } from '../../../languageHandler';
import SdkConfig from "../../../SdkConfig";
import IdentityAuthClient from '../../../IdentityAuthClient';
import SettingsStore from "../../../settings/SettingsStore";
import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
import {UPDATE_EVENT} from "../../../stores/AsyncStore";

Expand Down Expand Up @@ -300,10 +301,12 @@ export default class RoomPreviewBar extends React.Component {
const brand = SdkConfig.get().brand;
const Spinner = sdk.getComponent('elements.Spinner');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const EventTilePreview = sdk.getComponent('elements.EventTilePreview');

let showSpinner = false;
let title;
let subTitle;
let reasonElement;
let primaryActionHandler;
let primaryActionLabel;
let secondaryActionHandler;
Expand Down Expand Up @@ -489,6 +492,29 @@ export default class RoomPreviewBar extends React.Component {
primaryActionLabel = _t("Accept");
}

const myUserId = MatrixClientPeg.get().getUserId();
const reason = this.props.room.currentState.getMember(myUserId).events.member.event.content.reason;
if (reason) {
this.reasonElement = React.createRef();
// We hide the reason for invitation by default, since it can be a
// vector for spam/harassment.
const showReason = () => {
this.reasonElement.current.unfadeProfile();
this.reasonElement.current.changeMessage(reason);
};
reasonElement = <EventTilePreview
ref={this.reasonElement}
onClick={showReason}
className="mx_RoomPreviewBar_reason"
message={_t("Invite messages are hidden by default. Click to show the message.")}
layout={SettingsStore.getValue("layout")}
userId={inviteMember.user.userId}
displayName={inviteMember.user.displayName}
avatarUrl={inviteMember.user.avatarUrl}
faded={true}
/>;
}

primaryActionHandler = this.props.onJoinClick;
secondaryActionLabel = _t("Reject");
secondaryActionHandler = this.props.onRejectClick;
Expand Down Expand Up @@ -580,6 +606,7 @@ export default class RoomPreviewBar extends React.Component {
{ titleElement }
{ subTitleElements }
</div>
{ reasonElement }
<div className="mx_RoomPreviewBar_actions">
{ secondaryButton }
{ extraComponents }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ limitations under the License.
import React from 'react';
import {_t} from "../../../../../languageHandler";
import SdkConfig from "../../../../../SdkConfig";
import { MatrixClientPeg } from '../../../../../MatrixClientPeg';
import SettingsStore from "../../../../../settings/SettingsStore";
import { enumerateThemes } from "../../../../../theme";
import ThemeWatcher from "../../../../../settings/watchers/ThemeWatcher";
Expand Down Expand Up @@ -62,6 +63,10 @@ interface IState extends IThemeState {
systemFont: string;
showAdvanced: boolean;
layout: Layout;
// User profile data for the message preview
userId: string;
displayName: string;
avatarUrl: string;
}


Expand All @@ -83,9 +88,26 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
systemFont: SettingsStore.getValue("systemFont"),
showAdvanced: false,
layout: SettingsStore.getValue("layout"),
userId: "@erim:fink.fink",
displayName: "Erimayas Fink",
avatarUrl: null,
};
}

async componentDidMount() {
// Fetch the current user profile for the message preview
const client = MatrixClientPeg.get();
const userId = client.getUserId();
const profileInfo = await client.getProfileInfo(userId);

this.setState({
...this.state,
userId,
displayName: profileInfo.displayname,
avatarUrl: profileInfo.avatar_url,
});
}

private calculateThemeState(): IThemeState {
// We have to mirror the logic from ThemeWatcher.getEffectiveTheme so we
// show the right values for things.
Expand Down Expand Up @@ -306,6 +328,9 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
className="mx_AppearanceUserSettingsTab_fontSlider_preview"
message={this.MESSAGE_PREVIEW_TEXT}
layout={this.state.layout}
userId={this.state.userId}
displayName={this.state.displayName}
avatarUrl={this.state.avatarUrl}
/>
<div className="mx_AppearanceUserSettingsTab_fontSlider">
<div className="mx_AppearanceUserSettingsTab_fontSlider_smallText">Aa</div>
Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,7 @@
"Start chatting": "Start chatting",
"Do you want to join %(roomName)s?": "Do you want to join %(roomName)s?",
"<userName/> invited you": "<userName/> invited you",
"Invite messages are hidden by default. Click to show the message.": "Invite messages are hidden by default. Click to show the message.",
"Reject": "Reject",
"Reject & Ignore user": "Reject & Ignore user",
"You're previewing %(roomName)s. Want to join it?": "You're previewing %(roomName)s. Want to join it?",
Expand Down

0 comments on commit 6b3c374

Please sign in to comment.