You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-03 00:33:22 +03:00 
			
		
		
		
	Add presence icons; Convert to generic icon component
For https://github.com/vector-im/riot-web/issues/14039
This commit is contained in:
		@@ -189,6 +189,7 @@
 | 
			
		||||
@import "./views/rooms/_RoomSublist2.scss";
 | 
			
		||||
@import "./views/rooms/_RoomTile.scss";
 | 
			
		||||
@import "./views/rooms/_RoomTile2.scss";
 | 
			
		||||
@import "./views/rooms/_RoomTileIcon.scss";
 | 
			
		||||
@import "./views/rooms/_RoomUpgradeWarningBar.scss";
 | 
			
		||||
@import "./views/rooms/_SearchBar.scss";
 | 
			
		||||
@import "./views/rooms/_SendMessageComposer.scss";
 | 
			
		||||
 
 | 
			
		||||
@@ -34,28 +34,10 @@ limitations under the License.
 | 
			
		||||
        margin-right: 8px;
 | 
			
		||||
        position: relative;
 | 
			
		||||
 | 
			
		||||
        .mx_RoomTile2_publicRoom {
 | 
			
		||||
            width: 12px;
 | 
			
		||||
            height: 12px;
 | 
			
		||||
            border-radius: 12px;
 | 
			
		||||
            background-color: $roomlist2-bg-color; // to match the room list itself
 | 
			
		||||
        .mx_RoomTileIcon {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            bottom: 0;
 | 
			
		||||
            right: 0;
 | 
			
		||||
 | 
			
		||||
            &::before {
 | 
			
		||||
                content: '';
 | 
			
		||||
                width: 8px;
 | 
			
		||||
                height: 8px;
 | 
			
		||||
                top: 2px;
 | 
			
		||||
                left: 2px;
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                mask-position: center;
 | 
			
		||||
                mask-size: contain;
 | 
			
		||||
                mask-repeat: no-repeat;
 | 
			
		||||
                background: $primary-fg-color;
 | 
			
		||||
                mask-image: url('$(res)/img/globe.svg');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								res/css/views/rooms/_RoomTileIcon.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								res/css/views/rooms/_RoomTileIcon.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2020 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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
.mx_RoomTileIcon {
 | 
			
		||||
    width: 12px;
 | 
			
		||||
    height: 12px;
 | 
			
		||||
    border-radius: 12px;
 | 
			
		||||
    background-color: $roomlist2-bg-color; // to match the room list itself
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomTileIcon_globe::before {
 | 
			
		||||
    content: '';
 | 
			
		||||
    width: 8px;
 | 
			
		||||
    height: 8px;
 | 
			
		||||
    top: 2px;
 | 
			
		||||
    left: 2px;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    mask-position: center;
 | 
			
		||||
    mask-size: contain;
 | 
			
		||||
    mask-repeat: no-repeat;
 | 
			
		||||
    background: $primary-fg-color;
 | 
			
		||||
    mask-image: url('$(res)/img/globe.svg');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomTileIcon_offline::before {
 | 
			
		||||
    content: '';
 | 
			
		||||
    width: 8px;
 | 
			
		||||
    height: 8px;
 | 
			
		||||
    top: 2px;
 | 
			
		||||
    left: 2px;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    background-color: $presence-offline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomTileIcon_online::before {
 | 
			
		||||
    content: '';
 | 
			
		||||
    width: 8px;
 | 
			
		||||
    height: 8px;
 | 
			
		||||
    top: 2px;
 | 
			
		||||
    left: 2px;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    background-color: $presence-online;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomTileIcon_away::before {
 | 
			
		||||
    content: '';
 | 
			
		||||
    width: 8px;
 | 
			
		||||
    height: 8px;
 | 
			
		||||
    top: 2px;
 | 
			
		||||
    left: 2px;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    background-color: $presence-away;
 | 
			
		||||
}
 | 
			
		||||
@@ -186,6 +186,10 @@ $roomtile2-preview-color: #9e9e9e;
 | 
			
		||||
$roomtile2-default-badge-bg-color: #61708b;
 | 
			
		||||
$roomtile2-selected-bg-color: #FFF;
 | 
			
		||||
 | 
			
		||||
$presence-online: $accent-color;
 | 
			
		||||
$presence-away: orange; // TODO: Get color
 | 
			
		||||
$presence-offline: #E3E8F0;
 | 
			
		||||
 | 
			
		||||
// ********************
 | 
			
		||||
 | 
			
		||||
$roomtile-name-color: #61708b;
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ import React, { createRef } from "react";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
 | 
			
		||||
import AccessibleButton, {ButtonEvent} from "../../views/elements/AccessibleButton";
 | 
			
		||||
import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
 | 
			
		||||
import RoomAvatar from "../../views/avatars/RoomAvatar";
 | 
			
		||||
import dis from '../../../dispatcher/dispatcher';
 | 
			
		||||
import { Key } from "../../../Keyboard";
 | 
			
		||||
@@ -31,6 +31,7 @@ import { _t } from "../../../languageHandler";
 | 
			
		||||
import { ContextMenu, ContextMenuButton } from "../../structures/ContextMenu";
 | 
			
		||||
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
 | 
			
		||||
import { MessagePreviewStore } from "../../../stores/MessagePreviewStore";
 | 
			
		||||
import RoomTileIcon from "./RoomTileIcon";
 | 
			
		||||
 | 
			
		||||
/*******************************************************************
 | 
			
		||||
 *   CAUTION                                                       *
 | 
			
		||||
@@ -86,12 +87,6 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
			
		||||
        ActiveRoomObserver.addListener(this.props.room.roomId, this.onActiveRoomUpdate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private get isPublicRoom(): boolean {
 | 
			
		||||
        const joinRules = this.props.room.currentState.getStateEvents("m.room.join_rules", "");
 | 
			
		||||
        const joinRule = joinRules && joinRules.getContent().join_rule;
 | 
			
		||||
        return joinRule === 'public';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public componentWillUnmount() {
 | 
			
		||||
        if (this.props.room) {
 | 
			
		||||
            ActiveRoomObserver.removeListener(this.props.room.roomId, this.onActiveRoomUpdate);
 | 
			
		||||
@@ -187,25 +182,25 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
			
		||||
                            <ul>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                    <AccessibleButton onClick={(e) => this.onTagRoom(e, DefaultTagID.Favourite)}>
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconStar" />
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconStar"/>
 | 
			
		||||
                                        <span>{_t("Favourite")}</span>
 | 
			
		||||
                                    </AccessibleButton>
 | 
			
		||||
                                </li>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                    <AccessibleButton onClick={(e) => this.onTagRoom(e, DefaultTagID.LowPriority)}>
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconArrowDown" />
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconArrowDown"/>
 | 
			
		||||
                                        <span>{_t("Low Priority")}</span>
 | 
			
		||||
                                    </AccessibleButton>
 | 
			
		||||
                                </li>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                    <AccessibleButton onClick={(e) => this.onTagRoom(e, DefaultTagID.DM)}>
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconUser" />
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconUser"/>
 | 
			
		||||
                                        <span>{_t("Direct Chat")}</span>
 | 
			
		||||
                                    </AccessibleButton>
 | 
			
		||||
                                </li>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                    <AccessibleButton onClick={this.onOpenRoomSettings}>
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconSettings" />
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconSettings"/>
 | 
			
		||||
                                        <span>{_t("Settings")}</span>
 | 
			
		||||
                                    </AccessibleButton>
 | 
			
		||||
                                </li>
 | 
			
		||||
@@ -215,7 +210,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
			
		||||
                            <ul>
 | 
			
		||||
                                <li className="mx_RoomTile2_contextMenu_redRow">
 | 
			
		||||
                                    <AccessibleButton onClick={this.onLeaveRoomClick}>
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconSignOut" />
 | 
			
		||||
                                        <span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconSignOut"/>
 | 
			
		||||
                                        <span>{_t("Leave Room")}</span>
 | 
			
		||||
                                    </AccessibleButton>
 | 
			
		||||
                                </li>
 | 
			
		||||
@@ -253,7 +248,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
			
		||||
            'mx_RoomTile2_minimized': this.props.isMinimized,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const badge = <NotificationBadge notification={this.state.notificationState} allowNoCount={true} />;
 | 
			
		||||
        const badge = <NotificationBadge notification={this.state.notificationState} allowNoCount={true}/>;
 | 
			
		||||
 | 
			
		||||
        // TODO: the original RoomTile uses state for the room name. Do we need to?
 | 
			
		||||
        let name = this.props.room.name;
 | 
			
		||||
@@ -294,11 +289,6 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
			
		||||
        );
 | 
			
		||||
        if (this.props.isMinimized) nameContainer = null;
 | 
			
		||||
 | 
			
		||||
        let globe = null;
 | 
			
		||||
        if (this.isPublicRoom && this.props.tag !== DefaultTagID.DM) {
 | 
			
		||||
            globe = <span className='mx_RoomTile2_publicRoom' />; // sizing and such set by CSS
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const avatarSize = 32;
 | 
			
		||||
        return (
 | 
			
		||||
            <React.Fragment>
 | 
			
		||||
@@ -316,7 +306,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
			
		||||
                        >
 | 
			
		||||
                            <div className="mx_RoomTile2_avatarContainer">
 | 
			
		||||
                                <RoomAvatar room={this.props.room} width={avatarSize} height={avatarSize}/>
 | 
			
		||||
                                {globe}
 | 
			
		||||
                                <RoomTileIcon room={this.props.room} tag={this.props.tag}/>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            {nameContainer}
 | 
			
		||||
                            <div className="mx_RoomTile2_badgeContainer">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										148
									
								
								src/components/views/rooms/RoomTileIcon.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								src/components/views/rooms/RoomTileIcon.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2015, 2016 OpenMarket Ltd
 | 
			
		||||
Copyright 2017 New Vector Ltd
 | 
			
		||||
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
 | 
			
		||||
Copyright 2019, 2020 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 React from "react";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
 | 
			
		||||
import AccessibleButton from "../../views/elements/AccessibleButton";
 | 
			
		||||
import RoomAvatar from "../../views/avatars/RoomAvatar";
 | 
			
		||||
import ActiveRoomObserver from "../../../ActiveRoomObserver";
 | 
			
		||||
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
 | 
			
		||||
import { User } from "matrix-js-sdk/src/models/user";
 | 
			
		||||
import {MatrixEvent} from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import DMRoomMap from "../../../utils/DMRoomMap";
 | 
			
		||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import SdkConfig from "../../../SdkConfig";
 | 
			
		||||
import { isPresenceEnabled } from "../../../utils/presence";
 | 
			
		||||
 | 
			
		||||
enum Icon {
 | 
			
		||||
    // Note: the names here are used in CSS class names
 | 
			
		||||
    None = "NONE", // ... except this one
 | 
			
		||||
    Globe = "GLOBE",
 | 
			
		||||
    PresenceOnline = "ONLINE",
 | 
			
		||||
    PresenceAway = "AWAY",
 | 
			
		||||
    PresenceOffline = "OFFLINE",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IProps {
 | 
			
		||||
    room: Room;
 | 
			
		||||
    tag: TagID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IState {
 | 
			
		||||
    icon: Icon;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class RoomTileIcon extends React.Component<IProps, IState> {
 | 
			
		||||
    private isUnmounted = false;
 | 
			
		||||
    private dmUser: User;
 | 
			
		||||
    private isWatchingTimeline = false;
 | 
			
		||||
 | 
			
		||||
    constructor(props: IProps) {
 | 
			
		||||
        super(props);
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            icon: this.getIcon(),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private get isPublicRoom(): boolean {
 | 
			
		||||
        const joinRules = this.props.room.currentState.getStateEvents("m.room.join_rules", "");
 | 
			
		||||
        const joinRule = joinRules && joinRules.getContent().join_rule;
 | 
			
		||||
        return joinRule === 'public';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public componentWillUnmount() {
 | 
			
		||||
        this.isUnmounted = true;
 | 
			
		||||
        if (this.isWatchingTimeline) this.props.room.off('Room.timeline', this.onRoomTimeline);
 | 
			
		||||
        this.unsubscribePresence();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private unsubscribePresence() {
 | 
			
		||||
        if (this.dmUser) {
 | 
			
		||||
            this.dmUser.off('User.currentlyActive', this.onPresenceUpdate);
 | 
			
		||||
            this.dmUser.off('User.presence', this.onPresenceUpdate);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onRoomTimeline = (ev: MatrixEvent, room: Room) => {
 | 
			
		||||
        if (this.isUnmounted) return;
 | 
			
		||||
 | 
			
		||||
        // apparently these can happen?
 | 
			
		||||
        if (!room) return;
 | 
			
		||||
        if (this.props.room.roomId !== room.roomId) return;
 | 
			
		||||
 | 
			
		||||
        if (ev.getType() === 'm.room.join_rules' || ev.getType() === 'm.room.member') {
 | 
			
		||||
            this.setState({icon: this.getIcon()});
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onPresenceUpdate = () => {
 | 
			
		||||
        if (this.isUnmounted) return;
 | 
			
		||||
 | 
			
		||||
        let newIcon = this.getPresenceIcon();
 | 
			
		||||
        if (newIcon !== this.state.icon) this.setState({icon: newIcon});
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private getPresenceIcon(): Icon {
 | 
			
		||||
        let newIcon = Icon.None;
 | 
			
		||||
 | 
			
		||||
        const isOnline = this.dmUser.currentlyActive || this.dmUser.presence === 'online';
 | 
			
		||||
        if (isOnline) {
 | 
			
		||||
            newIcon = Icon.PresenceOnline;
 | 
			
		||||
        } else if (this.dmUser.presence === 'offline') {
 | 
			
		||||
            newIcon = Icon.PresenceOffline;
 | 
			
		||||
        } else if (this.dmUser.presence === 'unavailable') {
 | 
			
		||||
            newIcon = Icon.PresenceAway;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return newIcon;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private getIcon(): Icon {
 | 
			
		||||
        let defaultIcon = Icon.None;
 | 
			
		||||
        this.unsubscribePresence();
 | 
			
		||||
        if (this.props.tag === DefaultTagID.DM && this.props.room.getJoinedMemberCount() === 2) {
 | 
			
		||||
            // Track presence, if available
 | 
			
		||||
            if (isPresenceEnabled()) {
 | 
			
		||||
                const otherUserId = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId);
 | 
			
		||||
                if (otherUserId) {
 | 
			
		||||
                    this.dmUser = MatrixClientPeg.get().getUser(otherUserId);
 | 
			
		||||
                    if (this.dmUser) {
 | 
			
		||||
                        this.dmUser.on('User.currentlyActive', this.onPresenceUpdate);
 | 
			
		||||
                        this.dmUser.on('User.presence', this.onPresenceUpdate);
 | 
			
		||||
                        defaultIcon = this.getPresenceIcon();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Track publicity
 | 
			
		||||
            defaultIcon = this.isPublicRoom ? Icon.Globe : Icon.None;
 | 
			
		||||
            this.props.room.on('Room.timeline', this.onRoomTimeline);
 | 
			
		||||
            this.isWatchingTimeline = true;
 | 
			
		||||
        }
 | 
			
		||||
        return defaultIcon;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public render(): React.ReactElement {
 | 
			
		||||
        if (this.state.icon === Icon.None) return null;
 | 
			
		||||
 | 
			
		||||
        return <span className={`mx_RoomTileIcon mx_RoomTileIcon_${this.state.icon.toLowerCase()}`} />;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/utils/presence.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/utils/presence.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2020 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 { MatrixClientPeg } from "../MatrixClientPeg";
 | 
			
		||||
import SdkConfig from "../SdkConfig";
 | 
			
		||||
 | 
			
		||||
export function isPresenceEnabled() {
 | 
			
		||||
    const hsUrl = MatrixClientPeg.get().baseUrl;
 | 
			
		||||
    const urls = SdkConfig.get()['enable_presence_by_hs_url'];
 | 
			
		||||
    if (!urls) return true;
 | 
			
		||||
    if (urls[hsUrl] || urls[hsUrl] === undefined) return true;
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user