Move all the capability copy to its own class

pull/21833/head
Travis Ralston 2020-11-19 11:15:42 -07:00
parent 55592d365c
commit ddd8bdc00e
3 changed files with 413 additions and 148 deletions

View File

@ -16,113 +16,19 @@ limitations under the License.
import React from 'react';
import BaseDialog from "./BaseDialog";
import { _t, _td, TranslatedString } from "../../../languageHandler";
import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import { Capability, EventDirection, MatrixCapabilities, Widget, WidgetEventCapability } from "matrix-widget-api";
import {
Capability,
Widget,
WidgetEventCapability,
WidgetKind
} from "matrix-widget-api";
import { objectShallowClone } from "../../../utils/objects";
import { ElementWidgetCapabilities } from "../../../stores/widgets/ElementWidgetCapabilities";
import { EventType, MsgType } from "matrix-js-sdk/lib/@types/event";
import StyledCheckbox from "../elements/StyledCheckbox";
import DialogButtons from "../elements/DialogButtons";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
// TODO: These messaging things can probably get their own store of some sort
const SIMPLE_CAPABILITY_MESSAGES = {
[MatrixCapabilities.AlwaysOnScreen]: _td("Remain on your screen while running"),
[MatrixCapabilities.StickerSending]: _td("Send stickers into your active room"),
[ElementWidgetCapabilities.CanChangeViewedRoom]: _td("Change which room you're viewing"),
};
const SEND_RECV_EVENT_CAPABILITY_MESSAGES = {
[EventType.RoomTopic]: {
// TODO: We probably want to say "this room" when we can
[EventDirection.Send]: _td("Change the topic of your active room"),
[EventDirection.Receive]: _td("See when the topic changes in your active room"),
},
[EventType.RoomName]: {
[EventDirection.Send]: _td("Change the name of your active room"),
[EventDirection.Receive]: _td("See when the name changes in your active room"),
},
[EventType.RoomAvatar]: {
[EventDirection.Send]: _td("Change the avatar of your active room"),
[EventDirection.Receive]: _td("See when the avatar changes in your active room"),
},
// TODO: Add more as needed
};
function textForEventCapabilitiy(cap: WidgetEventCapability): { primary: TranslatedString, byline: TranslatedString } {
let primary: TranslatedString;
let byline: TranslatedString;
if (cap.isState) {
byline = cap.keyStr
? _t("with state key %(stateKey)s", {stateKey: cap.keyStr})
: _t("with an empty state key");
}
const srMessages = SEND_RECV_EVENT_CAPABILITY_MESSAGES[cap.eventType];
if (srMessages && srMessages[cap.direction]) {
primary = _t(srMessages[cap.direction]);
} else {
if (cap.eventType === EventType.RoomMessage) {
if (cap.direction === EventDirection.Receive) {
if (!cap.keyStr) {
primary = _t("See messages sent in your active room");
} else {
if (cap.keyStr === MsgType.Text) {
primary = _t("See text messages sent in your active room");
} else if (cap.keyStr === MsgType.Emote) {
primary = _t("See emotes sent in your active room");
} else if (cap.keyStr === MsgType.Image) {
primary = _t("See images sent in your active room");
} else if (cap.keyStr === MsgType.Video) {
primary = _t("See videos sent in your active room");
} else if (cap.keyStr === MsgType.File) {
primary = _t("See general files sent in your active room");
} else {
primary = _t(
"See <code>%(msgtype)s</code> messages sent in your active room",
{msgtype: cap.keyStr}, {code: sub => <code>{sub}</code>},
);
}
}
} else {
if (!cap.keyStr) {
primary = _t("Send messages as you in your active room");
} else {
if (cap.keyStr === MsgType.Text) {
primary = _t("Send text messages as you in your active room");
} else if (cap.keyStr === MsgType.Emote) {
primary = _t("Send emotes as you in your active room");
} else if (cap.keyStr === MsgType.Image) {
primary = _t("Send images as you in your active room");
} else if (cap.keyStr === MsgType.Video) {
primary = _t("Send videos as you in your active room");
} else if (cap.keyStr === MsgType.File) {
primary = _t("Send general files as you in your active room");
} else {
primary = _t(
"Send <code>%(msgtype)s</code> messages as you in your active room",
{msgtype: cap.keyStr}, {code: sub => <code>{sub}</code>},
);
}
}
}
} else {
if (cap.direction === EventDirection.Receive) {
primary = _t(
"See <code>%(eventType)s</code> events sent in your active room",
{eventType: cap.eventType}, {code: sub => <code>{sub}</code>},
);
} else {
primary = _t(
"Send <code>%(eventType)s</code> events as you in your active room",
{eventType: cap.eventType}, {code: sub => <code>{sub}</code>},
);
}
}
}
return {primary, byline};
}
import { CapabilityText } from "../../../widgets/CapabilityText";
export function getRememberedCapabilitiesForWidget(widget: Widget): Capability[] {
return JSON.parse(localStorage.getItem(`widget_${widget.id}_approved_caps`) || "[]");
@ -135,6 +41,7 @@ function setRememberedCapabilitiesForWidget(widget: Widget, caps: Capability[])
interface IProps extends IDialogProps {
requestedCapabilities: Set<Capability>;
widget: Widget;
widgetKind: WidgetKind; // TODO: Refactor into the Widget class
}
interface IBooleanStates {
@ -194,22 +101,10 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<
public render() {
const checkboxRows = Object.entries(this.state.booleanStates).map(([cap, isChecked], i) => {
const evCap = this.eventPermissionsMap.get(cap);
let text: TranslatedString;
let byline: TranslatedString;
if (evCap) {
const t = textForEventCapabilitiy(evCap);
text = t.primary;
byline = t.byline;
} else if (SIMPLE_CAPABILITY_MESSAGES[cap]) {
text = _t(SIMPLE_CAPABILITY_MESSAGES[cap]);
} else {
text = _t(
"The <code>%(capability)s</code> capability",
{capability: cap}, {code: sub => <code>{sub}</code>},
);
}
const text = CapabilityText.for(cap, this.props.widgetKind);
const byline = text.byline
? <span className="mx_WidgetCapabilitiesPromptDialog_byline">{text.byline}</span>
: null;
return (
<div className="mx_WidgetCapabilitiesPromptDialog_cap">
@ -217,8 +112,8 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<
key={cap + i}
checked={isChecked}
onChange={() => this.onToggle(cap)}
>{text}</StyledCheckbox>
{byline ? <span className="mx_WidgetCapabilitiesPromptDialog_byline">{byline}</span> : null}
>{text.primary}</StyledCheckbox>
{byline}
</div>
);
});

View File

@ -569,6 +569,62 @@
"%(names)s and %(count)s others are typing …|other": "%(names)s and %(count)s others are typing …",
"%(names)s and %(count)s others are typing …|one": "%(names)s and one other is typing …",
"%(names)s and %(lastPerson)s are typing …": "%(names)s and %(lastPerson)s are typing …",
"Remain on your screen when you leave this room (when running)": "Remain on your screen when you leave this room (when running)",
"Remain on your screen while running": "Remain on your screen while running",
"Send stickers into this room": "Send stickers into this room",
"Send stickers into your active room": "Send stickers into your active room",
"Change which room you're viewing": "Change which room you're viewing",
"Change the topic of this room": "Change the topic of this room",
"See when the topic changes in this room": "See when the topic changes in this room",
"Change the topic of your active room": "Change the topic of your active room",
"See when the topic changes in your active room": "See when the topic changes in your active room",
"Change the name of this room": "Change the name of this room",
"See when the name changes in this room": "See when the name changes in this room",
"Change the name of your active room": "Change the name of your active room",
"See when the name changes in your active room": "See when the name changes in your active room",
"Change the avatar of this room": "Change the avatar of this room",
"See when the avatar changes in this room": "See when the avatar changes in this room",
"Change the avatar of your active room": "Change the avatar of your active room",
"See when the avatar changes in your active room": "See when the avatar changes in your active room",
"Send stickers to this room as you": "Send stickers to this room as you",
"See when a sticker is posted in this room": "See when a sticker is posted in this room",
"Send stickers to your active room as you": "Send stickers to your active room as you",
"See when anyone posts a sticker to your active room": "See when anyone posts a sticker to your active room",
"with an empty state key": "with an empty state key",
"with state key %(stateKey)s": "with state key %(stateKey)s",
"Send <b>%(eventType)s</b> events as you in this room": "Send <b>%(eventType)s</b> events as you in this room",
"See <b>%(eventType)s</b> events posted to this room": "See <b>%(eventType)s</b> events posted to this room",
"Send <b>%(eventType)s</b> events as you in your active room": "Send <b>%(eventType)s</b> events as you in your active room",
"See <b>%(eventType)s</b> events posted to your active room": "See <b>%(eventType)s</b> events posted to your active room",
"The <b>%(capability)s</b> capability": "The <b>%(capability)s</b> capability",
"Send messages as you in this room": "Send messages as you in this room",
"Send messages as you in your active room": "Send messages as you in your active room",
"See messages posted to this room": "See messages posted to this room",
"See messages posted to your active room": "See messages posted to your active room",
"Send text messages as you in this room": "Send text messages as you in this room",
"Send text messages as you in your active room": "Send text messages as you in your active room",
"See text messages posted to this room": "See text messages posted to this room",
"See text messages posted to your active room": "See text messages posted to your active room",
"Send emotes as you in this room": "Send emotes as you in this room",
"Send emotes as you in your active room": "Send emotes as you in your active room",
"See emotes posted to this room": "See emotes posted to this room",
"See emotes posted to your active room": "See emotes posted to your active room",
"Send images as you in this room": "Send images as you in this room",
"Send images as you in your active room": "Send images as you in your active room",
"See images posted to this room": "See images posted to this room",
"See images posted to your active room": "See images posted to your active room",
"Send videos as you in this room": "Send videos as you in this room",
"Send videos as you in your active room": "Send videos as you in your active room",
"See videos posted to this room": "See videos posted to this room",
"See videos posted to your active room": "See videos posted to your active room",
"Send general files as you in this room": "Send general files as you in this room",
"Send general files as you in your active room": "Send general files as you in your active room",
"See general files posted to this room": "See general files posted to this room",
"See general files posted to your active room": "See general files posted to your active room",
"Send <b>%(msgtype)s</b> messages as you in this room": "Send <b>%(msgtype)s</b> messages as you in this room",
"Send <b>%(msgtype)s</b> messages as you in your active room": "Send <b>%(msgtype)s</b> messages as you in your active room",
"See <b>%(msgtype)s</b> messages posted to this room": "See <b>%(msgtype)s</b> messages posted to this room",
"See <b>%(msgtype)s</b> messages posted to your active room": "See <b>%(msgtype)s</b> messages posted to your active room",
"Cannot reach homeserver": "Cannot reach homeserver",
"Ensure you have a stable internet connection, or get in touch with the server admin": "Ensure you have a stable internet connection, or get in touch with the server admin",
"Your %(brand)s is misconfigured": "Your %(brand)s is misconfigured",
@ -2123,34 +2179,6 @@
"Upload Error": "Upload Error",
"Verify other session": "Verify other session",
"Verification Request": "Verification Request",
"Remain on your screen while running": "Remain on your screen while running",
"Send stickers into your active room": "Send stickers into your active room",
"Change which room you're viewing": "Change which room you're viewing",
"Change the topic of your active room": "Change the topic of your active room",
"See when the topic changes in your active room": "See when the topic changes in your active room",
"Change the name of your active room": "Change the name of your active room",
"See when the name changes in your active room": "See when the name changes in your active room",
"Change the avatar of your active room": "Change the avatar of your active room",
"See when the avatar changes in your active room": "See when the avatar changes in your active room",
"with state key %(stateKey)s": "with state key %(stateKey)s",
"with an empty state key": "with an empty state key",
"See messages sent in your active room": "See messages sent in your active room",
"See text messages sent in your active room": "See text messages sent in your active room",
"See emotes sent in your active room": "See emotes sent in your active room",
"See images sent in your active room": "See images sent in your active room",
"See videos sent in your active room": "See videos sent in your active room",
"See general files sent in your active room": "See general files sent in your active room",
"See <code>%(msgtype)s</code> messages sent in your active room": "See <code>%(msgtype)s</code> messages sent in your active room",
"Send messages as you in your active room": "Send messages as you in your active room",
"Send text messages as you in your active room": "Send text messages as you in your active room",
"Send emotes as you in your active room": "Send emotes as you in your active room",
"Send images as you in your active room": "Send images as you in your active room",
"Send videos as you in your active room": "Send videos as you in your active room",
"Send general files as you in your active room": "Send general files as you in your active room",
"Send <code>%(msgtype)s</code> messages as you in your active room": "Send <code>%(msgtype)s</code> messages as you in your active room",
"See <code>%(eventType)s</code> events sent in your active room": "See <code>%(eventType)s</code> events sent in your active room",
"Send <code>%(eventType)s</code> events as you in your active room": "Send <code>%(eventType)s</code> events as you in your active room",
"The <code>%(capability)s</code> capability": "The <code>%(capability)s</code> capability",
"Approve widget permissions": "Approve widget permissions",
"This widget would like to:": "This widget would like to:",
"Remember my selection for this widget": "Remember my selection for this widget",

View File

@ -0,0 +1,342 @@
/*
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 { Capability, EventDirection, MatrixCapabilities, WidgetEventCapability, WidgetKind } from "matrix-widget-api";
import { _t, _td, TranslatedString } from "../languageHandler";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
import { ElementWidgetCapabilities } from "../stores/widgets/ElementWidgetCapabilities";
import React from "react";
type GENERIC_WIDGET_KIND = "generic";
const GENERIC_WIDGET_KIND: GENERIC_WIDGET_KIND = "generic";
interface ISendRecvStaticCapText {
// @ts-ignore - TS wants the key to be a string, but we know better
[eventType: EventType]: {
// @ts-ignore - TS wants the key to be a string, but we know better
[widgetKind: WidgetKind | GENERIC_WIDGET_KIND]: {
// @ts-ignore - TS wants the key to be a string, but we know better
[direction: EventDirection]: string;
};
};
}
interface IStaticCapText {
// @ts-ignore - TS wants the key to be a string, but we know better
[capability: Capability]: {
// @ts-ignore - TS wants the key to be a string, but we know better
[widgetKind: WidgetKind | GENERIC_WIDGET_KIND]: string;
};
}
export interface TranslatedCapabilityText {
primary: TranslatedString;
byline?: TranslatedString;
}
export class CapabilityText {
private static simpleCaps: IStaticCapText = {
[MatrixCapabilities.AlwaysOnScreen]: {
[WidgetKind.Room]: _td("Remain on your screen when you leave this room (when running)"),
[GENERIC_WIDGET_KIND]: _td("Remain on your screen while running"),
},
[MatrixCapabilities.StickerSending]: {
[WidgetKind.Room]: _td("Send stickers into this room"),
[GENERIC_WIDGET_KIND]: _td("Send stickers into your active room"),
},
[ElementWidgetCapabilities.CanChangeViewedRoom]: {
[GENERIC_WIDGET_KIND]: _td("Change which room you're viewing"),
},
};
private static stateSendRecvCaps: ISendRecvStaticCapText = {
[EventType.RoomTopic]: {
[WidgetKind.Room]: {
[EventDirection.Send]: _td("Change the topic of this room"),
[EventDirection.Receive]: _td("See when the topic changes in this room"),
},
[GENERIC_WIDGET_KIND]: {
[EventDirection.Send]: _td("Change the topic of your active room"),
[EventDirection.Receive]: _td("See when the topic changes in your active room"),
},
},
[EventType.RoomName]: {
[WidgetKind.Room]: {
[EventDirection.Send]: _td("Change the name of this room"),
[EventDirection.Receive]: _td("See when the name changes in this room"),
},
[GENERIC_WIDGET_KIND]: {
[EventDirection.Send]: _td("Change the name of your active room"),
[EventDirection.Receive]: _td("See when the name changes in your active room"),
},
},
[EventType.RoomAvatar]: {
[WidgetKind.Room]: {
[EventDirection.Send]: _td("Change the avatar of this room"),
[EventDirection.Receive]: _td("See when the avatar changes in this room"),
},
[GENERIC_WIDGET_KIND]: {
[EventDirection.Send]: _td("Change the avatar of your active room"),
[EventDirection.Receive]: _td("See when the avatar changes in your active room"),
},
},
};
private static nonStateSendRecvCaps: ISendRecvStaticCapText = {
[EventType.Sticker]: {
[WidgetKind.Room]: {
[EventDirection.Send]: _td("Send stickers to this room as you"),
[EventDirection.Receive]: _td("See when a sticker is posted in this room"),
},
[GENERIC_WIDGET_KIND]: {
[EventDirection.Send]: _td("Send stickers to your active room as you"),
[EventDirection.Receive]: _td("See when anyone posts a sticker to your active room"),
},
},
};
private static bylineFor(eventCap: WidgetEventCapability): TranslatedString {
if (eventCap.isState) {
return !eventCap.keyStr
? _t("with an empty state key")
: _t("with state key %(stateKey)s", {stateKey: eventCap.keyStr});
}
return null; // room messages are handled specially
}
public static for(capability: Capability, kind: WidgetKind): TranslatedCapabilityText {
// First see if we have a super simple line of text to provide back
if (CapabilityText.simpleCaps[capability]) {
const textForKind = CapabilityText.simpleCaps[capability];
if (textForKind[kind]) return {primary: _t(textForKind[kind])};
if (textForKind[GENERIC_WIDGET_KIND]) return {primary: _t(textForKind[GENERIC_WIDGET_KIND])};
// ... we'll fall through to the generic capability processing at the end of this
// function if we fail to locate a simple string and the capability isn't for an
// event.
}
// We didn't have a super simple line of text, so try processing the capability as the
// more complex event send/receive permission type.
const [eventCap] = WidgetEventCapability.findEventCapabilities([capability]);
if (eventCap) {
// Special case room messages so they show up a bit cleaner to the user. Result is
// effectively "Send images" instead of "Send messages... of type images" if we were
// to handle the msgtype nuances in this function.
if (!eventCap.isState && eventCap.eventType === EventType.RoomMessage) {
return CapabilityText.forRoomMessageCap(eventCap, kind);
}
// See if we have a static line of text to provide for the given event type and
// direction. The hope is that we do for common event types for friendlier copy.
const evSendRecv = eventCap.isState
? CapabilityText.stateSendRecvCaps
: CapabilityText.nonStateSendRecvCaps;
if (evSendRecv[eventCap.eventType]) {
const textForKind = evSendRecv[eventCap.eventType];
const textForDirection = textForKind[kind] || textForKind[GENERIC_WIDGET_KIND];
if (textForDirection && textForDirection[eventCap.direction]) {
return {
primary: _t(textForDirection[eventCap.direction]),
byline: CapabilityText.bylineFor(eventCap),
};
}
}
// We don't have anything simple, so just return a generic string for the event cap
if (kind === WidgetKind.Room) {
if (eventCap.direction === EventDirection.Send) {
return {
primary: _t("Send <b>%(eventType)s</b> events as you in this room", {
eventType: eventCap.eventType,
}, {
b: sub => <b>{sub}</b>,
}),
byline: CapabilityText.bylineFor(eventCap),
};
} else {
return {
primary: _t("See <b>%(eventType)s</b> events posted to this room", {
eventType: eventCap.eventType,
}, {
b: sub => <b>{sub}</b>,
}),
byline: CapabilityText.bylineFor(eventCap),
};
}
} else { // assume generic
if (eventCap.direction === EventDirection.Send) {
return {
primary: _t("Send <b>%(eventType)s</b> events as you in your active room", {
eventType: eventCap.eventType,
}, {
b: sub => <b>{sub}</b>,
}),
byline: CapabilityText.bylineFor(eventCap),
};
} else {
return {
primary: _t("See <b>%(eventType)s</b> events posted to your active room", {
eventType: eventCap.eventType,
}, {
b: sub => <b>{sub}</b>,
}),
byline: CapabilityText.bylineFor(eventCap),
};
}
}
}
// We don't have enough context to render this capability specially, so we'll present it as-is
return {
primary: _t("The <b>%(capability)s</b> capability", {capability}, {
b: sub => <b>{sub}</b>,
}),
};
}
private static forRoomMessageCap(eventCap: WidgetEventCapability, kind: WidgetKind): TranslatedCapabilityText {
// First handle the case of "all messages" to make the switch later on a bit clearer
if (!eventCap.keyStr) {
if (eventCap.direction === EventDirection.Send) {
return {
primary: kind === WidgetKind.Room
? _t("Send messages as you in this room")
: _t("Send messages as you in your active room"),
};
} else {
return {
primary: kind === WidgetKind.Room
? _t("See messages posted to this room")
: _t("See messages posted to your active room"),
};
}
}
// Now handle all the message types we care about. There are more message types available, however
// they are not as common so we don't bother rendering them. They'll fall into the generic case.
switch(eventCap.keyStr) {
case MsgType.Text: {
if (eventCap.direction === EventDirection.Send) {
return {
primary: kind === WidgetKind.Room
? _t("Send text messages as you in this room")
: _t("Send text messages as you in your active room"),
};
} else {
return {
primary: kind === WidgetKind.Room
? _t("See text messages posted to this room")
: _t("See text messages posted to your active room"),
};
}
}
case MsgType.Emote: {
if (eventCap.direction === EventDirection.Send) {
return {
primary: kind === WidgetKind.Room
? _t("Send emotes as you in this room")
: _t("Send emotes as you in your active room"),
};
} else {
return {
primary: kind === WidgetKind.Room
? _t("See emotes posted to this room")
: _t("See emotes posted to your active room"),
};
}
}
case MsgType.Image: {
if (eventCap.direction === EventDirection.Send) {
return {
primary: kind === WidgetKind.Room
? _t("Send images as you in this room")
: _t("Send images as you in your active room"),
};
} else {
return {
primary: kind === WidgetKind.Room
? _t("See images posted to this room")
: _t("See images posted to your active room"),
};
}
}
case MsgType.Video: {
if (eventCap.direction === EventDirection.Send) {
return {
primary: kind === WidgetKind.Room
? _t("Send videos as you in this room")
: _t("Send videos as you in your active room"),
};
} else {
return {
primary: kind === WidgetKind.Room
? _t("See videos posted to this room")
: _t("See videos posted to your active room"),
};
}
}
case MsgType.File: {
if (eventCap.direction === EventDirection.Send) {
return {
primary: kind === WidgetKind.Room
? _t("Send general files as you in this room")
: _t("Send general files as you in your active room"),
};
} else {
return {
primary: kind === WidgetKind.Room
? _t("See general files posted to this room")
: _t("See general files posted to your active room"),
};
}
}
default: {
let primary: TranslatedString;
if (eventCap.direction === EventDirection.Send) {
if (kind === WidgetKind.Room) {
primary = _t("Send <b>%(msgtype)s</b> messages as you in this room", {
msgtype: eventCap.keyStr,
}, {
b: sub => <b>{sub}</b>,
});
} else {
primary = _t("Send <b>%(msgtype)s</b> messages as you in your active room", {
msgtype: eventCap.keyStr,
}, {
b: sub => <b>{sub}</b>,
});
}
} else {
if (kind === WidgetKind.Room) {
primary = _t("See <b>%(msgtype)s</b> messages posted to this room", {
msgtype: eventCap.keyStr,
}, {
b: sub => <b>{sub}</b>,
});
} else {
primary = _t("See <b>%(msgtype)s</b> messages posted to your active room", {
msgtype: eventCap.keyStr,
}, {
b: sub => <b>{sub}</b>,
});
}
}
return {primary};
}
}
}
}