Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/types/react
This commit is contained in:
commit
42d33cf091
39 changed files with 442 additions and 242 deletions
|
@ -19,49 +19,68 @@ limitations under the License.
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
background-color: $settings-profile-placeholder-bg-color;
|
background-color: $settings-profile-placeholder-bg-color;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
display: flex;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
> div {
|
.mx_BetaCard_columns {
|
||||||
.mx_BetaCard_title {
|
display: flex;
|
||||||
font-weight: $font-semi-bold;
|
|
||||||
font-size: $font-18px;
|
|
||||||
line-height: $font-22px;
|
|
||||||
color: $primary-fg-color;
|
|
||||||
margin: 4px 0 14px;
|
|
||||||
|
|
||||||
.mx_BetaCard_betaPill {
|
> div {
|
||||||
margin-left: 12px;
|
.mx_BetaCard_title {
|
||||||
|
font-weight: $font-semi-bold;
|
||||||
|
font-size: $font-18px;
|
||||||
|
line-height: $font-22px;
|
||||||
|
color: $primary-fg-color;
|
||||||
|
margin: 4px 0 14px;
|
||||||
|
|
||||||
|
.mx_BetaCard_betaPill {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_BetaCard_caption {
|
||||||
|
font-size: $font-15px;
|
||||||
|
line-height: $font-20px;
|
||||||
|
color: $secondary-fg-color;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_BetaCard_buttons .mx_AccessibleButton {
|
||||||
|
display: block;
|
||||||
|
margin: 12px 0;
|
||||||
|
padding: 7px 40px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_BetaCard_disclaimer {
|
||||||
|
font-size: $font-12px;
|
||||||
|
line-height: $font-15px;
|
||||||
|
color: $secondary-fg-color;
|
||||||
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_BetaCard_caption {
|
> img {
|
||||||
font-size: $font-15px;
|
margin: auto 0 auto 20px;
|
||||||
line-height: $font-20px;
|
width: 300px;
|
||||||
color: $secondary-fg-color;
|
object-fit: contain;
|
||||||
margin-bottom: 20px;
|
height: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
.mx_AccessibleButton {
|
|
||||||
display: block;
|
|
||||||
margin: 12px 0;
|
|
||||||
padding: 7px 40px;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_BetaCard_disclaimer {
|
|
||||||
font-size: $font-12px;
|
|
||||||
line-height: $font-15px;
|
|
||||||
color: $secondary-fg-color;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> img {
|
.mx_BetaCard_relatedSettings {
|
||||||
margin: auto 0 auto 20px;
|
.mx_SettingsFlag {
|
||||||
width: 300px;
|
margin: 16px 0 0;
|
||||||
object-fit: contain;
|
font-size: $font-15px;
|
||||||
height: 100%;
|
line-height: $font-24px;
|
||||||
|
color: $primary-fg-color;
|
||||||
|
|
||||||
|
.mx_SettingsFlag_microcopy {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: $font-12px;
|
||||||
|
line-height: $font-15px;
|
||||||
|
color: $secondary-fg-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
src/@types/global.d.ts
vendored
13
src/@types/global.d.ts
vendored
|
@ -113,19 +113,6 @@ declare global {
|
||||||
usageDetails?: {[key: string]: number};
|
usageDetails?: {[key: string]: number};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISettledFulfilled<T> {
|
|
||||||
status: "fulfilled";
|
|
||||||
value: T;
|
|
||||||
}
|
|
||||||
export interface ISettledRejected {
|
|
||||||
status: "rejected";
|
|
||||||
reason: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PromiseConstructor {
|
|
||||||
allSettled<T>(promises: Promise<T>[]): Promise<Array<ISettledFulfilled<T> | ISettledRejected>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HTMLAudioElement {
|
interface HTMLAudioElement {
|
||||||
type?: string;
|
type?: string;
|
||||||
// sinkId & setSinkId are experimental and typescript doesn't know about them
|
// sinkId & setSinkId are experimental and typescript doesn't know about them
|
||||||
|
|
|
@ -17,13 +17,12 @@ limitations under the License.
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
import { User } from "matrix-js-sdk/src/models/user";
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { ResizeMethod } from "matrix-js-sdk/src/@types/partials";
|
||||||
|
|
||||||
import DMRoomMap from './utils/DMRoomMap';
|
import DMRoomMap from './utils/DMRoomMap';
|
||||||
import { mediaFromMxc } from "./customisations/Media";
|
import { mediaFromMxc } from "./customisations/Media";
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
|
|
||||||
export type ResizeMethod = "crop" | "scale";
|
|
||||||
|
|
||||||
// Not to be used for BaseAvatar urls as that has similar default avatar fallback already
|
// Not to be used for BaseAvatar urls as that has similar default avatar fallback already
|
||||||
export function avatarUrlForMember(
|
export function avatarUrlForMember(
|
||||||
member: RoomMember,
|
member: RoomMember,
|
||||||
|
|
|
@ -17,8 +17,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
|
|
||||||
import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers';
|
import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers';
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||||
|
@ -1019,9 +1019,8 @@ export const Commands = [
|
||||||
const member = MatrixClientPeg.get().getRoom(roomId).getMember(userId);
|
const member = MatrixClientPeg.get().getRoom(roomId).getMember(userId);
|
||||||
dis.dispatch<ViewUserPayload>({
|
dis.dispatch<ViewUserPayload>({
|
||||||
action: Action.ViewUser,
|
action: Action.ViewUser,
|
||||||
// XXX: We should be using a real member object and not assuming what the
|
// XXX: We should be using a real member object and not assuming what the receiver wants.
|
||||||
// receiver wants.
|
member: member || { userId } as User,
|
||||||
member: member || {userId},
|
|
||||||
});
|
});
|
||||||
return success();
|
return success();
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,8 +15,9 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ReactElement} from 'react';
|
import { ReactElement } from 'react';
|
||||||
import Room from 'matrix-js-sdk/src/models/room';
|
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||||
|
|
||||||
import CommandProvider from './CommandProvider';
|
import CommandProvider from './CommandProvider';
|
||||||
import CommunityProvider from './CommunityProvider';
|
import CommunityProvider from './CommunityProvider';
|
||||||
import DuckDuckGoProvider from './DuckDuckGoProvider';
|
import DuckDuckGoProvider from './DuckDuckGoProvider';
|
||||||
|
@ -24,7 +25,7 @@ import RoomProvider from './RoomProvider';
|
||||||
import UserProvider from './UserProvider';
|
import UserProvider from './UserProvider';
|
||||||
import EmojiProvider from './EmojiProvider';
|
import EmojiProvider from './EmojiProvider';
|
||||||
import NotifProvider from './NotifProvider';
|
import NotifProvider from './NotifProvider';
|
||||||
import {timeout} from "../utils/promise";
|
import { timeout } from "../utils/promise";
|
||||||
import AutocompleteProvider, {ICommand} from "./AutocompleteProvider";
|
import AutocompleteProvider, {ICommand} from "./AutocompleteProvider";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import SpaceProvider from "./SpaceProvider";
|
import SpaceProvider from "./SpaceProvider";
|
||||||
|
|
|
@ -15,7 +15,8 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Room from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
import {MatrixClientPeg} from '../MatrixClientPeg';
|
||||||
|
|
|
@ -17,16 +17,16 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {uniqBy, sortBy} from "lodash";
|
import { uniqBy, sortBy } from "lodash";
|
||||||
import Room from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||||
import QueryMatcher from './QueryMatcher';
|
import QueryMatcher from './QueryMatcher';
|
||||||
import {PillCompletion} from './Components';
|
import { PillCompletion } from './Components';
|
||||||
import {makeRoomPermalink} from "../utils/permalinks/Permalinks";
|
import { makeRoomPermalink } from "../utils/permalinks/Permalinks";
|
||||||
import {ICompletion, ISelectionRange} from "./Autocompleter";
|
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||||
import RoomAvatar from '../components/views/avatars/RoomAvatar';
|
import RoomAvatar from '../components/views/avatars/RoomAvatar';
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { createRef } from 'react';
|
import React, { createRef } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { IRecommendedVersion, NotificationCountType, Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { SearchResult } from "matrix-js-sdk/src/models/search-result";
|
import { SearchResult } from "matrix-js-sdk/src/models/search-result";
|
||||||
import { EventSubscription } from "fbemitter";
|
import { EventSubscription } from "fbemitter";
|
||||||
|
@ -172,11 +172,7 @@ export interface IState {
|
||||||
// We load this later by asking the js-sdk to suggest a version for us.
|
// We load this later by asking the js-sdk to suggest a version for us.
|
||||||
// This object is the result of Room#getRecommendedVersion()
|
// This object is the result of Room#getRecommendedVersion()
|
||||||
|
|
||||||
upgradeRecommendation?: {
|
upgradeRecommendation?: IRecommendedVersion;
|
||||||
version: string;
|
|
||||||
needsUpgrade: boolean;
|
|
||||||
urgent: boolean;
|
|
||||||
};
|
|
||||||
canReact: boolean;
|
canReact: boolean;
|
||||||
canReply: boolean;
|
canReply: boolean;
|
||||||
layout: Layout;
|
layout: Layout;
|
||||||
|
@ -2058,7 +2054,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
if (!this.state.atEndOfLiveTimeline && !this.state.searchResults) {
|
if (!this.state.atEndOfLiveTimeline && !this.state.searchResults) {
|
||||||
const JumpToBottomButton = sdk.getComponent('rooms.JumpToBottomButton');
|
const JumpToBottomButton = sdk.getComponent('rooms.JumpToBottomButton');
|
||||||
jumpToBottom = (<JumpToBottomButton
|
jumpToBottom = (<JumpToBottomButton
|
||||||
highlight={this.state.room.getUnreadNotificationCount('highlight') > 0}
|
highlight={this.state.room.getUnreadNotificationCount(NotificationCountType.Highlight) > 0}
|
||||||
numUnreadMessages={this.state.numUnreadMessages}
|
numUnreadMessages={this.state.numUnreadMessages}
|
||||||
onScrollToBottomClick={this.jumpToLiveTimeline}
|
onScrollToBottomClick={this.jumpToLiveTimeline}
|
||||||
roomId={this.state.roomId}
|
roomId={this.state.roomId}
|
||||||
|
|
|
@ -17,16 +17,17 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useCallback, useContext, useEffect, useState} from 'react';
|
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials';
|
||||||
|
|
||||||
import * as AvatarLogic from '../../../Avatar';
|
import * as AvatarLogic from '../../../Avatar';
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
import RoomContext from "../../../contexts/RoomContext";
|
import RoomContext from "../../../contexts/RoomContext";
|
||||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||||
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||||
import {toPx} from "../../../utils/units";
|
import { toPx } from "../../../utils/units";
|
||||||
import {ResizeMethod} from "../../../Avatar";
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
|
|
@ -15,10 +15,11 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials';
|
||||||
|
|
||||||
import BaseAvatar from './BaseAvatar';
|
import BaseAvatar from './BaseAvatar';
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import {mediaFromMxc} from "../../../customisations/Media";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
import {ResizeMethod} from "../../../Avatar";
|
|
||||||
|
|
||||||
export interface IProps {
|
export interface IProps {
|
||||||
groupId?: string;
|
groupId?: string;
|
||||||
|
|
|
@ -16,14 +16,14 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {RoomMember} from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
|
import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials';
|
||||||
|
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import {Action} from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import BaseAvatar from "./BaseAvatar";
|
import BaseAvatar from "./BaseAvatar";
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import {mediaFromMxc} from "../../../customisations/Media";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
import {ResizeMethod} from "../../../Avatar";
|
|
||||||
|
|
||||||
interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url"> {
|
interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url"> {
|
||||||
member: RoomMember;
|
member: RoomMember;
|
||||||
|
|
|
@ -13,17 +13,17 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
import React, {ComponentProps} from 'react';
|
import React, { ComponentProps } from 'react';
|
||||||
import Room from 'matrix-js-sdk/src/models/room';
|
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||||
|
import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials';
|
||||||
|
|
||||||
import BaseAvatar from './BaseAvatar';
|
import BaseAvatar from './BaseAvatar';
|
||||||
import ImageView from '../elements/ImageView';
|
import ImageView from '../elements/ImageView';
|
||||||
import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
import * as Avatar from '../../../Avatar';
|
import * as Avatar from '../../../Avatar';
|
||||||
import {ResizeMethod} from "../../../Avatar";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
import {mediaFromMxc} from "../../../customisations/Media";
|
|
||||||
|
|
||||||
interface IProps extends Omit<ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url" | "onClick"> {
|
interface IProps extends Omit<ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url" | "onClick"> {
|
||||||
// Room may be left unset here, but if it is,
|
// Room may be left unset here, but if it is,
|
||||||
|
|
|
@ -25,6 +25,7 @@ import TextWithTooltip from "../elements/TextWithTooltip";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import BetaFeedbackDialog from "../dialogs/BetaFeedbackDialog";
|
import BetaFeedbackDialog from "../dialogs/BetaFeedbackDialog";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
|
import SettingsFlag from "../elements/SettingsFlag";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
@ -66,7 +67,7 @@ const BetaCard = ({ title: titleOverride, featureId }: IProps) => {
|
||||||
const info = SettingsStore.getBetaInfo(featureId);
|
const info = SettingsStore.getBetaInfo(featureId);
|
||||||
if (!info) return null; // Beta is invalid/disabled
|
if (!info) return null; // Beta is invalid/disabled
|
||||||
|
|
||||||
const { title, caption, disclaimer, image, feedbackLabel, feedbackSubheading } = info;
|
const { title, caption, disclaimer, image, feedbackLabel, feedbackSubheading, extraSettings } = info;
|
||||||
const value = SettingsStore.getValue(featureId);
|
const value = SettingsStore.getValue(featureId);
|
||||||
|
|
||||||
let feedbackButton;
|
let feedbackButton;
|
||||||
|
@ -82,26 +83,33 @@ const BetaCard = ({ title: titleOverride, featureId }: IProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="mx_BetaCard">
|
return <div className="mx_BetaCard">
|
||||||
<div>
|
<div className="mx_BetaCard_columns">
|
||||||
<h3 className="mx_BetaCard_title">
|
|
||||||
{ titleOverride || _t(title) }
|
|
||||||
<BetaPill />
|
|
||||||
</h3>
|
|
||||||
<span className="mx_BetaCard_caption">{ _t(caption) }</span>
|
|
||||||
<div>
|
<div>
|
||||||
{ feedbackButton }
|
<h3 className="mx_BetaCard_title">
|
||||||
<AccessibleButton
|
{ titleOverride || _t(title) }
|
||||||
onClick={() => SettingsStore.setValue(featureId, null, SettingLevel.DEVICE, !value)}
|
<BetaPill />
|
||||||
kind={feedbackButton ? "primary_outline" : "primary"}
|
</h3>
|
||||||
>
|
<span className="mx_BetaCard_caption">{ _t(caption) }</span>
|
||||||
{ value ? _t("Leave the beta") : _t("Join the beta") }
|
<div className="mx_BetaCard_buttons">
|
||||||
</AccessibleButton>
|
{ feedbackButton }
|
||||||
|
<AccessibleButton
|
||||||
|
onClick={() => SettingsStore.setValue(featureId, null, SettingLevel.DEVICE, !value)}
|
||||||
|
kind={feedbackButton ? "primary_outline" : "primary"}
|
||||||
|
>
|
||||||
|
{ value ? _t("Leave the beta") : _t("Join the beta") }
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
{ disclaimer && <div className="mx_BetaCard_disclaimer">
|
||||||
|
{ disclaimer(value) }
|
||||||
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
{ disclaimer && <div className="mx_BetaCard_disclaimer">
|
<img src={image} alt="" />
|
||||||
{ disclaimer(value) }
|
|
||||||
</div> }
|
|
||||||
</div>
|
</div>
|
||||||
<img src={image} alt="" />
|
{ extraSettings && <div className="mx_BetaCard_relatedSettings">
|
||||||
|
{ extraSettings.map(key => (
|
||||||
|
<SettingsFlag key={key} name={key} level={SettingLevel.DEVICE} />
|
||||||
|
)) }
|
||||||
|
</div> }
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,12 @@ const BetaFeedbackDialog: React.FC<IProps> = ({featureId, onFinished}) => {
|
||||||
const sendFeedback = async (ok: boolean) => {
|
const sendFeedback = async (ok: boolean) => {
|
||||||
if (!ok) return onFinished(false);
|
if (!ok) return onFinished(false);
|
||||||
|
|
||||||
submitFeedback(SdkConfig.get().bug_report_endpoint_url, info.feedbackLabel, comment, canContact);
|
const extraData = SettingsStore.getBetaInfo(featureId)?.extraSettings.reduce((o, k) => {
|
||||||
|
o[k] = SettingsStore.getValue(k);
|
||||||
|
return o;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
submitFeedback(SdkConfig.get().bug_report_endpoint_url, info.feedbackLabel, comment, canContact, extraData);
|
||||||
onFinished(true);
|
onFinished(true);
|
||||||
|
|
||||||
Modal.createTrackedDialog("Beta Dialog Sent", featureId, InfoDialog, {
|
Modal.createTrackedDialog("Beta Dialog Sent", featureId, InfoDialog, {
|
||||||
|
|
|
@ -14,10 +14,10 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {useEffect, useState} from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import {Room} from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -34,7 +34,7 @@ const RoomName = ({ room, children }: IProps): JSX.Element => {
|
||||||
}, [room]);
|
}, [room]);
|
||||||
|
|
||||||
if (children) return children(name);
|
if (children) return children(name);
|
||||||
return name || "";
|
return <>{ name || "" }</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RoomName;
|
export default RoomName;
|
||||||
|
|
|
@ -77,9 +77,10 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
|
||||||
public render() {
|
public render() {
|
||||||
const canChange = SettingsStore.canSetValue(this.props.name, this.props.roomId, this.props.level);
|
const canChange = SettingsStore.canSetValue(this.props.name, this.props.roomId, this.props.level);
|
||||||
|
|
||||||
let label = this.props.label;
|
const label = this.props.label
|
||||||
if (!label) label = SettingsStore.getDisplayName(this.props.name, this.props.level);
|
? _t(this.props.label)
|
||||||
else label = _t(label);
|
: SettingsStore.getDisplayName(this.props.name, this.props.level);
|
||||||
|
const description = SettingsStore.getDescription(this.props.name);
|
||||||
|
|
||||||
if (this.props.useCheckbox) {
|
if (this.props.useCheckbox) {
|
||||||
return <StyledCheckbox
|
return <StyledCheckbox
|
||||||
|
@ -99,6 +100,9 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
|
||||||
disabled={this.props.disabled || !canChange}
|
disabled={this.props.disabled || !canChange}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
/>
|
/>
|
||||||
|
{ description && <div className="mx_SettingsFlag_microcopy">
|
||||||
|
{ description }
|
||||||
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,28 +14,29 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useCallback, useEffect, useState} from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
|
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
|
import { PHASE_REQUESTED, PHASE_UNSENT } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
|
|
||||||
import EncryptionInfo from "./EncryptionInfo";
|
import EncryptionInfo from "./EncryptionInfo";
|
||||||
import VerificationPanel from "./VerificationPanel";
|
import VerificationPanel from "./VerificationPanel";
|
||||||
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import {ensureDMExists} from "../../../createRoom";
|
import { ensureDMExists } from "../../../createRoom";
|
||||||
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import {PHASE_REQUESTED, PHASE_UNSENT} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
|
||||||
import * as sdk from "../../../index";
|
import * as sdk from "../../../index";
|
||||||
import {_t} from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
|
||||||
import {RoomMember} from "matrix-js-sdk/src/models/room-member";
|
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import {Action} from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import {RightPanelPhases} from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||||
|
|
||||||
// cancellation codes which constitute a key mismatch
|
// cancellation codes which constitute a key mismatch
|
||||||
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
member: RoomMember;
|
member: RoomMember | User;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
verificationRequest: VerificationRequest;
|
verificationRequest: VerificationRequest;
|
||||||
verificationRequestPromise: Promise<VerificationRequest>;
|
verificationRequestPromise: Promise<VerificationRequest>;
|
||||||
|
|
|
@ -1594,7 +1594,7 @@ const UserInfo: React.FC<IProps> = ({
|
||||||
content = (
|
content = (
|
||||||
<BasicUserInfo
|
<BasicUserInfo
|
||||||
room={room}
|
room={room}
|
||||||
member={member}
|
member={member as User}
|
||||||
groupId={groupId as string}
|
groupId={groupId as string}
|
||||||
devices={devices}
|
devices={devices}
|
||||||
isRoomEncrypted={isRoomEncrypted} />
|
isRoomEncrypted={isRoomEncrypted} />
|
||||||
|
@ -1605,7 +1605,7 @@ const UserInfo: React.FC<IProps> = ({
|
||||||
content = (
|
content = (
|
||||||
<EncryptionPanel
|
<EncryptionPanel
|
||||||
{...props as React.ComponentProps<typeof EncryptionPanel>}
|
{...props as React.ComponentProps<typeof EncryptionPanel>}
|
||||||
member={member}
|
member={member as User | RoomMember}
|
||||||
onClose={onEncryptionPanelClose}
|
onClose={onEncryptionPanelClose}
|
||||||
isRoomEncrypted={isRoomEncrypted}
|
isRoomEncrypted={isRoomEncrypted}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -15,10 +15,12 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
|
||||||
import { Room } from 'matrix-js-sdk/src/models/room'
|
|
||||||
import AppsDrawer from './AppsDrawer';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { lexicographicCompare } from 'matrix-js-sdk/src/utils';
|
||||||
|
import { Room } from 'matrix-js-sdk/src/models/room'
|
||||||
|
|
||||||
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
|
import AppsDrawer from './AppsDrawer';
|
||||||
import RateLimitedFunc from '../../../ratelimitedfunc';
|
import RateLimitedFunc from '../../../ratelimitedfunc';
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
||||||
|
@ -106,9 +108,7 @@ export default class AuxPanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
if (this.props.room && SettingsStore.getValue("feature_state_counters")) {
|
if (this.props.room && SettingsStore.getValue("feature_state_counters")) {
|
||||||
const stateEvs = this.props.room.currentState.getStateEvents('re.jki.counter');
|
const stateEvs = this.props.room.currentState.getStateEvents('re.jki.counter');
|
||||||
stateEvs.sort((a, b) => {
|
stateEvs.sort((a, b) => lexicographicCompare(a.getStateKey(), b.getStateKey()));
|
||||||
return a.getStateKey() < b.getStateKey();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const ev of stateEvs) {
|
for (const ev of stateEvs) {
|
||||||
const title = ev.getContent().title;
|
const title = ev.getContent().title;
|
||||||
|
|
|
@ -14,30 +14,31 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useContext} from "react";
|
import React, { useContext } from "react";
|
||||||
import {EventType} from "matrix-js-sdk/src/@types/event";
|
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
|
|
||||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||||
import RoomContext from "../../../contexts/RoomContext";
|
import RoomContext from "../../../contexts/RoomContext";
|
||||||
import DMRoomMap from "../../../utils/DMRoomMap";
|
import DMRoomMap from "../../../utils/DMRoomMap";
|
||||||
import {_t} from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import MiniAvatarUploader, {AVATAR_SIZE} from "../elements/MiniAvatarUploader";
|
import MiniAvatarUploader, { AVATAR_SIZE } from "../elements/MiniAvatarUploader";
|
||||||
import RoomAvatar from "../avatars/RoomAvatar";
|
import RoomAvatar from "../avatars/RoomAvatar";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
import {ViewUserPayload} from "../../../dispatcher/payloads/ViewUserPayload";
|
import { ViewUserPayload } from "../../../dispatcher/payloads/ViewUserPayload";
|
||||||
import {Action} from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import SpaceStore from "../../../stores/SpaceStore";
|
import SpaceStore from "../../../stores/SpaceStore";
|
||||||
import {showSpaceInvite} from "../../../utils/space";
|
import { showSpaceInvite } from "../../../utils/space";
|
||||||
|
|
||||||
import { privateShouldBeEncrypted } from "../../../createRoom";
|
import { privateShouldBeEncrypted } from "../../../createRoom";
|
||||||
|
|
||||||
import EventTileBubble from "../messages/EventTileBubble";
|
import EventTileBubble from "../messages/EventTileBubble";
|
||||||
import { ROOM_SECURITY_TAB } from "../dialogs/RoomSettingsDialog";
|
import { ROOM_SECURITY_TAB } from "../dialogs/RoomSettingsDialog";
|
||||||
|
|
||||||
function hasExpectedEncryptionSettings(room): boolean {
|
function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room): boolean {
|
||||||
const isEncrypted: boolean = room._client?.isRoomEncrypted(room.roomId);
|
const isEncrypted: boolean = matrixClient.isRoomEncrypted(room.roomId);
|
||||||
const isPublic: boolean = room.getJoinRule() === "public";
|
const isPublic: boolean = room.getJoinRule() === "public";
|
||||||
return isPublic || !privateShouldBeEncrypted() || isEncrypted;
|
return isPublic || !privateShouldBeEncrypted() || isEncrypted;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +62,7 @@ const NewRoomIntro = () => {
|
||||||
defaultDispatcher.dispatch<ViewUserPayload>({
|
defaultDispatcher.dispatch<ViewUserPayload>({
|
||||||
action: Action.ViewUser,
|
action: Action.ViewUser,
|
||||||
// XXX: We should be using a real member object and not assuming what the receiver wants.
|
// XXX: We should be using a real member object and not assuming what the receiver wants.
|
||||||
member: member || {userId: dmPartner},
|
member: member || { userId: dmPartner } as User,
|
||||||
});
|
});
|
||||||
}} />
|
}} />
|
||||||
|
|
||||||
|
@ -194,7 +195,7 @@ const NewRoomIntro = () => {
|
||||||
|
|
||||||
return <div className="mx_NewRoomIntro">
|
return <div className="mx_NewRoomIntro">
|
||||||
|
|
||||||
{ !hasExpectedEncryptionSettings(room) && (
|
{ !hasExpectedEncryptionSettings(cli, room) && (
|
||||||
<EventTileBubble
|
<EventTileBubble
|
||||||
className="mx_cryptoEvent mx_cryptoEvent_icon_warning"
|
className="mx_cryptoEvent mx_cryptoEvent_icon_warning"
|
||||||
title={_t("End-to-end encryption isn't enabled")}
|
title={_t("End-to-end encryption isn't enabled")}
|
||||||
|
|
|
@ -119,7 +119,7 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onLocalEchoUpdated = (ev: MatrixEvent, room: Room) => {
|
private onLocalEchoUpdated = (ev: MatrixEvent, room: Room) => {
|
||||||
if (!room?.roomId === this.props.room.roomId) return;
|
if (room?.roomId !== this.props.room.roomId) return;
|
||||||
this.setState({hasUnsentEvents: this.countUnsentEvents() > 0});
|
this.setState({hasUnsentEvents: this.countUnsentEvents() > 0});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
||||||
0,
|
0,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Unexpected tag ${tagId} applied to ${this.props.room.room_id}`);
|
console.warn(`Unexpected tag ${tagId} applied to ${this.props.room.roomId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ev as React.KeyboardEvent).key === Key.ENTER) {
|
if ((ev as React.KeyboardEvent).key === Key.ENTER) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Room from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import {SpaceItem} from "./SpaceTreeLevel";
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
||||||
import SpaceStore, {
|
import SpaceStore, {
|
||||||
|
HOME_SPACE,
|
||||||
UPDATE_INVITED_SPACES,
|
UPDATE_INVITED_SPACES,
|
||||||
UPDATE_SELECTED_SPACE,
|
UPDATE_SELECTED_SPACE,
|
||||||
UPDATE_TOP_LEVEL_SPACES,
|
UPDATE_TOP_LEVEL_SPACES,
|
||||||
|
@ -40,6 +41,7 @@ import {
|
||||||
import {Key} from "../../../Keyboard";
|
import {Key} from "../../../Keyboard";
|
||||||
import {RoomNotificationStateStore} from "../../../stores/notifications/RoomNotificationStateStore";
|
import {RoomNotificationStateStore} from "../../../stores/notifications/RoomNotificationStateStore";
|
||||||
import {NotificationState} from "../../../stores/notifications/NotificationState";
|
import {NotificationState} from "../../../stores/notifications/NotificationState";
|
||||||
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
|
||||||
interface IButtonProps {
|
interface IButtonProps {
|
||||||
space?: Room;
|
space?: Room;
|
||||||
|
@ -205,6 +207,10 @@ const SpacePanel = () => {
|
||||||
|
|
||||||
const activeSpaces = activeSpace ? [activeSpace] : [];
|
const activeSpaces = activeSpace ? [activeSpace] : [];
|
||||||
const expandCollapseButtonTitle = isPanelCollapsed ? _t("Expand space panel") : _t("Collapse space panel");
|
const expandCollapseButtonTitle = isPanelCollapsed ? _t("Expand space panel") : _t("Collapse space panel");
|
||||||
|
|
||||||
|
const homeNotificationState = SettingsStore.getValue("feature_spaces.all_rooms")
|
||||||
|
? RoomNotificationStateStore.instance.globalState : SpaceStore.instance.getNotificationState(HOME_SPACE);
|
||||||
|
|
||||||
// TODO drag and drop for re-arranging order
|
// TODO drag and drop for re-arranging order
|
||||||
return <RovingTabIndexProvider handleHomeEnd={true} onKeyDown={onKeyDown}>
|
return <RovingTabIndexProvider handleHomeEnd={true} onKeyDown={onKeyDown}>
|
||||||
{({onKeyDownHandler}) => (
|
{({onKeyDownHandler}) => (
|
||||||
|
@ -218,8 +224,8 @@ const SpacePanel = () => {
|
||||||
className="mx_SpaceButton_home"
|
className="mx_SpaceButton_home"
|
||||||
onClick={() => SpaceStore.instance.setActiveSpace(null)}
|
onClick={() => SpaceStore.instance.setActiveSpace(null)}
|
||||||
selected={!activeSpace}
|
selected={!activeSpace}
|
||||||
tooltip={_t("All rooms")}
|
tooltip={SettingsStore.getValue("feature_spaces.all_rooms") ? _t("All rooms") : _t("Home")}
|
||||||
notificationState={RoomNotificationStateStore.instance.globalState}
|
notificationState={homeNotificationState}
|
||||||
isNarrow={isPanelCollapsed}
|
isNarrow={isPanelCollapsed}
|
||||||
/>
|
/>
|
||||||
{ invites.map(s => <SpaceItem
|
{ invites.map(s => <SpaceItem
|
||||||
|
|
|
@ -14,10 +14,11 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MatrixClientPeg} from "../MatrixClientPeg";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import {IMediaEventContent, IPreparedMedia, prepEventContentAsMedia} from "./models/IMediaEventContent";
|
import { ResizeMethod } from "matrix-js-sdk/src/@types/partials";
|
||||||
import {ResizeMethod} from "../Avatar";
|
|
||||||
import {MatrixClient} from "matrix-js-sdk/src/client";
|
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||||
|
import { IMediaEventContent, IPreparedMedia, prepEventContentAsMedia } from "./models/IMediaEventContent";
|
||||||
|
|
||||||
// Populate this class with the details of your customisations when copying it.
|
// Populate this class with the details of your customisations when copying it.
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
import { ActionPayload } from "../payloads";
|
import { ActionPayload } from "../payloads";
|
||||||
import { Action } from "../actions";
|
import { Action } from "../actions";
|
||||||
|
|
||||||
|
@ -25,5 +26,5 @@ export interface ViewUserPayload extends ActionPayload {
|
||||||
* The member to view. May be null or falsy to indicate that no member
|
* The member to view. May be null or falsy to indicate that no member
|
||||||
* should be shown (hide whichever relevant components).
|
* should be shown (hide whichever relevant components).
|
||||||
*/
|
*/
|
||||||
member?: RoomMember;
|
member?: RoomMember | User;
|
||||||
}
|
}
|
||||||
|
|
|
@ -794,6 +794,10 @@
|
||||||
"You can leave the beta any time from settings or tapping on a beta badge, like the one above.": "You can leave the beta any time from settings or tapping on a beta badge, like the one above.",
|
"You can leave the beta any time from settings or tapping on a beta badge, like the one above.": "You can leave the beta any time from settings or tapping on a beta badge, like the one above.",
|
||||||
"Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.",
|
"Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.",
|
||||||
"Your feedback will help make spaces better. The more detail you can go into, the better.": "Your feedback will help make spaces better. The more detail you can go into, the better.",
|
"Your feedback will help make spaces better. The more detail you can go into, the better.": "Your feedback will help make spaces better. The more detail you can go into, the better.",
|
||||||
|
"Show all rooms in Home": "Show all rooms in Home",
|
||||||
|
"Show people in spaces": "Show people in spaces",
|
||||||
|
"If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you'll automatically see everyone who is a member of the Space.": "If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you'll automatically see everyone who is a member of the Space.",
|
||||||
|
"Show notification badges for People in Spaces": "Show notification badges for People in Spaces",
|
||||||
"Show options to enable 'Do not disturb' mode": "Show options to enable 'Do not disturb' mode",
|
"Show options to enable 'Do not disturb' mode": "Show options to enable 'Do not disturb' mode",
|
||||||
"Send and receive voice messages": "Send and receive voice messages",
|
"Send and receive voice messages": "Send and receive voice messages",
|
||||||
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
|
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
|
||||||
|
@ -1024,6 +1028,7 @@
|
||||||
"Expand space panel": "Expand space panel",
|
"Expand space panel": "Expand space panel",
|
||||||
"Collapse space panel": "Collapse space panel",
|
"Collapse space panel": "Collapse space panel",
|
||||||
"All rooms": "All rooms",
|
"All rooms": "All rooms",
|
||||||
|
"Home": "Home",
|
||||||
"Click to copy": "Click to copy",
|
"Click to copy": "Click to copy",
|
||||||
"Copied!": "Copied!",
|
"Copied!": "Copied!",
|
||||||
"Failed to copy": "Failed to copy",
|
"Failed to copy": "Failed to copy",
|
||||||
|
@ -2031,7 +2036,6 @@
|
||||||
"Continue with %(provider)s": "Continue with %(provider)s",
|
"Continue with %(provider)s": "Continue with %(provider)s",
|
||||||
"Sign in with single sign-on": "Sign in with single sign-on",
|
"Sign in with single sign-on": "Sign in with single sign-on",
|
||||||
"And %(count)s more...|other": "And %(count)s more...",
|
"And %(count)s more...|other": "And %(count)s more...",
|
||||||
"Home": "Home",
|
|
||||||
"Enter a server name": "Enter a server name",
|
"Enter a server name": "Enter a server name",
|
||||||
"Looks good": "Looks good",
|
"Looks good": "Looks good",
|
||||||
"You are not allowed to view this server's rooms list": "You are not allowed to view this server's rooms list",
|
"You are not allowed to view this server's rooms list": "You are not allowed to view this server's rooms list",
|
||||||
|
|
|
@ -92,7 +92,7 @@ export class BanList {
|
||||||
if (!room) return;
|
if (!room) return;
|
||||||
|
|
||||||
for (const eventType of ALL_RULE_TYPES) {
|
for (const eventType of ALL_RULE_TYPES) {
|
||||||
const events = room.currentState.getStateEvents(eventType, undefined);
|
const events = room.currentState.getStateEvents(eventType);
|
||||||
for (const ev of events) {
|
for (const ev of events) {
|
||||||
if (!ev.getStateKey()) continue;
|
if (!ev.getStateKey()) continue;
|
||||||
|
|
||||||
|
|
|
@ -263,7 +263,13 @@ function uint8ToString(buf: Buffer) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function submitFeedback(endpoint: string, label: string, comment: string, canContact = false) {
|
export async function submitFeedback(
|
||||||
|
endpoint: string,
|
||||||
|
label: string,
|
||||||
|
comment: string,
|
||||||
|
canContact = false,
|
||||||
|
extraData: Record<string, string> = {},
|
||||||
|
) {
|
||||||
let version = "UNKNOWN";
|
let version = "UNKNOWN";
|
||||||
try {
|
try {
|
||||||
version = await PlatformPeg.get().getAppVersion();
|
version = await PlatformPeg.get().getAppVersion();
|
||||||
|
@ -279,6 +285,10 @@ export async function submitFeedback(endpoint: string, label: string, comment: s
|
||||||
body.append("platform", PlatformPeg.get().getHumanReadableName());
|
body.append("platform", PlatformPeg.get().getHumanReadableName());
|
||||||
body.append("user_id", MatrixClientPeg.get()?.getUserId());
|
body.append("user_id", MatrixClientPeg.get()?.getUserId());
|
||||||
|
|
||||||
|
for (const k in extraData) {
|
||||||
|
body.append(k, extraData[k]);
|
||||||
|
}
|
||||||
|
|
||||||
await _submitReport(SdkConfig.get().bug_report_endpoint_url, body, () => {});
|
await _submitReport(SdkConfig.get().bug_report_endpoint_url, body, () => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2017 Travis Ralston
|
Copyright 2017 Travis Ralston
|
||||||
Copyright 2018, 2019, 2020 The Matrix.org Foundation C.I.C.
|
Copyright 2018 - 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -94,6 +94,9 @@ export interface ISetting {
|
||||||
[level: SettingLevel]: string;
|
[level: SettingLevel]: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Optional description which will be shown as microCopy under SettingsFlags
|
||||||
|
description?: string;
|
||||||
|
|
||||||
// The supported levels are required. Preferably, use the preset arrays
|
// The supported levels are required. Preferably, use the preset arrays
|
||||||
// at the top of this file to define this rather than a custom array.
|
// at the top of this file to define this rather than a custom array.
|
||||||
supportedLevels?: SettingLevel[];
|
supportedLevels?: SettingLevel[];
|
||||||
|
@ -127,6 +130,7 @@ export interface ISetting {
|
||||||
image: string; // require(...)
|
image: string; // require(...)
|
||||||
feedbackSubheading?: string;
|
feedbackSubheading?: string;
|
||||||
feedbackLabel?: string;
|
feedbackLabel?: string;
|
||||||
|
extraSettings?: string[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,8 +178,33 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
||||||
feedbackSubheading: _td("Your feedback will help make spaces better. " +
|
feedbackSubheading: _td("Your feedback will help make spaces better. " +
|
||||||
"The more detail you can go into, the better."),
|
"The more detail you can go into, the better."),
|
||||||
feedbackLabel: "spaces-feedback",
|
feedbackLabel: "spaces-feedback",
|
||||||
|
extraSettings: [
|
||||||
|
"feature_spaces.all_rooms",
|
||||||
|
"feature_spaces.space_member_dms",
|
||||||
|
"feature_spaces.space_dm_badges",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"feature_spaces.all_rooms": {
|
||||||
|
displayName: _td("Show all rooms in Home"),
|
||||||
|
supportedLevels: LEVELS_FEATURE,
|
||||||
|
default: true,
|
||||||
|
controller: new ReloadOnChangeController(),
|
||||||
|
},
|
||||||
|
"feature_spaces.space_member_dms": {
|
||||||
|
displayName: _td("Show people in spaces"),
|
||||||
|
description: _td("If disabled, you can still add Direct Messages to Personal Spaces. " +
|
||||||
|
"If enabled, you'll automatically see everyone who is a member of the Space."),
|
||||||
|
supportedLevels: LEVELS_FEATURE,
|
||||||
|
default: true,
|
||||||
|
controller: new ReloadOnChangeController(),
|
||||||
|
},
|
||||||
|
"feature_spaces.space_dm_badges": {
|
||||||
|
displayName: _td("Show notification badges for People in Spaces"),
|
||||||
|
supportedLevels: LEVELS_FEATURE,
|
||||||
|
default: false,
|
||||||
|
controller: new ReloadOnChangeController(),
|
||||||
|
},
|
||||||
"feature_dnd": {
|
"feature_dnd": {
|
||||||
isFeature: true,
|
isFeature: true,
|
||||||
displayName: _td("Show options to enable 'Do not disturb' mode"),
|
displayName: _td("Show options to enable 'Do not disturb' mode"),
|
||||||
|
|
|
@ -248,6 +248,16 @@ export default class SettingsStore {
|
||||||
return _t(displayName as string);
|
return _t(displayName as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the translated description for a given setting
|
||||||
|
* @param {string} settingName The setting to look up.
|
||||||
|
* @return {String} The description for the setting, or null if not found.
|
||||||
|
*/
|
||||||
|
public static getDescription(settingName: string) {
|
||||||
|
if (!SETTINGS[settingName]?.description) return null;
|
||||||
|
return _t(SETTINGS[settingName].description);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if a setting is also a feature.
|
* Determines if a setting is also a feature.
|
||||||
* @param {string} settingName The setting to look up.
|
* @param {string} settingName The setting to look up.
|
||||||
|
|
|
@ -107,8 +107,9 @@ export class CommunityPrototypeStore extends AsyncStoreWithClient<IState> {
|
||||||
|
|
||||||
const pl = generalChat.currentState.getStateEvents("m.room.power_levels", "");
|
const pl = generalChat.currentState.getStateEvents("m.room.power_levels", "");
|
||||||
if (!pl) return this.isAdminOf(communityId);
|
if (!pl) return this.isAdminOf(communityId);
|
||||||
|
const plContent = pl.getContent();
|
||||||
|
|
||||||
const invitePl = isNullOrUndefined(pl.invite) ? 50 : Number(pl.invite);
|
const invitePl = isNullOrUndefined(plContent.invite) ? 50 : Number(plContent.invite);
|
||||||
return invitePl <= myMember.powerLevel;
|
return invitePl <= myMember.powerLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,10 +160,16 @@ export class CommunityPrototypeStore extends AsyncStoreWithClient<IState> {
|
||||||
if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
|
if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
|
||||||
const data = this.matrixClient.getAccountData("im.vector.group_info." + roomId);
|
const data = this.matrixClient.getAccountData("im.vector.group_info." + roomId);
|
||||||
if (data && data.getContent()) {
|
if (data && data.getContent()) {
|
||||||
return {displayName: data.getContent().name, avatarMxc: data.getContent().avatar_url};
|
return {
|
||||||
|
displayName: data.getContent().name,
|
||||||
|
avatarMxc: data.getContent().avatar_url,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {displayName: room.name, avatarMxc: room.avatar_url};
|
return {
|
||||||
|
displayName: room.name,
|
||||||
|
avatarMxc: room.getMxcAvatarUrl(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async onReady(): Promise<any> {
|
protected async onReady(): Promise<any> {
|
||||||
|
|
|
@ -276,7 +276,7 @@ class RoomViewStore extends Store<ActionPayload> {
|
||||||
const address = this.state.roomAlias || this.state.roomId;
|
const address = this.state.roomAlias || this.state.roomId;
|
||||||
const viaServers = this.state.viaServers || [];
|
const viaServers = this.state.viaServers || [];
|
||||||
try {
|
try {
|
||||||
await retry<void, MatrixError>(() => cli.joinRoom(address, {
|
await retry<any, MatrixError>(() => cli.joinRoom(address, {
|
||||||
viaServers,
|
viaServers,
|
||||||
...payload.opts,
|
...payload.opts,
|
||||||
}), NUM_JOIN_RETRY, (err) => {
|
}), NUM_JOIN_RETRY, (err) => {
|
||||||
|
|
|
@ -14,37 +14,42 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ListIteratee, Many, sortBy, throttle} from "lodash";
|
import { ListIteratee, Many, sortBy, throttle } from "lodash";
|
||||||
import {EventType, RoomType} from "matrix-js-sdk/src/@types/event";
|
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
||||||
import {Room} from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import {MatrixEvent} from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
import {AsyncStoreWithClient} from "./AsyncStoreWithClient";
|
import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
|
||||||
import defaultDispatcher from "../dispatcher/dispatcher";
|
import defaultDispatcher from "../dispatcher/dispatcher";
|
||||||
import {ActionPayload} from "../dispatcher/payloads";
|
import { ActionPayload } from "../dispatcher/payloads";
|
||||||
import RoomListStore from "./room-list/RoomListStore";
|
import RoomListStore from "./room-list/RoomListStore";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import DMRoomMap from "../utils/DMRoomMap";
|
import DMRoomMap from "../utils/DMRoomMap";
|
||||||
import {FetchRoomFn} from "./notifications/ListNotificationState";
|
import { FetchRoomFn } from "./notifications/ListNotificationState";
|
||||||
import {SpaceNotificationState} from "./notifications/SpaceNotificationState";
|
import { SpaceNotificationState } from "./notifications/SpaceNotificationState";
|
||||||
import {RoomNotificationStateStore} from "./notifications/RoomNotificationStateStore";
|
import { RoomNotificationStateStore } from "./notifications/RoomNotificationStateStore";
|
||||||
import {DefaultTagID} from "./room-list/models";
|
import { DefaultTagID } from "./room-list/models";
|
||||||
import {EnhancedMap, mapDiff} from "../utils/maps";
|
import { EnhancedMap, mapDiff } from "../utils/maps";
|
||||||
import {setHasDiff} from "../utils/sets";
|
import { setHasDiff } from "../utils/sets";
|
||||||
import {ISpaceSummaryEvent, ISpaceSummaryRoom} from "../components/structures/SpaceRoomDirectory";
|
import { ISpaceSummaryEvent, ISpaceSummaryRoom } from "../components/structures/SpaceRoomDirectory";
|
||||||
import RoomViewStore from "./RoomViewStore";
|
import RoomViewStore from "./RoomViewStore";
|
||||||
import {Action} from "../dispatcher/actions";
|
import { Action } from "../dispatcher/actions";
|
||||||
|
import { arrayHasDiff } from "../utils/arrays";
|
||||||
|
import { objectDiff } from "../utils/objects";
|
||||||
|
|
||||||
|
type SpaceKey = string | symbol;
|
||||||
|
|
||||||
interface IState {}
|
interface IState {}
|
||||||
|
|
||||||
const ACTIVE_SPACE_LS_KEY = "mx_active_space";
|
const ACTIVE_SPACE_LS_KEY = "mx_active_space";
|
||||||
|
|
||||||
|
export const HOME_SPACE = Symbol("home-space");
|
||||||
export const SUGGESTED_ROOMS = Symbol("suggested-rooms");
|
export const SUGGESTED_ROOMS = Symbol("suggested-rooms");
|
||||||
|
|
||||||
export const UPDATE_TOP_LEVEL_SPACES = Symbol("top-level-spaces");
|
export const UPDATE_TOP_LEVEL_SPACES = Symbol("top-level-spaces");
|
||||||
export const UPDATE_INVITED_SPACES = Symbol("invited-spaces");
|
export const UPDATE_INVITED_SPACES = Symbol("invited-spaces");
|
||||||
export const UPDATE_SELECTED_SPACE = Symbol("selected-space");
|
export const UPDATE_SELECTED_SPACE = Symbol("selected-space");
|
||||||
// Space Room ID will be emitted when a Space's children change
|
// Space Room ID/HOME_SPACE will be emitted when a Space's children change
|
||||||
|
|
||||||
export interface ISuggestedRoom extends ISpaceSummaryRoom {
|
export interface ISuggestedRoom extends ISpaceSummaryRoom {
|
||||||
viaServers: string[];
|
viaServers: string[];
|
||||||
|
@ -52,7 +57,8 @@ export interface ISuggestedRoom extends ISpaceSummaryRoom {
|
||||||
|
|
||||||
const MAX_SUGGESTED_ROOMS = 20;
|
const MAX_SUGGESTED_ROOMS = 20;
|
||||||
|
|
||||||
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || "ALL_ROOMS"}`;
|
const homeSpaceKey = SettingsStore.getValue("feature_spaces.all_rooms") ? "ALL_ROOMS" : "HOME_SPACE";
|
||||||
|
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || homeSpaceKey}`;
|
||||||
|
|
||||||
const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => { // [spaces, rooms]
|
const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => { // [spaces, rooms]
|
||||||
return arr.reduce((result, room: Room) => {
|
return arr.reduce((result, room: Room) => {
|
||||||
|
@ -86,13 +92,15 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
|
|
||||||
// The spaces representing the roots of the various tree-like hierarchies
|
// The spaces representing the roots of the various tree-like hierarchies
|
||||||
private rootSpaces: Room[] = [];
|
private rootSpaces: Room[] = [];
|
||||||
|
// The list of rooms not present in any currently joined spaces
|
||||||
|
private orphanedRooms = new Set<string>();
|
||||||
// Map from room ID to set of spaces which list it as a child
|
// Map from room ID to set of spaces which list it as a child
|
||||||
private parentMap = new EnhancedMap<string, Set<string>>();
|
private parentMap = new EnhancedMap<string, Set<string>>();
|
||||||
// Map from spaceId to SpaceNotificationState instance representing that space
|
// Map from SpaceKey to SpaceNotificationState instance representing that space
|
||||||
private notificationStateMap = new Map<string, SpaceNotificationState>();
|
private notificationStateMap = new Map<SpaceKey, SpaceNotificationState>();
|
||||||
// Map from space key to Set of room IDs that should be shown as part of that space's filter
|
// Map from space key to Set of room IDs that should be shown as part of that space's filter
|
||||||
private spaceFilteredRooms = new Map<string, Set<string>>();
|
private spaceFilteredRooms = new Map<SpaceKey, Set<string>>();
|
||||||
// The space currently selected in the Space Panel - if null then All Rooms is selected
|
// The space currently selected in the Space Panel - if null then Home is selected
|
||||||
private _activeSpace?: Room = null;
|
private _activeSpace?: Room = null;
|
||||||
private _suggestedRooms: ISuggestedRoom[] = [];
|
private _suggestedRooms: ISuggestedRoom[] = [];
|
||||||
private _invitedSpaces = new Set<Room>();
|
private _invitedSpaces = new Set<Room>();
|
||||||
|
@ -134,7 +142,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
// if the space being selected is an invite then always view that invite
|
// if the space being selected is an invite then always view that invite
|
||||||
// else if the last viewed room in this space is joined then view that
|
// else if the last viewed room in this space is joined then view that
|
||||||
// else view space home or home depending on what is being clicked on
|
// else view space home or home depending on what is being clicked on
|
||||||
if (space?.getMyMembership !== "invite" &&
|
if (space?.getMyMembership() !== "invite" &&
|
||||||
this.matrixClient?.getRoom(roomId)?.getMyMembership() === "join"
|
this.matrixClient?.getRoom(roomId)?.getMyMembership() === "join"
|
||||||
) {
|
) {
|
||||||
defaultDispatcher.dispatch({
|
defaultDispatcher.dispatch({
|
||||||
|
@ -252,10 +260,10 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSpaceFilteredRoomIds = (space: Room | null): Set<string> => {
|
public getSpaceFilteredRoomIds = (space: Room | null): Set<string> => {
|
||||||
if (!space) {
|
if (!space && SettingsStore.getValue("feature_spaces.all_rooms")) {
|
||||||
return new Set(this.matrixClient.getVisibleRooms().map(r => r.roomId));
|
return new Set(this.matrixClient.getVisibleRooms().map(r => r.roomId));
|
||||||
}
|
}
|
||||||
return this.spaceFilteredRooms.get(space.roomId) || new Set();
|
return this.spaceFilteredRooms.get(space?.roomId || HOME_SPACE) || new Set();
|
||||||
};
|
};
|
||||||
|
|
||||||
private rebuild = throttle(() => {
|
private rebuild = throttle(() => {
|
||||||
|
@ -286,7 +294,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const [rootSpaces] = partitionSpacesAndRooms(Array.from(unseenChildren));
|
const [rootSpaces, orphanedRooms] = partitionSpacesAndRooms(Array.from(unseenChildren));
|
||||||
|
|
||||||
// somewhat algorithm to handle full-cycles
|
// somewhat algorithm to handle full-cycles
|
||||||
const detachedNodes = new Set<Room>(spaces);
|
const detachedNodes = new Set<Room>(spaces);
|
||||||
|
@ -327,6 +335,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
// rootSpaces.push(space);
|
// rootSpaces.push(space);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
this.orphanedRooms = new Set(orphanedRooms);
|
||||||
this.rootSpaces = rootSpaces;
|
this.rootSpaces = rootSpaces;
|
||||||
this.parentMap = backrefs;
|
this.parentMap = backrefs;
|
||||||
|
|
||||||
|
@ -343,10 +352,30 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
this.emit(UPDATE_INVITED_SPACES, this.invitedSpaces);
|
this.emit(UPDATE_INVITED_SPACES, this.invitedSpaces);
|
||||||
}, 100, {trailing: true, leading: true});
|
}, 100, {trailing: true, leading: true});
|
||||||
|
|
||||||
onSpaceUpdate = () => {
|
private onSpaceUpdate = () => {
|
||||||
this.rebuild();
|
this.rebuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private showInHomeSpace = (room: Room) => {
|
||||||
|
if (SettingsStore.getValue("feature_spaces.all_rooms")) return true;
|
||||||
|
if (room.isSpaceRoom()) return false;
|
||||||
|
return !this.parentMap.get(room.roomId)?.size // put all orphaned rooms in the Home Space
|
||||||
|
|| DMRoomMap.shared().getUserIdForRoomId(room.roomId) // put all DMs in the Home Space
|
||||||
|
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite) // show all favourites
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update a given room due to its tag changing (e.g DM-ness or Fav-ness)
|
||||||
|
// This can only change whether it shows up in the HOME_SPACE or not
|
||||||
|
private onRoomUpdate = (room: Room) => {
|
||||||
|
if (this.showInHomeSpace(room)) {
|
||||||
|
this.spaceFilteredRooms.get(HOME_SPACE)?.add(room.roomId);
|
||||||
|
this.emit(HOME_SPACE);
|
||||||
|
} else if (!this.orphanedRooms.has(room.roomId)) {
|
||||||
|
this.spaceFilteredRooms.get(HOME_SPACE)?.delete(room.roomId);
|
||||||
|
this.emit(HOME_SPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private onSpaceMembersChange = (ev: MatrixEvent) => {
|
private onSpaceMembersChange = (ev: MatrixEvent) => {
|
||||||
// skip this update if we do not have a DM with this user
|
// skip this update if we do not have a DM with this user
|
||||||
if (DMRoomMap.shared().getDMRoomsForUserId(ev.getStateKey()).length < 1) return;
|
if (DMRoomMap.shared().getDMRoomsForUserId(ev.getStateKey()).length < 1) return;
|
||||||
|
@ -360,6 +389,18 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
const oldFilteredRooms = this.spaceFilteredRooms;
|
const oldFilteredRooms = this.spaceFilteredRooms;
|
||||||
this.spaceFilteredRooms = new Map();
|
this.spaceFilteredRooms = new Map();
|
||||||
|
|
||||||
|
if (!SettingsStore.getValue("feature_spaces.all_rooms")) {
|
||||||
|
// put all room invites in the Home Space
|
||||||
|
const invites = visibleRooms.filter(r => !r.isSpaceRoom() && r.getMyMembership() === "invite");
|
||||||
|
this.spaceFilteredRooms.set(HOME_SPACE, new Set<string>(invites.map(room => room.roomId)));
|
||||||
|
|
||||||
|
visibleRooms.forEach(room => {
|
||||||
|
if (this.showInHomeSpace(room)) {
|
||||||
|
this.spaceFilteredRooms.get(HOME_SPACE).add(room.roomId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.rootSpaces.forEach(s => {
|
this.rootSpaces.forEach(s => {
|
||||||
// traverse each space tree in DFS to build up the supersets as you go up,
|
// traverse each space tree in DFS to build up the supersets as you go up,
|
||||||
// reusing results from like subtrees.
|
// reusing results from like subtrees.
|
||||||
|
@ -375,13 +416,15 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
const roomIds = new Set(childRooms.map(r => r.roomId));
|
const roomIds = new Set(childRooms.map(r => r.roomId));
|
||||||
const space = this.matrixClient?.getRoom(spaceId);
|
const space = this.matrixClient?.getRoom(spaceId);
|
||||||
|
|
||||||
// Add relevant DMs
|
if (SettingsStore.getValue("feature_spaces.space_member_dms")) {
|
||||||
space?.getMembers().forEach(member => {
|
// Add relevant DMs
|
||||||
if (member.membership !== "join" && member.membership !== "invite") return;
|
space?.getMembers().forEach(member => {
|
||||||
DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => {
|
if (member.membership !== "join" && member.membership !== "invite") return;
|
||||||
roomIds.add(roomId);
|
DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => {
|
||||||
|
roomIds.add(roomId);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
const newPath = new Set(parentPath).add(spaceId);
|
const newPath = new Set(parentPath).add(spaceId);
|
||||||
childSpaces.forEach(childSpace => {
|
childSpaces.forEach(childSpace => {
|
||||||
|
@ -407,6 +450,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
// Update NotificationStates
|
// Update NotificationStates
|
||||||
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
|
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
|
||||||
if (roomIds.has(room.roomId)) {
|
if (roomIds.has(room.roomId)) {
|
||||||
|
if (s !== HOME_SPACE && SettingsStore.getValue("feature_spaces.space_dm_badges")) return true;
|
||||||
|
|
||||||
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
|
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
|
||||||
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
|
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
|
||||||
}
|
}
|
||||||
|
@ -424,8 +469,14 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
parent = this.rootSpaces.find(s => this.spaceFilteredRooms.get(s.roomId)?.has(roomId));
|
parent = this.rootSpaces.find(s => this.spaceFilteredRooms.get(s.roomId)?.has(roomId));
|
||||||
}
|
}
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
const parents = Array.from(this.parentMap.get(roomId) || []);
|
const parentIds = Array.from(this.parentMap.get(roomId) || []);
|
||||||
parent = parents.find(p => this.matrixClient.getRoom(p));
|
for (const parentId of parentIds) {
|
||||||
|
const room = this.matrixClient.getRoom(parentId);
|
||||||
|
if (room) {
|
||||||
|
parent = room;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't trigger a context switch when we are switching a space to match the chosen room
|
// don't trigger a context switch when we are switching a space to match the chosen room
|
||||||
|
@ -490,6 +541,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
// TODO confirm this after implementing parenting behaviour
|
// TODO confirm this after implementing parenting behaviour
|
||||||
if (room.isSpaceRoom()) {
|
if (room.isSpaceRoom()) {
|
||||||
this.onSpaceUpdate();
|
this.onSpaceUpdate();
|
||||||
|
} else if (!SettingsStore.getValue("feature_spaces.all_rooms")) {
|
||||||
|
this.onRoomUpdate(room);
|
||||||
}
|
}
|
||||||
this.emit(room.roomId);
|
this.emit(room.roomId);
|
||||||
break;
|
break;
|
||||||
|
@ -502,8 +555,38 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onRoomAccountData = (ev: MatrixEvent, room: Room, lastEvent?: MatrixEvent) => {
|
||||||
|
if (ev.getType() === EventType.Tag && !room.isSpaceRoom()) {
|
||||||
|
// If the room was in favourites and now isn't or the opposite then update its position in the trees
|
||||||
|
const oldTags = lastEvent?.getContent()?.tags || {};
|
||||||
|
const newTags = ev.getContent()?.tags || {};
|
||||||
|
if (!!oldTags[DefaultTagID.Favourite] !== !!newTags[DefaultTagID.Favourite]) {
|
||||||
|
this.onRoomUpdate(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onAccountData = (ev: MatrixEvent, lastEvent: MatrixEvent) => {
|
||||||
|
if (ev.getType() === EventType.Direct) {
|
||||||
|
const lastContent = lastEvent.getContent();
|
||||||
|
const content = ev.getContent();
|
||||||
|
|
||||||
|
const diff = objectDiff<Record<string, string[]>>(lastContent, content);
|
||||||
|
// filter out keys which changed by reference only by checking whether the sets differ
|
||||||
|
const changed = diff.changed.filter(k => arrayHasDiff(lastContent[k], content[k]));
|
||||||
|
// DM tag changes, refresh relevant rooms
|
||||||
|
new Set([...diff.added, ...diff.removed, ...changed]).forEach(roomId => {
|
||||||
|
const room = this.matrixClient?.getRoom(roomId);
|
||||||
|
if (room) {
|
||||||
|
this.onRoomUpdate(room);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
protected async reset() {
|
protected async reset() {
|
||||||
this.rootSpaces = [];
|
this.rootSpaces = [];
|
||||||
|
this.orphanedRooms = new Set();
|
||||||
this.parentMap = new EnhancedMap();
|
this.parentMap = new EnhancedMap();
|
||||||
this.notificationStateMap = new Map();
|
this.notificationStateMap = new Map();
|
||||||
this.spaceFilteredRooms = new Map();
|
this.spaceFilteredRooms = new Map();
|
||||||
|
@ -518,6 +601,10 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
this.matrixClient.removeListener("Room", this.onRoom);
|
this.matrixClient.removeListener("Room", this.onRoom);
|
||||||
this.matrixClient.removeListener("Room.myMembership", this.onRoom);
|
this.matrixClient.removeListener("Room.myMembership", this.onRoom);
|
||||||
this.matrixClient.removeListener("RoomState.events", this.onRoomState);
|
this.matrixClient.removeListener("RoomState.events", this.onRoomState);
|
||||||
|
if (!SettingsStore.getValue("feature_spaces.all_rooms")) {
|
||||||
|
this.matrixClient.removeListener("Room.accountData", this.onRoomAccountData);
|
||||||
|
this.matrixClient.removeListener("accountData", this.onAccountData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await this.reset();
|
await this.reset();
|
||||||
}
|
}
|
||||||
|
@ -527,6 +614,10 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
this.matrixClient.on("Room", this.onRoom);
|
this.matrixClient.on("Room", this.onRoom);
|
||||||
this.matrixClient.on("Room.myMembership", this.onRoom);
|
this.matrixClient.on("Room.myMembership", this.onRoom);
|
||||||
this.matrixClient.on("RoomState.events", this.onRoomState);
|
this.matrixClient.on("RoomState.events", this.onRoomState);
|
||||||
|
if (!SettingsStore.getValue("feature_spaces.all_rooms")) {
|
||||||
|
this.matrixClient.on("Room.accountData", this.onRoomAccountData);
|
||||||
|
this.matrixClient.on("accountData", this.onAccountData);
|
||||||
|
}
|
||||||
|
|
||||||
await this.onSpaceUpdate(); // trigger an initial update
|
await this.onSpaceUpdate(); // trigger an initial update
|
||||||
|
|
||||||
|
@ -551,7 +642,10 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
// Don't context switch when navigating to the space room
|
// Don't context switch when navigating to the space room
|
||||||
// as it will cause you to end up in the wrong room
|
// as it will cause you to end up in the wrong room
|
||||||
this.setActiveSpace(room, false);
|
this.setActiveSpace(room, false);
|
||||||
} else if (this.activeSpace && !this.getSpaceFilteredRoomIds(this.activeSpace).has(roomId)) {
|
} else if (
|
||||||
|
(!SettingsStore.getValue("feature_spaces.all_rooms") || this.activeSpace) &&
|
||||||
|
!this.getSpaceFilteredRoomIds(this.activeSpace).has(roomId)
|
||||||
|
) {
|
||||||
this.switchToRelatedSpace(roomId);
|
this.switchToRelatedSpace(roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,7 +669,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNotificationState(key: string): SpaceNotificationState {
|
public getNotificationState(key: SpaceKey): SpaceNotificationState {
|
||||||
if (this.notificationStateMap.has(key)) {
|
if (this.notificationStateMap.has(key)) {
|
||||||
return this.notificationStateMap.get(key);
|
return this.notificationStateMap.get(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { RoomListStoreClass } from "./RoomListStore";
|
import { RoomListStoreClass } from "./RoomListStore";
|
||||||
import { SpaceFilterCondition } from "./filters/SpaceFilterCondition";
|
import { SpaceFilterCondition } from "./filters/SpaceFilterCondition";
|
||||||
import SpaceStore, { UPDATE_SELECTED_SPACE } from "../SpaceStore";
|
import SpaceStore, { UPDATE_SELECTED_SPACE } from "../SpaceStore";
|
||||||
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Watches for changes in spaces to manage the filter on the provided RoomListStore
|
* Watches for changes in spaces to manage the filter on the provided RoomListStore
|
||||||
|
@ -28,6 +29,11 @@ export class SpaceWatcher {
|
||||||
private activeSpace: Room = SpaceStore.instance.activeSpace;
|
private activeSpace: Room = SpaceStore.instance.activeSpace;
|
||||||
|
|
||||||
constructor(private store: RoomListStoreClass) {
|
constructor(private store: RoomListStoreClass) {
|
||||||
|
if (!SettingsStore.getValue("feature_spaces.all_rooms")) {
|
||||||
|
this.filter = new SpaceFilterCondition();
|
||||||
|
this.updateFilter();
|
||||||
|
store.addFilter(this.filter);
|
||||||
|
}
|
||||||
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdated);
|
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +41,7 @@ export class SpaceWatcher {
|
||||||
this.activeSpace = activeSpace;
|
this.activeSpace = activeSpace;
|
||||||
|
|
||||||
if (this.filter) {
|
if (this.filter) {
|
||||||
if (activeSpace) {
|
if (activeSpace || !SettingsStore.getValue("feature_spaces.all_rooms")) {
|
||||||
this.updateFilter();
|
this.updateFilter();
|
||||||
} else {
|
} else {
|
||||||
this.store.removeFilter(this.filter);
|
this.store.removeFilter(this.filter);
|
||||||
|
@ -49,9 +55,11 @@ export class SpaceWatcher {
|
||||||
};
|
};
|
||||||
|
|
||||||
private updateFilter = () => {
|
private updateFilter = () => {
|
||||||
SpaceStore.instance.traverseSpace(this.activeSpace.roomId, roomId => {
|
if (this.activeSpace) {
|
||||||
this.store.matrixClient?.getRoom(roomId)?.loadMembersIfNeeded();
|
SpaceStore.instance.traverseSpace(this.activeSpace.roomId, roomId => {
|
||||||
});
|
this.store.matrixClient?.getRoom(roomId)?.loadMembersIfNeeded();
|
||||||
|
});
|
||||||
|
}
|
||||||
this.filter.updateSpace(this.activeSpace);
|
this.filter.updateSpace(this.activeSpace);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
|
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
|
||||||
import { IDestroyable } from "../../../utils/IDestroyable";
|
import { IDestroyable } from "../../../utils/IDestroyable";
|
||||||
import SpaceStore from "../../SpaceStore";
|
import SpaceStore, { HOME_SPACE } from "../../SpaceStore";
|
||||||
import { setHasDiff } from "../../../utils/sets";
|
import { setHasDiff } from "../../../utils/sets";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,7 +29,7 @@ import { setHasDiff } from "../../../utils/sets";
|
||||||
* + All DMs
|
* + All DMs
|
||||||
*/
|
*/
|
||||||
export class SpaceFilterCondition extends EventEmitter implements IFilterCondition, IDestroyable {
|
export class SpaceFilterCondition extends EventEmitter implements IFilterCondition, IDestroyable {
|
||||||
private roomIds = new Set<Room>();
|
private roomIds = new Set<string>();
|
||||||
private space: Room = null;
|
private space: Room = null;
|
||||||
|
|
||||||
public get kind(): FilterKind {
|
public get kind(): FilterKind {
|
||||||
|
@ -55,12 +55,10 @@ export class SpaceFilterCondition extends EventEmitter implements IFilterConditi
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private getSpaceEventKey = (space: Room) => space.roomId;
|
private getSpaceEventKey = (space: Room | null) => space ? space.roomId : HOME_SPACE;
|
||||||
|
|
||||||
public updateSpace(space: Room) {
|
public updateSpace(space: Room) {
|
||||||
if (this.space) {
|
SpaceStore.instance.off(this.getSpaceEventKey(this.space), this.onStoreUpdate);
|
||||||
SpaceStore.instance.off(this.getSpaceEventKey(this.space), this.onStoreUpdate);
|
|
||||||
}
|
|
||||||
SpaceStore.instance.on(this.getSpaceEventKey(this.space = space), this.onStoreUpdate);
|
SpaceStore.instance.on(this.getSpaceEventKey(this.space = space), this.onStoreUpdate);
|
||||||
this.onStoreUpdate(); // initial update from the change to the space
|
this.onStoreUpdate(); // initial update from the change to the space
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,31 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import DMRoomMap from './DMRoomMap';
|
import DMRoomMap from './DMRoomMap';
|
||||||
|
|
||||||
/* For now, a cut-down type spec for the client */
|
|
||||||
interface Client {
|
|
||||||
getUserId: () => string;
|
|
||||||
checkUserTrust: (userId: string) => {
|
|
||||||
isCrossSigningVerified: () => boolean
|
|
||||||
wasCrossSigningVerified: () => boolean
|
|
||||||
};
|
|
||||||
getStoredDevicesForUser: (userId: string) => [{ deviceId: string }];
|
|
||||||
checkDeviceTrust: (userId: string, deviceId: string) => {
|
|
||||||
isVerified: () => boolean
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Room {
|
|
||||||
getEncryptionTargetMembers: () => Promise<[{userId: string}]>;
|
|
||||||
roomId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum E2EStatus {
|
export enum E2EStatus {
|
||||||
Warning = "warning",
|
Warning = "warning",
|
||||||
Verified = "verified",
|
Verified = "verified",
|
||||||
Normal = "normal"
|
Normal = "normal"
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function shieldStatusForRoom(client: Client, room: Room): Promise<E2EStatus> {
|
export async function shieldStatusForRoom(client: MatrixClient, room: Room): Promise<E2EStatus> {
|
||||||
const members = (await room.getEncryptionTargetMembers()).map(({userId}) => userId);
|
const members = (await room.getEncryptionTargetMembers()).map(({userId}) => userId);
|
||||||
const inDMMap = !!DMRoomMap.shared().getUserIdForRoomId(room.roomId);
|
const inDMMap = !!DMRoomMap.shared().getUserIdForRoomId(room.roomId);
|
||||||
|
|
||||||
|
|
|
@ -16,19 +16,20 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as url from "url";
|
import * as url from "url";
|
||||||
|
import { Capability, IWidget, IWidgetData, MatrixCapabilities } from "matrix-widget-api";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||||
import SdkConfig from "../SdkConfig";
|
import SdkConfig from "../SdkConfig";
|
||||||
import dis from '../dispatcher/dispatcher';
|
import dis from '../dispatcher/dispatcher';
|
||||||
import WidgetEchoStore from '../stores/WidgetEchoStore';
|
import WidgetEchoStore from '../stores/WidgetEchoStore';
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import {IntegrationManagers} from "../integrations/IntegrationManagers";
|
import { IntegrationManagers } from "../integrations/IntegrationManagers";
|
||||||
import {Room} from "matrix-js-sdk/src/models/room";
|
import { WidgetType } from "../widgets/WidgetType";
|
||||||
import {WidgetType} from "../widgets/WidgetType";
|
import { objectClone } from "./objects";
|
||||||
import {objectClone} from "./objects";
|
import { _t } from "../languageHandler";
|
||||||
import {_t} from "../languageHandler";
|
import { IApp } from "../stores/WidgetStore";
|
||||||
import {Capability, IWidget, IWidgetData, MatrixCapabilities} from "matrix-widget-api";
|
|
||||||
import {IApp} from "../stores/WidgetStore";
|
|
||||||
|
|
||||||
// How long we wait for the state event echo to come back from the server
|
// How long we wait for the state event echo to come back from the server
|
||||||
// before waitFor[Room/User]Widget rejects its promise
|
// before waitFor[Room/User]Widget rejects its promise
|
||||||
|
@ -377,9 +378,9 @@ export default class WidgetUtils {
|
||||||
return widgets.filter(w => w.content && w.content.type === "m.integration_manager");
|
return widgets.filter(w => w.content && w.content.type === "m.integration_manager");
|
||||||
}
|
}
|
||||||
|
|
||||||
static getRoomWidgetsOfType(room: Room, type: WidgetType): IWidgetEvent[] {
|
static getRoomWidgetsOfType(room: Room, type: WidgetType): MatrixEvent[] {
|
||||||
const widgets = WidgetUtils.getRoomWidgets(room);
|
const widgets = WidgetUtils.getRoomWidgets(room) || [];
|
||||||
return (widgets || []).filter(w => {
|
return widgets.filter(w => {
|
||||||
const content = w.getContent();
|
const content = w.getContent();
|
||||||
return content.url && type.matches(content.type);
|
return content.url && type.matches(content.type);
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,7 +42,7 @@ import DMRoomMap from "../../../src/utils/DMRoomMap";
|
||||||
configure({ adapter: new Adapter() });
|
configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
let client;
|
let client;
|
||||||
const room = new Matrix.Room();
|
const room = new Matrix.Room("!roomId:server_name");
|
||||||
|
|
||||||
// wrap MessagePanel with a component which provides the MatrixClient in the context.
|
// wrap MessagePanel with a component which provides the MatrixClient in the context.
|
||||||
class WrappedMessagePanel extends React.Component {
|
class WrappedMessagePanel extends React.Component {
|
||||||
|
|
|
@ -123,8 +123,15 @@ describe("SpaceStore", () => {
|
||||||
jest.runAllTimers();
|
jest.runAllTimers();
|
||||||
client.getVisibleRooms.mockReturnValue(rooms = []);
|
client.getVisibleRooms.mockReturnValue(rooms = []);
|
||||||
getValue.mockImplementation(settingName => {
|
getValue.mockImplementation(settingName => {
|
||||||
if (settingName === "feature_spaces") {
|
switch (settingName) {
|
||||||
return true;
|
case "feature_spaces":
|
||||||
|
return true;
|
||||||
|
case "feature_spaces.all_rooms":
|
||||||
|
return true;
|
||||||
|
case "feature_spaces.space_member_dms":
|
||||||
|
return true;
|
||||||
|
case "feature_spaces.space_dm_badges":
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue