Merge branch 'develop' of https://github.com/matrix-org/matrix-react-sdk into export-conversations
This commit is contained in:
commit
398d49245f
17 changed files with 182 additions and 113 deletions
|
@ -111,6 +111,29 @@ $roomListCollapsedWidth: 68px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_LeftPanel_dialPadButton {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: $roomlist-button-bg-color;
|
||||||
|
position: relative;
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 8px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
mask-image: url('$(res)/img/element-icons/call/dialpad.svg');
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
background: $secondary-fg-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.mx_LeftPanel_exploreButton {
|
.mx_LeftPanel_exploreButton {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
@ -185,6 +208,12 @@ $roomListCollapsedWidth: 68px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
.mx_LeftPanel_dialPadButton {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-top: 8px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_LeftPanel_exploreButton {
|
.mx_LeftPanel_exploreButton {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
|
|
@ -17,4 +17,9 @@ limitations under the License.
|
||||||
.mx_TextualEvent {
|
.mx_TextualEvent {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $accent-color;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AccessibleButton {
|
.mx_AccessibleButton_hasKind {
|
||||||
padding: 8px 22px;
|
padding: 8px 22px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
3
res/img/element-icons/call/dialpad.svg
Normal file
3
res/img/element-icons/call/dialpad.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="12" height="18" viewBox="0 0 12 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 14.25C5.175 14.25 4.5 14.925 4.5 15.75C4.5 16.575 5.175 17.25 6 17.25C6.825 17.25 7.5 16.575 7.5 15.75C7.5 14.925 6.825 14.25 6 14.25ZM1.5 0.75C0.675 0.75 0 1.425 0 2.25C0 3.075 0.675 3.75 1.5 3.75C2.325 3.75 3 3.075 3 2.25C3 1.425 2.325 0.75 1.5 0.75ZM1.5 5.25C0.675 5.25 0 5.925 0 6.75C0 7.575 0.675 8.25 1.5 8.25C2.325 8.25 3 7.575 3 6.75C3 5.925 2.325 5.25 1.5 5.25ZM1.5 9.75C0.675 9.75 0 10.425 0 11.25C0 12.075 0.675 12.75 1.5 12.75C2.325 12.75 3 12.075 3 11.25C3 10.425 2.325 9.75 1.5 9.75ZM10.5 3.75C11.325 3.75 12 3.075 12 2.25C12 1.425 11.325 0.75 10.5 0.75C9.675 0.75 9 1.425 9 2.25C9 3.075 9.675 3.75 10.5 3.75ZM6 9.75C5.175 9.75 4.5 10.425 4.5 11.25C4.5 12.075 5.175 12.75 6 12.75C6.825 12.75 7.5 12.075 7.5 11.25C7.5 10.425 6.825 9.75 6 9.75ZM10.5 9.75C9.675 9.75 9 10.425 9 11.25C9 12.075 9.675 12.75 10.5 12.75C11.325 12.75 12 12.075 12 11.25C12 10.425 11.325 9.75 10.5 9.75ZM10.5 5.25C9.675 5.25 9 5.925 9 6.75C9 7.575 9.675 8.25 10.5 8.25C11.325 8.25 12 7.575 12 6.75C12 5.925 11.325 5.25 10.5 5.25ZM6 5.25C5.175 5.25 4.5 5.925 4.5 6.75C4.5 7.575 5.175 8.25 6 8.25C6.825 8.25 7.5 7.575 7.5 6.75C7.5 5.925 6.825 5.25 6 5.25ZM6 0.75C5.175 0.75 4.5 1.425 4.5 2.25C4.5 3.075 5.175 3.75 6 3.75C6.825 3.75 7.5 3.075 7.5 2.25C7.5 1.425 6.825 0.75 6 0.75Z" fill="#737D8C"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -68,7 +68,7 @@ export const Notifier = {
|
||||||
// or not
|
// or not
|
||||||
pendingEncryptedEventIds: [],
|
pendingEncryptedEventIds: [],
|
||||||
|
|
||||||
notificationMessageForEvent: function(ev: MatrixEvent) {
|
notificationMessageForEvent: function(ev: MatrixEvent): string {
|
||||||
if (typehandlers.hasOwnProperty(ev.getContent().msgtype)) {
|
if (typehandlers.hasOwnProperty(ev.getContent().msgtype)) {
|
||||||
return typehandlers[ev.getContent().msgtype](ev);
|
return typehandlers[ev.getContent().msgtype](ev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,19 @@ 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 { MatrixClientPeg } from './MatrixClientPeg';
|
|
||||||
|
import React from 'react';
|
||||||
|
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import * as Roles from './Roles';
|
import * as Roles from './Roles';
|
||||||
import { isValid3pidInvite } from "./RoomInvite";
|
import { isValid3pidInvite } from "./RoomInvite";
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import { ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES } from "./mjolnir/BanList";
|
import {ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES} from "./mjolnir/BanList";
|
||||||
import { WIDGET_LAYOUT_EVENT_TYPE } from "./stores/widgets/WidgetLayoutStore";
|
import {WIDGET_LAYOUT_EVENT_TYPE} from "./stores/widgets/WidgetLayoutStore";
|
||||||
|
import { RightPanelPhases } from './stores/RightPanelStorePhases';
|
||||||
|
import { Action } from './dispatcher/actions';
|
||||||
|
import defaultDispatcher from './dispatcher/dispatcher';
|
||||||
|
import { SetRightPanelPhasePayload } from './dispatcher/payloads/SetRightPanelPhasePayload';
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
// These functions are frequently used just to check whether an event has
|
// These functions are frequently used just to check whether an event has
|
||||||
|
@ -497,9 +503,33 @@ function textForPowerEvent(event): () => string | null {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForPinnedEvent(event): () => string | null {
|
const onPinnedMessagesClick = (): void => {
|
||||||
|
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
||||||
|
action: Action.SetRightPanelPhase,
|
||||||
|
phase: RightPanelPhases.PinnedMessages,
|
||||||
|
allowClose: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null {
|
||||||
|
if (!SettingsStore.getValue("feature_pinning")) return null;
|
||||||
const senderName = event.sender ? event.sender.name : event.getSender();
|
const senderName = event.sender ? event.sender.name : event.getSender();
|
||||||
return () => _t("%(senderName)s changed the pinned messages for the room.", {senderName});
|
|
||||||
|
if (allowJSX) {
|
||||||
|
return () => (
|
||||||
|
<span>
|
||||||
|
{
|
||||||
|
_t(
|
||||||
|
"%(senderName)s changed the <a>pinned messages</a> for the room.",
|
||||||
|
{ senderName },
|
||||||
|
{ "a": (sub) => <a onClick={onPinnedMessagesClick}> { sub } </a> },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => _t("%(senderName)s changed the pinned messages for the room.", { senderName });
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForWidgetEvent(event): () => string | null {
|
function textForWidgetEvent(event): () => string | null {
|
||||||
|
@ -625,7 +655,7 @@ function textForMjolnirEvent(event): () => string | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IHandlers {
|
interface IHandlers {
|
||||||
[type: string]: (ev: any) => (() => string | null);
|
[type: string]: (ev: MatrixEvent, allowJSX?: boolean) => (() => string | JSX.Element | null);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlers: IHandlers = {
|
const handlers: IHandlers = {
|
||||||
|
@ -668,7 +698,9 @@ export function hasText(ev): boolean {
|
||||||
return Boolean(handler?.(ev));
|
return Boolean(handler?.(ev));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function textForEvent(ev: MatrixEvent): string {
|
export function textForEvent(ev: MatrixEvent): string;
|
||||||
|
export function textForEvent(ev: MatrixEvent, allowJSX: true): string | JSX.Element;
|
||||||
|
export function textForEvent(ev: MatrixEvent, allowJSX = false): string | JSX.Element {
|
||||||
const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()];
|
const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()];
|
||||||
return handler?.(ev)?.() || '';
|
return handler?.(ev, allowJSX)?.() || '';
|
||||||
}
|
}
|
|
@ -24,6 +24,7 @@ import CustomRoomTagPanel from "./CustomRoomTagPanel";
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
import RoomList from "../views/rooms/RoomList";
|
import RoomList from "../views/rooms/RoomList";
|
||||||
|
import CallHandler from "../../CallHandler";
|
||||||
import { HEADER_HEIGHT } from "../views/rooms/RoomSublist";
|
import { HEADER_HEIGHT } from "../views/rooms/RoomSublist";
|
||||||
import { Action } from "../../dispatcher/actions";
|
import { Action } from "../../dispatcher/actions";
|
||||||
import UserMenu from "./UserMenu";
|
import UserMenu from "./UserMenu";
|
||||||
|
@ -124,6 +125,10 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
this.setState({ activeSpace });
|
this.setState({ activeSpace });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onDialPad = () => {
|
||||||
|
dis.fire(Action.OpenDialPad);
|
||||||
|
}
|
||||||
|
|
||||||
private onExplore = () => {
|
private onExplore = () => {
|
||||||
dis.fire(Action.ViewRoomDirectory);
|
dis.fire(Action.ViewRoomDirectory);
|
||||||
};
|
};
|
||||||
|
@ -397,7 +402,20 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderSearchExplore(): React.ReactNode {
|
private renderSearchDialExplore(): React.ReactNode {
|
||||||
|
let dialPadButton = null;
|
||||||
|
|
||||||
|
// If we have dialer support, show a button to bring up the dial pad
|
||||||
|
// to start a new call
|
||||||
|
if (CallHandler.sharedInstance().getSupportsPstnProtocol()) {
|
||||||
|
dialPadButton =
|
||||||
|
<AccessibleTooltipButton
|
||||||
|
className={classNames("mx_LeftPanel_dialPadButton", {})}
|
||||||
|
onClick={this.onDialPad}
|
||||||
|
title={_t("Open dial pad")}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="mx_LeftPanel_filterContainer"
|
className="mx_LeftPanel_filterContainer"
|
||||||
|
@ -410,6 +428,9 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
onSelectRoom={this.selectRoom}
|
onSelectRoom={this.selectRoom}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{dialPadButton}
|
||||||
|
|
||||||
<AccessibleTooltipButton
|
<AccessibleTooltipButton
|
||||||
className={classNames("mx_LeftPanel_exploreButton", {
|
className={classNames("mx_LeftPanel_exploreButton", {
|
||||||
mx_LeftPanel_exploreButton_space: !!this.state.activeSpace,
|
mx_LeftPanel_exploreButton_space: !!this.state.activeSpace,
|
||||||
|
@ -458,7 +479,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
{leftLeftPanel}
|
{leftLeftPanel}
|
||||||
<aside className="mx_LeftPanel_roomListContainer">
|
<aside className="mx_LeftPanel_roomListContainer">
|
||||||
{this.renderHeader()}
|
{this.renderHeader()}
|
||||||
{this.renderSearchExplore()}
|
{this.renderSearchDialExplore()}
|
||||||
{this.renderBreadcrumbs()}
|
{this.renderBreadcrumbs()}
|
||||||
<RoomListNumResults onVisibilityChange={this.refreshStickyHeaders} />
|
<RoomListNumResults onVisibilityChange={this.refreshStickyHeaders} />
|
||||||
<div className="mx_LeftPanel_roomListWrapper">
|
<div className="mx_LeftPanel_roomListWrapper">
|
||||||
|
|
|
@ -14,58 +14,60 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {RefObject, useContext, useRef, useState} from "react";
|
import React, { RefObject, useContext, useRef, useState } from "react";
|
||||||
import {EventType} from "matrix-js-sdk/src/@types/event";
|
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
import {Room} from "matrix-js-sdk/src/models/room";
|
import { Preset } from "matrix-js-sdk/src/@types/partials";
|
||||||
import {EventSubscription} from "fbemitter";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { EventSubscription } from "fbemitter";
|
||||||
|
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import RoomAvatar from "../views/avatars/RoomAvatar";
|
import RoomAvatar from "../views/avatars/RoomAvatar";
|
||||||
import {_t} from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||||
import RoomName from "../views/elements/RoomName";
|
import RoomName from "../views/elements/RoomName";
|
||||||
import RoomTopic from "../views/elements/RoomTopic";
|
import RoomTopic from "../views/elements/RoomTopic";
|
||||||
import InlineSpinner from "../views/elements/InlineSpinner";
|
import InlineSpinner from "../views/elements/InlineSpinner";
|
||||||
import {inviteMultipleToRoom, showRoomInviteDialog} from "../../RoomInvite";
|
import { inviteMultipleToRoom, showRoomInviteDialog } from "../../RoomInvite";
|
||||||
import {useRoomMembers} from "../../hooks/useRoomMembers";
|
import { useRoomMembers } from "../../hooks/useRoomMembers";
|
||||||
import createRoom, {IOpts} from "../../createRoom";
|
import createRoom, { IOpts } from "../../createRoom";
|
||||||
import Field from "../views/elements/Field";
|
import Field from "../views/elements/Field";
|
||||||
import {useEventEmitter} from "../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../hooks/useEventEmitter";
|
||||||
import withValidation from "../views/elements/Validation";
|
import withValidation from "../views/elements/Validation";
|
||||||
import * as Email from "../../email";
|
import * as Email from "../../email";
|
||||||
import defaultDispatcher from "../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||||
import {Action} from "../../dispatcher/actions";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
|
import { Action } from "../../dispatcher/actions";
|
||||||
import ResizeNotifier from "../../utils/ResizeNotifier"
|
import ResizeNotifier from "../../utils/ResizeNotifier"
|
||||||
import MainSplit from './MainSplit';
|
import MainSplit from './MainSplit';
|
||||||
import ErrorBoundary from "../views/elements/ErrorBoundary";
|
import ErrorBoundary from "../views/elements/ErrorBoundary";
|
||||||
import {ActionPayload} from "../../dispatcher/payloads";
|
import { ActionPayload } from "../../dispatcher/payloads";
|
||||||
import RightPanel from "./RightPanel";
|
import RightPanel from "./RightPanel";
|
||||||
import RightPanelStore from "../../stores/RightPanelStore";
|
import RightPanelStore from "../../stores/RightPanelStore";
|
||||||
import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
||||||
import {SetRightPanelPhasePayload} from "../../dispatcher/payloads/SetRightPanelPhasePayload";
|
import { SetRightPanelPhasePayload } from "../../dispatcher/payloads/SetRightPanelPhasePayload";
|
||||||
import {useStateArray} from "../../hooks/useStateArray";
|
import { useStateArray } from "../../hooks/useStateArray";
|
||||||
import SpacePublicShare from "../views/spaces/SpacePublicShare";
|
import SpacePublicShare from "../views/spaces/SpacePublicShare";
|
||||||
import {showAddExistingRooms, showCreateNewRoom, shouldShowSpaceSettings, showSpaceSettings} from "../../utils/space";
|
import { shouldShowSpaceSettings, showAddExistingRooms, showCreateNewRoom, showSpaceSettings } from "../../utils/space";
|
||||||
import {showRoom, SpaceHierarchy} from "./SpaceRoomDirectory";
|
import { showRoom, SpaceHierarchy } from "./SpaceRoomDirectory";
|
||||||
import MemberAvatar from "../views/avatars/MemberAvatar";
|
import MemberAvatar from "../views/avatars/MemberAvatar";
|
||||||
import {useStateToggle} from "../../hooks/useStateToggle";
|
import { useStateToggle } from "../../hooks/useStateToggle";
|
||||||
import SpaceStore from "../../stores/SpaceStore";
|
import SpaceStore from "../../stores/SpaceStore";
|
||||||
import FacePile from "../views/elements/FacePile";
|
import FacePile from "../views/elements/FacePile";
|
||||||
import {AddExistingToSpace} from "../views/dialogs/AddExistingToSpaceDialog";
|
import { AddExistingToSpace } from "../views/dialogs/AddExistingToSpaceDialog";
|
||||||
import {ChevronFace, ContextMenuButton, useContextMenu} from "./ContextMenu";
|
import { ChevronFace, ContextMenuButton, useContextMenu } from "./ContextMenu";
|
||||||
import IconizedContextMenu, {
|
import IconizedContextMenu, {
|
||||||
IconizedContextMenuOption,
|
IconizedContextMenuOption,
|
||||||
IconizedContextMenuOptionList,
|
IconizedContextMenuOptionList,
|
||||||
} from "../views/context_menus/IconizedContextMenu";
|
} from "../views/context_menus/IconizedContextMenu";
|
||||||
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
||||||
import {BetaPill} from "../views/beta/BetaCard";
|
import { BetaPill } from "../views/beta/BetaCard";
|
||||||
import { UserTab } from "../views/dialogs/UserSettingsDialog";
|
import { UserTab } from "../views/dialogs/UserSettingsDialog";
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
import dis from "../../dispatcher/dispatcher";
|
|
||||||
import Modal from "../../Modal";
|
import Modal from "../../Modal";
|
||||||
import BetaFeedbackDialog from "../views/dialogs/BetaFeedbackDialog";
|
import BetaFeedbackDialog from "../views/dialogs/BetaFeedbackDialog";
|
||||||
import SdkConfig from "../../SdkConfig";
|
import SdkConfig from "../../SdkConfig";
|
||||||
import { Preset } from "matrix-js-sdk/src/@types/partials";
|
import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership";
|
||||||
|
import { JoinRule } from "../views/settings/tabs/room/SecurityRoomSettingsTab";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
space: Room;
|
space: Room;
|
||||||
|
@ -178,6 +180,9 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
|
||||||
|
|
||||||
const spacesEnabled = SettingsStore.getValue("feature_spaces");
|
const spacesEnabled = SettingsStore.getValue("feature_spaces");
|
||||||
|
|
||||||
|
const cannotJoin = getEffectiveMembership(myMembership) === EffectiveMembership.Leave
|
||||||
|
&& space.getJoinRule() !== JoinRule.Public;
|
||||||
|
|
||||||
let inviterSection;
|
let inviterSection;
|
||||||
let joinButtons;
|
let joinButtons;
|
||||||
if (myMembership === "join") {
|
if (myMembership === "join") {
|
||||||
|
@ -244,7 +249,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
onJoinButtonClicked();
|
onJoinButtonClicked();
|
||||||
}}
|
}}
|
||||||
disabled={!spacesEnabled}
|
disabled={!spacesEnabled || cannotJoin}
|
||||||
>
|
>
|
||||||
{ _t("Join") }
|
{ _t("Join") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
@ -255,6 +260,30 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
|
||||||
joinButtons = <InlineSpinner />;
|
joinButtons = <InlineSpinner />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let footer;
|
||||||
|
if (!spacesEnabled) {
|
||||||
|
footer = <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
|
||||||
|
{ myMembership === "join"
|
||||||
|
? _t("To view %(spaceName)s, turn on the <a>Spaces beta</a>", {
|
||||||
|
spaceName: space.name,
|
||||||
|
}, {
|
||||||
|
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
|
||||||
|
})
|
||||||
|
: _t("To join %(spaceName)s, turn on the <a>Spaces beta</a>", {
|
||||||
|
spaceName: space.name,
|
||||||
|
}, {
|
||||||
|
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>;
|
||||||
|
} else if (cannotJoin) {
|
||||||
|
footer = <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
|
||||||
|
{ _t("To view %(spaceName)s, you need an invite", {
|
||||||
|
spaceName: space.name,
|
||||||
|
}) }
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
return <div className="mx_SpaceRoomView_preview">
|
return <div className="mx_SpaceRoomView_preview">
|
||||||
<BetaPill onClick={onBetaClick} />
|
<BetaPill onClick={onBetaClick} />
|
||||||
{ inviterSection }
|
{ inviterSection }
|
||||||
|
@ -274,20 +303,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
|
||||||
<div className="mx_SpaceRoomView_preview_joinButtons">
|
<div className="mx_SpaceRoomView_preview_joinButtons">
|
||||||
{ joinButtons }
|
{ joinButtons }
|
||||||
</div>
|
</div>
|
||||||
{ !spacesEnabled && <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
|
{ footer }
|
||||||
{ myMembership === "join"
|
|
||||||
? _t("To view %(spaceName)s, turn on the <a>Spaces beta</a>", {
|
|
||||||
spaceName: space.name,
|
|
||||||
}, {
|
|
||||||
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
|
|
||||||
})
|
|
||||||
: _t("To join %(spaceName)s, turn on the <a>Spaces beta</a>", {
|
|
||||||
spaceName: space.name,
|
|
||||||
}, {
|
|
||||||
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div> }
|
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ export default class TextualEvent extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const text = TextForEvent.textForEvent(this.props.mxEvent);
|
const text = TextForEvent.textForEvent(this.props.mxEvent, true);
|
||||||
if (text == null || text.length === 0) return null;
|
if (text == null || text.length === 0) return null;
|
||||||
return (
|
return (
|
||||||
<div className="mx_TextualEvent">{ text }</div>
|
<div className="mx_TextualEvent">{ text }</div>
|
||||||
|
|
|
@ -41,11 +41,11 @@ export default class PresenceLabel extends React.Component<IProps> {
|
||||||
// XXX: This would be better handled using a culture-aware library, but we don't use one yet.
|
// XXX: This would be better handled using a culture-aware library, but we don't use one yet.
|
||||||
private getDuration(time: number): string {
|
private getDuration(time: number): string {
|
||||||
if (!time) return;
|
if (!time) return;
|
||||||
const t = time / 1000;
|
const t = Math.round(time / 1000);
|
||||||
const s = t % 60;
|
const s = t % 60;
|
||||||
const m = t / 60 % 60;
|
const m = Math.round(t / 60) % 60;
|
||||||
const h = t / (60 * 60) % 24;
|
const h = Math.round(t / (60 * 60)) % 24;
|
||||||
const d = t / (60 * 60 * 24);
|
const d = Math.round(t / (60 * 60 * 24));
|
||||||
if (t < 60) {
|
if (t < 60) {
|
||||||
if (t < 0) {
|
if (t < 0) {
|
||||||
return _t("%(duration)ss", { duration: 0 });
|
return _t("%(duration)ss", { duration: 0 });
|
||||||
|
|
|
@ -45,7 +45,6 @@ import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
|
||||||
import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../context_menus/IconizedContextMenu";
|
import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../context_menus/IconizedContextMenu";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
|
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
|
||||||
import CallHandler from "../../../CallHandler";
|
|
||||||
import SpaceStore, {ISuggestedRoom, SUGGESTED_ROOMS} from "../../../stores/SpaceStore";
|
import SpaceStore, {ISuggestedRoom, SUGGESTED_ROOMS} from "../../../stores/SpaceStore";
|
||||||
import {showAddExistingRooms, showCreateNewRoom, showSpaceInvite} from "../../../utils/space";
|
import {showAddExistingRooms, showCreateNewRoom, showSpaceInvite} from "../../../utils/space";
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||||
|
@ -103,38 +102,6 @@ interface ITagAestheticsMap {
|
||||||
[tagId: TagID]: ITagAesthetics;
|
[tagId: TagID]: ITagAesthetics;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have no dialer support, we just show the create chat dialog
|
|
||||||
const dmOnAddRoom = (dispatcher?: Dispatcher<ActionPayload>) => {
|
|
||||||
(dispatcher || defaultDispatcher).dispatch({action: 'view_create_chat'});
|
|
||||||
};
|
|
||||||
|
|
||||||
// If we have dialer support, show a context menu so the user can pick between
|
|
||||||
// the dialer and the create chat dialog
|
|
||||||
const dmAddRoomContextMenu = (onFinished: () => void) => {
|
|
||||||
return <IconizedContextMenuOptionList first>
|
|
||||||
<IconizedContextMenuOption
|
|
||||||
label={_t("Start a Conversation")}
|
|
||||||
iconClassName="mx_RoomList_iconPlus"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
onFinished();
|
|
||||||
defaultDispatcher.dispatch({action: "view_create_chat"});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<IconizedContextMenuOption
|
|
||||||
label={_t("Open dial pad")}
|
|
||||||
iconClassName="mx_RoomList_iconDialpad"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
onFinished();
|
|
||||||
defaultDispatcher.fire(Action.OpenDialPad);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconizedContextMenuOptionList>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const TAG_AESTHETICS: ITagAestheticsMap = {
|
const TAG_AESTHETICS: ITagAestheticsMap = {
|
||||||
[DefaultTagID.Invite]: {
|
[DefaultTagID.Invite]: {
|
||||||
sectionLabel: _td("Invites"),
|
sectionLabel: _td("Invites"),
|
||||||
|
@ -151,8 +118,9 @@ const TAG_AESTHETICS: ITagAestheticsMap = {
|
||||||
isInvite: false,
|
isInvite: false,
|
||||||
defaultHidden: false,
|
defaultHidden: false,
|
||||||
addRoomLabel: _td("Start chat"),
|
addRoomLabel: _td("Start chat"),
|
||||||
// Either onAddRoom or addRoomContextMenu are set depending on whether we
|
onAddRoom: (dispatcher?: Dispatcher<ActionPayload>) => {
|
||||||
// have dialer support.
|
(dispatcher || defaultDispatcher).dispatch({action: 'view_create_chat'});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[DefaultTagID.Untagged]: {
|
[DefaultTagID.Untagged]: {
|
||||||
sectionLabel: _td("Rooms"),
|
sectionLabel: _td("Rooms"),
|
||||||
|
@ -271,7 +239,6 @@ function customTagAesthetics(tagId: TagID): ITagAesthetics {
|
||||||
export default class RoomList extends React.PureComponent<IProps, IState> {
|
export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
private dispatcherRef;
|
private dispatcherRef;
|
||||||
private customTagStoreRef;
|
private customTagStoreRef;
|
||||||
private tagAesthetics: ITagAestheticsMap;
|
|
||||||
private roomStoreToken: fbEmitter.EventSubscription;
|
private roomStoreToken: fbEmitter.EventSubscription;
|
||||||
|
|
||||||
constructor(props: IProps) {
|
constructor(props: IProps) {
|
||||||
|
@ -282,10 +249,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
isNameFiltering: !!RoomListStore.instance.getFirstNameFilterCondition(),
|
isNameFiltering: !!RoomListStore.instance.getFirstNameFilterCondition(),
|
||||||
suggestedRooms: SpaceStore.instance.suggestedRooms,
|
suggestedRooms: SpaceStore.instance.suggestedRooms,
|
||||||
};
|
};
|
||||||
|
|
||||||
// shallow-copy from the template as we need to make modifications to it
|
|
||||||
this.tagAesthetics = objectShallowClone(TAG_AESTHETICS);
|
|
||||||
this.updateDmAddRoomAction();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
|
@ -311,17 +274,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private updateDmAddRoomAction() {
|
|
||||||
const dmTagAesthetics = objectShallowClone(TAG_AESTHETICS[DefaultTagID.DM]);
|
|
||||||
if (CallHandler.sharedInstance().getSupportsPstnProtocol()) {
|
|
||||||
dmTagAesthetics.addRoomContextMenu = dmAddRoomContextMenu;
|
|
||||||
} else {
|
|
||||||
dmTagAesthetics.onAddRoom = dmOnAddRoom;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tagAesthetics[DefaultTagID.DM] = dmTagAesthetics;
|
|
||||||
}
|
|
||||||
|
|
||||||
private onAction = (payload: ActionPayload) => {
|
private onAction = (payload: ActionPayload) => {
|
||||||
if (payload.action === Action.ViewRoomDelta) {
|
if (payload.action === Action.ViewRoomDelta) {
|
||||||
const viewRoomDeltaPayload = payload as ViewRoomDeltaPayload;
|
const viewRoomDeltaPayload = payload as ViewRoomDeltaPayload;
|
||||||
|
@ -335,7 +287,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (payload.action === Action.PstnSupportUpdated) {
|
} else if (payload.action === Action.PstnSupportUpdated) {
|
||||||
this.updateDmAddRoomAction();
|
|
||||||
this.updateLists();
|
this.updateLists();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -524,7 +475,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
const aesthetics: ITagAesthetics = isCustomTag(orderedTagId)
|
const aesthetics: ITagAesthetics = isCustomTag(orderedTagId)
|
||||||
? customTagAesthetics(orderedTagId)
|
? customTagAesthetics(orderedTagId)
|
||||||
: this.tagAesthetics[orderedTagId];
|
: TAG_AESTHETICS[orderedTagId];
|
||||||
if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`);
|
if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`);
|
||||||
|
|
||||||
// The cost of mounting/unmounting this component offsets the cost
|
// The cost of mounting/unmounting this component offsets the cost
|
||||||
|
|
|
@ -33,6 +33,9 @@ export enum JoinRule {
|
||||||
Public = "public",
|
Public = "public",
|
||||||
Knock = "knock",
|
Knock = "knock",
|
||||||
Invite = "invite",
|
Invite = "invite",
|
||||||
|
/**
|
||||||
|
* @deprecated Reserved. Should not be used.
|
||||||
|
*/
|
||||||
Private = "private",
|
Private = "private",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,9 @@ const SpaceCreateMenu = ({ onFinished }) => {
|
||||||
events_default: 100,
|
events_default: 100,
|
||||||
...Visibility.Public ? { invite: 0 } : {},
|
...Visibility.Public ? { invite: 0 } : {},
|
||||||
},
|
},
|
||||||
room_alias_name: alias ? alias.substr(1, alias.indexOf(":") - 1) : undefined,
|
room_alias_name: visibility === Visibility.Public && alias
|
||||||
|
? alias.substr(1, alias.indexOf(":") - 1)
|
||||||
|
: undefined,
|
||||||
topic,
|
topic,
|
||||||
},
|
},
|
||||||
spinner: false,
|
spinner: false,
|
||||||
|
|
|
@ -62,9 +62,9 @@ const SpaceSettingsVisibilityTab = ({ matrixClient: cli, space }: IProps) => {
|
||||||
const userId = cli.getUserId();
|
const userId = cli.getUserId();
|
||||||
|
|
||||||
const [visibility, setVisibility] = useLocalEcho<SpaceVisibility>(
|
const [visibility, setVisibility] = useLocalEcho<SpaceVisibility>(
|
||||||
() => space.getJoinRule() === JoinRule.Private ? SpaceVisibility.Private : SpaceVisibility.Unlisted,
|
() => space.getJoinRule() === JoinRule.Invite ? SpaceVisibility.Private : SpaceVisibility.Unlisted,
|
||||||
visibility => cli.sendStateEvent(space.roomId, EventType.RoomJoinRules, {
|
visibility => cli.sendStateEvent(space.roomId, EventType.RoomJoinRules, {
|
||||||
join_rule: visibility === SpaceVisibility.Unlisted ? JoinRule.Public : JoinRule.Private,
|
join_rule: visibility === SpaceVisibility.Unlisted ? JoinRule.Public : JoinRule.Invite,
|
||||||
}, ""),
|
}, ""),
|
||||||
() => setError(_t("Failed to update the visibility of this space")),
|
() => setError(_t("Failed to update the visibility of this space")),
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,6 +27,11 @@ export interface SetRightPanelPhasePayload extends ActionPayload {
|
||||||
|
|
||||||
phase: RightPanelPhases;
|
phase: RightPanelPhases;
|
||||||
refireParams?: SetRightPanelPhaseRefireParams;
|
refireParams?: SetRightPanelPhaseRefireParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default SetRightPanelPhase can close the panel, this allows overriding that behaviour
|
||||||
|
*/
|
||||||
|
allowClose?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SetRightPanelPhaseRefireParams {
|
export interface SetRightPanelPhaseRefireParams {
|
||||||
|
|
|
@ -567,6 +567,7 @@
|
||||||
"%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s made future room history visible to unknown (%(visibility)s).",
|
"%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s made future room history visible to unknown (%(visibility)s).",
|
||||||
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s changed the power level of %(powerLevelDiffText)s.",
|
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s changed the power level of %(powerLevelDiffText)s.",
|
||||||
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s",
|
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s",
|
||||||
|
"%(senderName)s changed the <a>pinned messages</a> for the room.": "%(senderName)s changed the <a>pinned messages</a> for the room.",
|
||||||
"%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.",
|
"%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.",
|
||||||
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
|
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
|
||||||
"%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s",
|
"%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s",
|
||||||
|
@ -1599,8 +1600,6 @@
|
||||||
"Search": "Search",
|
"Search": "Search",
|
||||||
"Voice call": "Voice call",
|
"Voice call": "Voice call",
|
||||||
"Video call": "Video call",
|
"Video call": "Video call",
|
||||||
"Start a Conversation": "Start a Conversation",
|
|
||||||
"Open dial pad": "Open dial pad",
|
|
||||||
"Invites": "Invites",
|
"Invites": "Invites",
|
||||||
"Favourites": "Favourites",
|
"Favourites": "Favourites",
|
||||||
"People": "People",
|
"People": "People",
|
||||||
|
@ -2691,6 +2690,7 @@
|
||||||
"Explore Public Rooms": "Explore Public Rooms",
|
"Explore Public Rooms": "Explore Public Rooms",
|
||||||
"Create a Group Chat": "Create a Group Chat",
|
"Create a Group Chat": "Create a Group Chat",
|
||||||
"Upgrade to %(hostSignupBrand)s": "Upgrade to %(hostSignupBrand)s",
|
"Upgrade to %(hostSignupBrand)s": "Upgrade to %(hostSignupBrand)s",
|
||||||
|
"Open dial pad": "Open dial pad",
|
||||||
"Failed to reject invitation": "Failed to reject invitation",
|
"Failed to reject invitation": "Failed to reject invitation",
|
||||||
"Cannot create rooms in this community": "Cannot create rooms in this community",
|
"Cannot create rooms in this community": "Cannot create rooms in this community",
|
||||||
"You do not have permission to create rooms in this community.": "You do not have permission to create rooms in this community.",
|
"You do not have permission to create rooms in this community.": "You do not have permission to create rooms in this community.",
|
||||||
|
@ -2797,6 +2797,7 @@
|
||||||
"<inviter/> invites you": "<inviter/> invites you",
|
"<inviter/> invites you": "<inviter/> invites you",
|
||||||
"To view %(spaceName)s, turn on the <a>Spaces beta</a>": "To view %(spaceName)s, turn on the <a>Spaces beta</a>",
|
"To view %(spaceName)s, turn on the <a>Spaces beta</a>": "To view %(spaceName)s, turn on the <a>Spaces beta</a>",
|
||||||
"To join %(spaceName)s, turn on the <a>Spaces beta</a>": "To join %(spaceName)s, turn on the <a>Spaces beta</a>",
|
"To join %(spaceName)s, turn on the <a>Spaces beta</a>": "To join %(spaceName)s, turn on the <a>Spaces beta</a>",
|
||||||
|
"To view %(spaceName)s, you need an invite": "To view %(spaceName)s, you need an invite",
|
||||||
"Welcome to <name/>": "Welcome to <name/>",
|
"Welcome to <name/>": "Welcome to <name/>",
|
||||||
"Random": "Random",
|
"Random": "Random",
|
||||||
"Support": "Support",
|
"Support": "Support",
|
||||||
|
|
|
@ -161,6 +161,7 @@ export default class RightPanelStore extends Store<ActionPayload> {
|
||||||
case Action.SetRightPanelPhase: {
|
case Action.SetRightPanelPhase: {
|
||||||
let targetPhase = payload.phase;
|
let targetPhase = payload.phase;
|
||||||
let refireParams = payload.refireParams;
|
let refireParams = payload.refireParams;
|
||||||
|
const allowClose = payload.allowClose ?? true;
|
||||||
// redirect to EncryptionPanel if there is an ongoing verification request
|
// redirect to EncryptionPanel if there is an ongoing verification request
|
||||||
if (targetPhase === RightPanelPhases.RoomMemberInfo && payload.refireParams) {
|
if (targetPhase === RightPanelPhases.RoomMemberInfo && payload.refireParams) {
|
||||||
const {member} = payload.refireParams;
|
const {member} = payload.refireParams;
|
||||||
|
@ -192,7 +193,7 @@ export default class RightPanelStore extends Store<ActionPayload> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetPhase === this.state.lastRoomPhase && !refireParams) {
|
if (targetPhase === this.state.lastRoomPhase && !refireParams && allowClose) {
|
||||||
this.setState({
|
this.setState({
|
||||||
showRoomPanel: !this.state.showRoomPanel,
|
showRoomPanel: !this.state.showRoomPanel,
|
||||||
previousPhase: null,
|
previousPhase: null,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue