Merge pull request #6199 from matrix-org/t3chguy/fix/17665
This commit is contained in:
commit
59052b1eb7
13 changed files with 300 additions and 104 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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, {
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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>();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -496,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;
|
||||||
|
@ -508,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();
|
||||||
|
@ -524,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();
|
||||||
}
|
}
|
||||||
|
@ -533,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
|
||||||
|
|
||||||
|
@ -557,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,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";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue