From 37558f1f0d9aaf4e09def6409ddb1644c26c9cb8 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 12 Oct 2020 09:51:49 +0100 Subject: [PATCH] Improve the context menu Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- ...tContextMenu.tsx => WidgetContextMenu.tsx} | 49 ++++++++++++------- src/components/views/elements/AppTile.js | 11 +++-- .../views/right_panel/RoomSummaryCard.tsx | 18 +++++-- .../views/right_panel/WidgetCard.tsx | 4 +- src/i18n/strings/en_EN.json | 13 ++--- src/stores/WidgetStore.ts | 2 +- 6 files changed, 63 insertions(+), 34 deletions(-) rename src/components/views/context_menus/{RoomWidgetContextMenu.tsx => WidgetContextMenu.tsx} (74%) diff --git a/src/components/views/context_menus/RoomWidgetContextMenu.tsx b/src/components/views/context_menus/WidgetContextMenu.tsx similarity index 74% rename from src/components/views/context_menus/RoomWidgetContextMenu.tsx rename to src/components/views/context_menus/WidgetContextMenu.tsx index e904605faa..b77e91ed0b 100644 --- a/src/components/views/context_menus/RoomWidgetContextMenu.tsx +++ b/src/components/views/context_menus/WidgetContextMenu.tsx @@ -29,19 +29,28 @@ import SettingsStore from "../../../settings/SettingsStore"; import {SettingLevel} from "../../../settings/SettingLevel"; import Modal from "../../../Modal"; import QuestionDialog from "../dialogs/QuestionDialog"; +import {WidgetType} from "../../../widgets/WidgetType"; interface IProps extends React.ComponentProps { app: IApp; + userWidget?: boolean; showUnpin?: boolean; // override delete handler onDeleteClick?(): void; } -const RoomWidgetContextMenu: React.FC = ({ onFinished, app, onDeleteClick, showUnpin, ...props}) => { +const WidgetContextMenu: React.FC = ({ + onFinished, + app, + userWidget, + onDeleteClick, + showUnpin, + ...props +}) => { const {room, roomId} = useContext(RoomContext); const widgetMessaging = WidgetMessagingStore.instance.getMessagingForId(app.id); - const canModify = WidgetUtils.canUserModifyWidgets(roomId); + const canModify = userWidget || WidgetUtils.canUserModifyWidgets(roomId); let unpinButton; if (showUnpin) { @@ -80,7 +89,7 @@ const RoomWidgetContextMenu: React.FC = ({ onFinished, app, onDeleteClic let deleteButton; if (onDeleteClick || canModify) { - const onDeleteClick = () => { + const onDeleteClickDefault = () => { // Show delete confirmation dialog Modal.createTrackedDialog('Delete Widget', '', QuestionDialog, { title: _t("Delete Widget"), @@ -97,21 +106,27 @@ const RoomWidgetContextMenu: React.FC = ({ onFinished, app, onDeleteClic }; deleteButton = ; } - const onRevokeClick = () => { - console.info("Revoking permission for widget to load: " + app.eventId); - const current = SettingsStore.getValue("allowedWidgets", roomId); - current[app.eventId] = false; - SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).catch(err => { - console.error(err); - // We don't really need to do anything about this - the user will just hit the button again. - }); - onFinished(); - }; + const isLocalWidget = WidgetType.JITSI.matches(app.type); + let revokeButton; + if (!userWidget && !isLocalWidget) { + const onRevokeClick = () => { + console.info("Revoking permission for widget to load: " + app.eventId); + const current = SettingsStore.getValue("allowedWidgets", roomId); + current[app.eventId] = false; + SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).catch(err => { + console.error(err); + // We don't really need to do anything about this - the user will just hit the button again. + }); + onFinished(); + }; + + revokeButton = ; + } return @@ -119,10 +134,10 @@ const RoomWidgetContextMenu: React.FC = ({ onFinished, app, onDeleteClic { snapshotButton } { editButton } { deleteButton } - + { revokeButton } ; }; -export default RoomWidgetContextMenu; +export default WidgetContextMenu; diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 759359fe32..e540e11633 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -38,7 +38,7 @@ import {SettingLevel} from "../../../settings/SettingLevel"; import {StopGapWidget} from "../../../stores/widgets/StopGapWidget"; import {ElementWidgetActions} from "../../../stores/widgets/ElementWidgetActions"; import {MatrixCapabilities} from "matrix-widget-api"; -import RoomWidgetContextMenu from "../context_menus/RoomWidgetContextMenu"; +import RoomWidgetContextMenu from "../context_menus/WidgetContextMenu"; export default class AppTile extends React.Component { constructor(props) { @@ -62,6 +62,9 @@ export default class AppTile extends React.Component { if (this._usingLocalWidget()) return true; const currentlyAllowedWidgets = SettingsStore.getValue("allowedWidgets", props.room.roomId); + if (currentlyAllowedWidgets[props.app.eventId] === undefined) { + return props.userId === props.creatorUserId; + } return !!currentlyAllowedWidgets[props.app.eventId]; }; @@ -78,7 +81,7 @@ export default class AppTile extends React.Component { loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this._persistKey), // Assume that widget has permission to load if we are the user who // added it to the room, or if explicitly granted by the user - hasPermissionToLoad: newProps.userId === newProps.creatorUserId || this.hasPermissionToLoad(newProps), + hasPermissionToLoad: this.hasPermissionToLoad(newProps), error: null, widgetPageTitle: newProps.widgetPageTitle, menuDisplayed: false, @@ -86,8 +89,7 @@ export default class AppTile extends React.Component { } onAllowedWidgetsChange = () => { - const hasPermissionToLoad = - this.props.userId === this.prop.creatorUserId || this.hasPermissionToLoad(this.props); + const hasPermissionToLoad = this.hasPermissionToLoad(this.props); if (this.state.hasPermissionToLoad && !hasPermissionToLoad) { // Force the widget to be non-persistent (able to be deleted/forgotten) @@ -399,6 +401,7 @@ export default class AppTile extends React.Component { app={this.props.app} onFinished={this._closeContextMenu} showUnpin={!this.props.userWidget} + userWidget={this.props.userWidget} /> ); } diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index 0c6e002d2b..b57bd44122 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -39,13 +39,13 @@ import SettingsStore from "../../../settings/SettingsStore"; import TextWithTooltip from "../elements/TextWithTooltip"; import BaseAvatar from "../avatars/BaseAvatar"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import WidgetStore, {IApp} from "../../../stores/WidgetStore"; +import WidgetStore, {IApp, MAX_PINNED} from "../../../stores/WidgetStore"; import { E2EStatus } from "../../../utils/ShieldUtils"; import RoomContext from "../../../contexts/RoomContext"; import {UIFeature} from "../../../settings/UIFeature"; import {ContextMenuButton} from "../../../accessibility/context_menu/ContextMenuButton"; import {ChevronFace, useContextMenu} from "../../structures/ContextMenu"; -import RoomWidgetContextMenu from "../context_menus/RoomWidgetContextMenu"; +import WidgetContextMenu from "../context_menus/WidgetContextMenu"; interface IProps { room: Room; @@ -129,7 +129,7 @@ const AppRow: React.FC = ({ app }) => { let contextMenu; if (menuDisplayed) { const rect = handle.current.getBoundingClientRect(); - contextMenu = = ({ app }) => { />; } + const cannotPin = !isPinned && !WidgetStore.instance.canPin(app.id); + + let pinTitle: string; + if (cannotPin) { + pinTitle = _t("You can only pin up to %(count)s widgets", { count: MAX_PINNED }); + } else { + pinTitle = isPinned ? _t("Unpin") : _t("Pin"); + } + return
= ({ app }) => { mx_RoomSummaryCard_app_pinned: isPinned, })} onClick={togglePin} - title={isPinned ? _t("Unpin") : _t("Pin")} + title={pinTitle} + disabled={cannotPin} /> = ({ room, widgetId, onClose }) => { if (menuDisplayed) { const rect = handle.current.getBoundingClientRect(); contextMenu = ( - ; } -const MAX_PINNED = 3; +export const MAX_PINNED = 3; // TODO consolidate WidgetEchoStore into this // TODO consolidate ActiveWidgetStore into this