Merge remote-tracking branch 'upstream/develop' into fix/12652/screen-share

This commit is contained in:
Šimon Brandner 2021-05-20 15:50:49 +02:00
commit 340bbeec4f
No known key found for this signature in database
GPG key ID: 9760693FDD98A790
9 changed files with 32 additions and 21 deletions

View file

@ -36,6 +36,7 @@ limitations under the License.
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: pre-wrap;
} }
.mx_RoomSummaryCard_avatar { .mx_RoomSummaryCard_avatar {

View file

@ -152,7 +152,7 @@ const Tile: React.FC<ITileProps> = ({
} }
let description = _t("%(count)s members", { count: room.num_joined_members }); let description = _t("%(count)s members", { count: room.num_joined_members });
if (numChildRooms) { if (numChildRooms !== undefined) {
description += " · " + _t("%(count)s rooms", { count: numChildRooms }); description += " · " + _t("%(count)s rooms", { count: numChildRooms });
} }
if (room.topic) { if (room.topic) {

View file

@ -45,6 +45,7 @@ import {ChevronFace, ContextMenuTooltipButton, useContextMenu} from "../../struc
import WidgetContextMenu from "../context_menus/WidgetContextMenu"; import WidgetContextMenu from "../context_menus/WidgetContextMenu";
import {useRoomMemberCount} from "../../../hooks/useRoomMembers"; import {useRoomMemberCount} from "../../../hooks/useRoomMembers";
import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
import RoomName from "../elements/RoomName";
interface IProps { interface IProps {
room: Room; room: Room;
@ -249,7 +250,13 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
/> />
</div> </div>
<h2 title={room.name}>{ room.name }</h2> <RoomName room={room}>
{ name => (
<h2 title={name}>
{ name }
</h2>
)}
</RoomName>
<div className="mx_RoomSummaryCard_alias" title={alias}> <div className="mx_RoomSummaryCard_alias" title={alias}>
{ alias } { alias }
</div> </div>

View file

@ -133,6 +133,12 @@ export default class MemberList extends React.Component {
} }
} }
get canInvite() {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(this.props.roomId);
return room && room.canInvite(cli.getUserId());
}
_getMembersState(members) { _getMembersState(members) {
// set the state after determining _showPresence to make sure it's // set the state after determining _showPresence to make sure it's
// taken into account while rerendering // taken into account while rerendering
@ -141,6 +147,7 @@ export default class MemberList extends React.Component {
members: members, members: members,
filteredJoinedMembers: this._filterMembers(members, 'join'), filteredJoinedMembers: this._filterMembers(members, 'join'),
filteredInvitedMembers: this._filterMembers(members, 'invite'), filteredInvitedMembers: this._filterMembers(members, 'invite'),
canInvite: this.canInvite,
// ideally we'd size this to the page height, but // ideally we'd size this to the page height, but
// in practice I find that a little constraining // in practice I find that a little constraining
@ -196,6 +203,8 @@ export default class MemberList extends React.Component {
event.getType() === "m.room.third_party_invite") { event.getType() === "m.room.third_party_invite") {
this._updateList(); this._updateList();
} }
if (this.canInvite !== this.state.canInvite) this.setState({ canInvite: this.canInvite });
}; };
_updateList = rate_limited_func(() => { _updateList = rate_limited_func(() => {
@ -455,8 +464,6 @@ export default class MemberList extends React.Component {
let inviteButton; let inviteButton;
if (room && room.getMyMembership() === 'join') { if (room && room.getMyMembership() === 'join') {
const canInvite = room.canInvite(cli.getUserId());
let inviteButtonText = _t("Invite to this room"); let inviteButtonText = _t("Invite to this room");
const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat(); const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat();
if (chat && chat.roomId === this.props.roomId) { if (chat && chat.roomId === this.props.roomId) {
@ -467,7 +474,7 @@ export default class MemberList extends React.Component {
const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
inviteButton = inviteButton =
<AccessibleButton className="mx_MemberList_invite" onClick={this.onInviteButtonClick} disabled={!canInvite}> <AccessibleButton className="mx_MemberList_invite" onClick={this.onInviteButtonClick} disabled={!this.state.canInvite}>
<span>{ inviteButtonText }</span> <span>{ inviteButtonText }</span>
</AccessibleButton>; </AccessibleButton>;
} }

View file

@ -18,6 +18,7 @@ limitations under the License.
import * as React from "react"; import * as React from "react";
import { createRef, ReactComponentElement } from "react"; import { createRef, ReactComponentElement } from "react";
import { normalize } from "matrix-js-sdk/src/utils";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import classNames from 'classnames'; import classNames from 'classnames';
import { RovingAccessibleButton, RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex"; import { RovingAccessibleButton, RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
@ -259,7 +260,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
const nameCondition = RoomListStore.instance.getFirstNameFilterCondition(); const nameCondition = RoomListStore.instance.getFirstNameFilterCondition();
if (nameCondition) { if (nameCondition) {
stateUpdates.filteredExtraTiles = this.props.extraTiles stateUpdates.filteredExtraTiles = this.props.extraTiles
.filter(t => nameCondition.matches(t.props.displayName || "")); .filter(t => nameCondition.matches(normalize(t.props.displayName || "")));
} else if (this.state.filteredExtraTiles) { } else if (this.state.filteredExtraTiles) {
stateUpdates.filteredExtraTiles = null; stateUpdates.filteredExtraTiles = null;
} }

View file

@ -344,7 +344,10 @@ export function setLanguage(preferredLangs: string | string[]) {
counterpart.registerTranslations(langToUse, langData); counterpart.registerTranslations(langToUse, langData);
counterpart.setLocale(langToUse); counterpart.setLocale(langToUse);
SettingsStore.setValue("language", null, SettingLevel.DEVICE, langToUse); SettingsStore.setValue("language", null, SettingLevel.DEVICE, langToUse);
console.log("set language to " + langToUse); // Adds a lot of noise to test runs, so disable logging there.
if (process.env.NODE_ENV !== "test") {
console.log("set language to " + langToUse);
}
// Set 'en' as fallback language: // Set 'en' as fallback language:
if (langToUse !== "en") { if (langToUse !== "en") {

View file

@ -17,7 +17,7 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition"; import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { removeHiddenChars } from "matrix-js-sdk/src/utils"; import { normalize } from "matrix-js-sdk/src/utils";
import { throttle } from "lodash"; import { throttle } from "lodash";
/** /**
@ -62,20 +62,10 @@ export class NameFilterCondition extends EventEmitter implements IFilterConditio
if (!room.name) return false; // should realistically not happen: the js-sdk always calculates a name if (!room.name) return false; // should realistically not happen: the js-sdk always calculates a name
return this.matches(room.name); return this.matches(room.normalizedName);
} }
private normalize(val: string): string { public matches(normalizedName: string): boolean {
// Note: we have to match the filter with the removeHiddenChars() room name because the return normalizedName.includes(normalize(this.search));
// function strips spaces and other characters (M becomes RN for example, in lowercase).
return removeHiddenChars(val.toLowerCase())
// Strip all punctuation
.replace(/[\\'!"#$%&()*+,\-./:;<=>?@[\]^_`{|}~\u2000-\u206f\u2e00-\u2e7f]/g, "")
// We also doubly convert to lowercase to work around oddities of the library.
.toLowerCase();
}
public matches(val: string): boolean {
return this.normalize(val).includes(this.normalize(this.search));
} }
} }

View file

@ -88,6 +88,7 @@ describe('MemberList', () => {
}; };
memberListRoom.currentState = { memberListRoom.currentState = {
members: {}, members: {},
getMember: jest.fn(),
getStateEvents: (eventType, stateKey) => stateKey === undefined ? [] : null, // ignore 3pid invites getStateEvents: (eventType, stateKey) => stateKey === undefined ? [] : null, // ignore 3pid invites
}; };
for (const member of [...adminUsers, ...moderatorUsers, ...defaultUsers]) { for (const member of [...adminUsers, ...moderatorUsers, ...defaultUsers]) {

View file

@ -246,6 +246,7 @@ export function mkStubRoom(roomId = null) {
maySendMessage: jest.fn().mockReturnValue(true), maySendMessage: jest.fn().mockReturnValue(true),
currentState: { currentState: {
getStateEvents: jest.fn(), getStateEvents: jest.fn(),
getMember: jest.fn(),
mayClientSendStateEvent: jest.fn().mockReturnValue(true), mayClientSendStateEvent: jest.fn().mockReturnValue(true),
maySendStateEvent: jest.fn().mockReturnValue(true), maySendStateEvent: jest.fn().mockReturnValue(true),
maySendEvent: jest.fn().mockReturnValue(true), maySendEvent: jest.fn().mockReturnValue(true),