Merge branches 'develop' and 't3chguy/remove_bluebird' of github.com:matrix-org/matrix-react-sdk into t3chguy/remove_bluebird
This commit is contained in:
commit
d3f872bf7a
24 changed files with 262 additions and 107 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>;
|
||||
})}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue