Merge branches 'develop' and 't3chguy/remove_bluebird' of github.com:matrix-org/matrix-react-sdk into t3chguy/remove_bluebird

This commit is contained in:
Michael Telatynski 2019-11-21 11:15:32 +00:00
commit d3f872bf7a
24 changed files with 262 additions and 107 deletions

View file

@ -57,7 +57,7 @@ import { ValidatedServerConfig } from "../../utils/AutoDiscoveryUtils";
import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils";
import DMRoomMap from '../../utils/DMRoomMap';
import { countRoomsWithNotif } from '../../RoomNotifs';
import { setTheme } from "../../theme";
import { ThemeWatcher } from "../../theme";
import { storeRoomAliasInCache } from '../../RoomAliasCache';
import { defer } from "../../utils/promise";
@ -268,7 +268,8 @@ export default createReactClass({
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
this._themeWatchRef = SettingsStore.watchSetting("theme", null, this._onThemeChanged);
this._themeWatcher = new ThemeWatcher();
this._themeWatcher.start();
this.focusComposer = false;
@ -355,7 +356,7 @@ export default createReactClass({
componentWillUnmount: function() {
Lifecycle.stopMatrixClient();
dis.unregister(this.dispatcherRef);
SettingsStore.unwatchSetting(this._themeWatchRef);
this._themeWatcher.stop();
window.removeEventListener("focus", this.onFocus);
window.removeEventListener('resize', this.handleResize);
this.state.resizeNotifier.removeListener("middlePanelResized", this._dispatchTimelineResize);
@ -378,13 +379,6 @@ export default createReactClass({
}
},
_onThemeChanged: function(settingName, roomId, atLevel, newValue) {
dis.dispatch({
action: 'set_theme',
value: newValue,
});
},
startPageChangeTimer() {
// Tor doesn't support performance
if (!performance || !performance.mark) return null;
@ -666,9 +660,6 @@ export default createReactClass({
});
break;
}
case 'set_theme':
setTheme(payload.value);
break;
case 'on_logging_in':
// We are now logging in, so set the state to reflect that
// NB. This does not touch 'ready' since if our dispatches

View file

@ -34,7 +34,7 @@ import dis from '../../../dispatcher';
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
import classNames from 'classnames';
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
import SettingsStore from "../../../settings/SettingsStore";
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
const ENABLE_REACT_PERF = false;
@ -69,8 +69,11 @@ export default class AppTile extends React.Component {
* @return {Object} Updated component state to be set with setState
*/
_getNewState(newProps) {
const widgetPermissionId = [newProps.room.roomId, encodeURIComponent(newProps.url)].join('_');
const hasPermissionToLoad = localStorage.getItem(widgetPermissionId);
// This is a function to make the impact of calling SettingsStore slightly less
const hasPermissionToLoad = () => {
const currentlyAllowedWidgets = SettingsStore.getValue("allowedWidgets", newProps.room.roomId);
return !!currentlyAllowedWidgets[newProps.eventId];
};
const PersistedElement = sdk.getComponent("elements.PersistedElement");
return {
@ -78,10 +81,9 @@ export default class AppTile extends React.Component {
// True while the iframe content is loading
loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this._persistKey),
widgetUrl: this._addWurlParams(newProps.url),
widgetPermissionId: widgetPermissionId,
// 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: hasPermissionToLoad === 'true' || newProps.userId === newProps.creatorUserId,
hasPermissionToLoad: newProps.userId === newProps.creatorUserId || hasPermissionToLoad(),
error: null,
deleting: false,
widgetPageTitle: newProps.widgetPageTitle,
@ -446,24 +448,38 @@ export default class AppTile extends React.Component {
});
}
/* TODO -- Store permission in account data so that it is persisted across multiple devices */
_grantWidgetPermission() {
console.warn('Granting permission to load widget - ', this.state.widgetUrl);
localStorage.setItem(this.state.widgetPermissionId, true);
this.setState({hasPermissionToLoad: true});
// Now that we have permission, fetch the IM token
this.setScalarToken();
const roomId = this.props.room.roomId;
console.info("Granting permission for widget to load: " + this.props.eventId);
const current = SettingsStore.getValue("allowedWidgets", roomId);
current[this.props.eventId] = true;
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
this.setState({hasPermissionToLoad: true});
// Fetch a token for the integration manager, now that we're allowed to
this.setScalarToken();
}).catch(err => {
console.error(err);
// We don't really need to do anything about this - the user will just hit the button again.
});
}
_revokeWidgetPermission() {
console.warn('Revoking permission to load widget - ', this.state.widgetUrl);
localStorage.removeItem(this.state.widgetPermissionId);
this.setState({hasPermissionToLoad: false});
const roomId = this.props.room.roomId;
console.info("Revoking permission for widget to load: " + this.props.eventId);
const current = SettingsStore.getValue("allowedWidgets", roomId);
current[this.props.eventId] = false;
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
this.setState({hasPermissionToLoad: false});
// Force the widget to be non-persistent
ActiveWidgetStore.destroyPersistentWidget(this.props.id);
const PersistedElement = sdk.getComponent("elements.PersistedElement");
PersistedElement.destroyElement(this._persistKey);
// Force the widget to be non-persistent (able to be deleted/forgotten)
ActiveWidgetStore.destroyPersistentWidget(this.props.id);
const PersistedElement = sdk.getComponent("elements.PersistedElement");
PersistedElement.destroyElement(this._persistKey);
}).catch(err => {
console.error(err);
// We don't really need to do anything about this - the user will just hit the button again.
});
}
formatAppTileName() {
@ -720,6 +736,7 @@ AppTile.displayName ='AppTile';
AppTile.propTypes = {
id: PropTypes.string.isRequired,
eventId: PropTypes.string, // required for room widgets
url: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
room: PropTypes.object.isRequired,

View file

@ -67,13 +67,15 @@ module.exports = createReactClass({
return ev.getStateKey() === ActiveWidgetStore.getPersistentWidgetId();
});
const app = WidgetUtils.makeAppConfig(
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(), persistentWidgetInRoomId,
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(),
persistentWidgetInRoomId, appEvent.getId(),
);
const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, persistentWidgetInRoomId);
const AppTile = sdk.getComponent('elements.AppTile');
return <AppTile
key={app.id}
id={app.id}
eventId={app.eventId}
url={app.url}
name={app.name}
type={app.type}

View file

@ -43,7 +43,8 @@ export default class ReactionsRowButtonTooltip extends React.PureComponent {
if (room) {
const senders = [];
for (const reactionEvent of reactionEvents) {
const { name } = room.getMember(reactionEvent.getSender());
const member = room.getMember(reactionEvent.getSender());
const name = member ? member.name : reactionEvent.getSender();
senders.push(name);
}
const shortName = unicodeToShortcode(content);

View file

@ -107,7 +107,9 @@ module.exports = createReactClass({
this.props.room.roomId, WidgetUtils.getRoomWidgets(this.props.room),
);
return widgets.map((ev) => {
return WidgetUtils.makeAppConfig(ev.getStateKey(), ev.getContent(), ev.getSender());
return WidgetUtils.makeAppConfig(
ev.getStateKey(), ev.getContent(), ev.getSender(), ev.getRoomId(), ev.getId(),
);
});
},
@ -159,6 +161,7 @@ module.exports = createReactClass({
return (<AppTile
key={app.id}
id={app.id}
eventId={app.eventId}
url={app.url}
name={app.name}
type={app.type}

View file

@ -25,7 +25,6 @@ import RoomViewStore from '../../../stores/RoomViewStore';
import Stickerpicker from './Stickerpicker';
import { makeRoomPermalink } from '../../../utils/permalinks/Permalinks';
import ContentMessages from '../../../ContentMessages';
import classNames from 'classnames';
import E2EIcon from './E2EIcon';
function ComposerAvatar(props) {
@ -353,13 +352,9 @@ export default class MessageComposer extends React.Component {
);
}
const wrapperClasses = classNames({
mx_MessageComposer_wrapper: true,
mx_MessageComposer_hasE2EIcon: !!this.props.e2eStatus,
});
return (
<div className="mx_MessageComposer">
<div className={wrapperClasses}>
<div className="mx_MessageComposer_wrapper">
<div className="mx_MessageComposer_row">
{ controls }
</div>

View file

@ -460,13 +460,9 @@ export default class SlateMessageComposer extends React.Component {
const showFormatBar = this.state.showFormatting && this.state.inputState.isRichTextEnabled;
const wrapperClasses = classNames({
mx_MessageComposer_wrapper: true,
mx_MessageComposer_hasE2EIcon: !!this.props.e2eStatus,
});
return (
<div className="mx_MessageComposer">
<div className={wrapperClasses}>
<div className="mx_MessageComposer_wrapper">
<div className="mx_MessageComposer_row">
{ controls }
</div>

View file

@ -27,7 +27,7 @@ import LanguageDropdown from "../../../elements/LanguageDropdown";
import AccessibleButton from "../../../elements/AccessibleButton";
import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog";
import PropTypes from "prop-types";
import {enumerateThemes} from "../../../../../theme";
import {enumerateThemes, ThemeWatcher} from "../../../../../theme";
import PlatformPeg from "../../../../../PlatformPeg";
import MatrixClientPeg from "../../../../../MatrixClientPeg";
import sdk from "../../../../..";
@ -50,6 +50,7 @@ export default class GeneralUserSettingsTab extends React.Component {
this.state = {
language: languageHandler.getCurrentLanguage(),
theme: SettingsStore.getValueAt(SettingLevel.ACCOUNT, "theme"),
useSystemTheme: SettingsStore.getValueAt(SettingLevel.DEVICE, "use_system_theme"),
haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()),
serverSupportsSeparateAddAndBind: null,
idServerHasUnsignedTerms: false,
@ -177,16 +178,25 @@ export default class GeneralUserSettingsTab extends React.Component {
// so remember what the value was before we tried to set it so we can revert
const oldTheme = SettingsStore.getValue('theme');
SettingsStore.setValue("theme", null, SettingLevel.ACCOUNT, newTheme).catch(() => {
dis.dispatch({action: 'set_theme', value: oldTheme});
dis.dispatch({action: 'recheck_theme'});
this.setState({theme: oldTheme});
});
this.setState({theme: newTheme});
// The settings watcher doesn't fire until the echo comes back from the
// server, so to make the theme change immediately we need to manually
// do the dispatch now
dis.dispatch({action: 'set_theme', value: newTheme});
// XXX: The local echoed value appears to be unreliable, in particular
// when settings custom themes(!) so adding forceTheme to override
// the value from settings.
dis.dispatch({action: 'recheck_theme', forceTheme: newTheme});
};
_onUseSystemThemeChanged = (checked) => {
this.setState({useSystemTheme: checked});
dis.dispatch({action: 'recheck_theme'});
}
_onPasswordChangeError = (err) => {
// TODO: Figure out a design that doesn't involve replacing the current dialog
let errMsg = err.error || "";
@ -297,11 +307,24 @@ export default class GeneralUserSettingsTab extends React.Component {
_renderThemeSection() {
const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
const themeWatcher = new ThemeWatcher();
let systemThemeSection;
if (themeWatcher.isSystemThemeSupported()) {
systemThemeSection = <div>
<SettingsFlag name="use_system_theme" level={SettingLevel.DEVICE}
onChange={this._onUseSystemThemeChanged}
/>
</div>;
}
return (
<div className="mx_SettingsTab_section mx_GeneralUserSettingsTab_themeSection">
<span className="mx_SettingsTab_subheading">{_t("Theme")}</span>
{systemThemeSection}
<Field id="theme" label={_t("Theme")} element="select"
value={this.state.theme} onChange={this._onThemeChange}>
value={this.state.theme} onChange={this._onThemeChange}
disabled={this.state.useSystemTheme}
>
{Object.entries(enumerateThemes()).map(([theme, text]) => {
return <option key={theme} value={theme}>{text}</option>;
})}