2015-06-23 15:41:25 +00:00
|
|
|
/*
|
2016-01-07 04:06:39 +00:00
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
2017-02-24 11:41:23 +00:00
|
|
|
Copyright 2017 Vector Creations Ltd
|
2019-01-11 13:15:09 +00:00
|
|
|
Copyright 2017-2019 New Vector Ltd
|
2015-06-23 15:41:25 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2016-09-01 10:08:40 +00:00
|
|
|
|
2017-07-12 12:58:14 +00:00
|
|
|
import Promise from 'bluebird';
|
2016-09-01 10:08:40 +00:00
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
import React from 'react';
|
2017-12-26 01:03:18 +00:00
|
|
|
import PropTypes from 'prop-types';
|
2017-05-19 12:53:11 +00:00
|
|
|
import Matrix from "matrix-js-sdk";
|
|
|
|
|
2017-05-27 19:47:09 +00:00
|
|
|
import Analytics from "../../Analytics";
|
2018-07-06 10:00:39 +00:00
|
|
|
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
|
2017-05-19 12:53:11 +00:00
|
|
|
import MatrixClientPeg from "../../MatrixClientPeg";
|
|
|
|
import PlatformPeg from "../../PlatformPeg";
|
|
|
|
import SdkConfig from "../../SdkConfig";
|
|
|
|
import * as RoomListSorter from "../../RoomListSorter";
|
|
|
|
import dis from "../../dispatcher";
|
|
|
|
|
|
|
|
import Modal from "../../Modal";
|
|
|
|
import Tinter from "../../Tinter";
|
|
|
|
import sdk from '../../index';
|
2017-08-16 13:58:30 +00:00
|
|
|
import { showStartChatInviteDialog, showRoomInviteDialog } from '../../RoomInvite';
|
2017-05-19 12:53:11 +00:00
|
|
|
import * as Rooms from '../../Rooms';
|
|
|
|
import linkifyMatrix from "../../linkify-matrix";
|
|
|
|
import * as Lifecycle from '../../Lifecycle';
|
2017-05-26 10:50:32 +00:00
|
|
|
// LifecycleStore is not used but does listen to and dispatch actions
|
2017-06-08 19:56:13 +00:00
|
|
|
require('../../stores/LifecycleStore');
|
2017-05-19 12:53:11 +00:00
|
|
|
import PageTypes from '../../PageTypes';
|
|
|
|
|
|
|
|
import createRoom from "../../createRoom";
|
2017-05-19 08:54:29 +00:00
|
|
|
import KeyRequestHandler from '../../KeyRequestHandler';
|
2017-06-02 13:13:33 +00:00
|
|
|
import { _t, getCurrentLanguage } from '../../languageHandler';
|
2017-11-05 03:13:23 +00:00
|
|
|
import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
|
2018-09-05 16:07:39 +00:00
|
|
|
import { startAnyRegistrationFlow } from "../../Registration.js";
|
2018-09-07 11:18:25 +00:00
|
|
|
import { messageForSyncError } from '../../utils/ErrorUtils';
|
2016-06-08 22:03:46 +00:00
|
|
|
|
2018-12-05 06:34:57 +00:00
|
|
|
const AutoDiscovery = Matrix.AutoDiscovery;
|
|
|
|
|
2018-10-05 11:15:03 +00:00
|
|
|
// Disable warnings for now: we use deprecated bluebird functions
|
|
|
|
// and need to migrate, but they spam the console with warnings.
|
|
|
|
Promise.config({warnings: false});
|
|
|
|
|
2017-06-09 16:18:45 +00:00
|
|
|
/** constants for MatrixChat.state.view */
|
|
|
|
const VIEWS = {
|
2017-06-14 19:04:55 +00:00
|
|
|
// a special initial state which is only used at startup, while we are
|
|
|
|
// trying to re-animate a matrix client or register as a guest.
|
|
|
|
LOADING: 0,
|
|
|
|
|
2019-02-07 16:25:09 +00:00
|
|
|
// we are showing the welcome view
|
|
|
|
WELCOME: 1,
|
|
|
|
|
2017-06-14 19:04:55 +00:00
|
|
|
// we are showing the login view
|
2019-02-07 16:25:09 +00:00
|
|
|
LOGIN: 2,
|
2017-06-14 19:04:55 +00:00
|
|
|
|
|
|
|
// we are showing the registration view
|
2019-02-07 16:25:09 +00:00
|
|
|
REGISTER: 3,
|
2017-06-14 19:04:55 +00:00
|
|
|
|
|
|
|
// completeing the registration flow
|
2019-02-07 16:25:09 +00:00
|
|
|
POST_REGISTRATION: 4,
|
2017-06-14 19:04:55 +00:00
|
|
|
|
|
|
|
// showing the 'forgot password' view
|
2019-02-07 16:25:09 +00:00
|
|
|
FORGOT_PASSWORD: 5,
|
2017-06-14 19:04:55 +00:00
|
|
|
|
|
|
|
// we have valid matrix credentials (either via an explicit login, via the
|
|
|
|
// initial re-animation/guest registration, or via a registration), and are
|
|
|
|
// now setting up a matrixclient to talk to it. This isn't an instant
|
2019-01-25 22:10:54 +00:00
|
|
|
// process because we need to clear out indexeddb. While it is going on we
|
|
|
|
// show a big spinner.
|
2019-02-07 16:25:09 +00:00
|
|
|
LOGGING_IN: 6,
|
2017-06-14 19:04:55 +00:00
|
|
|
|
|
|
|
// we are logged in with an active matrix client.
|
2019-02-07 16:25:09 +00:00
|
|
|
LOGGED_IN: 7,
|
2017-06-09 16:18:45 +00:00
|
|
|
};
|
2016-06-08 22:03:46 +00:00
|
|
|
|
2017-11-10 10:51:28 +00:00
|
|
|
// Actions that are redirected through the onboarding process prior to being
|
|
|
|
// re-dispatched. NOTE: some actions are non-trivial and would require
|
|
|
|
// re-factoring to be included in this list in future.
|
|
|
|
const ONBOARDING_FLOW_STARTERS = [
|
|
|
|
'view_user_settings',
|
|
|
|
'view_create_chat',
|
|
|
|
'view_create_room',
|
2017-11-28 12:08:53 +00:00
|
|
|
'view_create_group',
|
2017-11-10 10:51:28 +00:00
|
|
|
];
|
|
|
|
|
2017-12-08 11:29:21 +00:00
|
|
|
export default React.createClass({
|
2017-06-14 19:04:55 +00:00
|
|
|
// we export this so that the integration tests can use it :-S
|
|
|
|
statics: {
|
|
|
|
VIEWS: VIEWS,
|
|
|
|
},
|
|
|
|
|
2015-11-30 18:11:04 +00:00
|
|
|
displayName: 'MatrixChat',
|
|
|
|
|
|
|
|
propTypes: {
|
2017-12-26 01:03:18 +00:00
|
|
|
config: PropTypes.object,
|
|
|
|
ConferenceHandler: PropTypes.any,
|
|
|
|
onNewScreen: PropTypes.func,
|
|
|
|
registrationUrl: PropTypes.string,
|
|
|
|
enableGuest: PropTypes.bool,
|
2016-08-11 10:00:15 +00:00
|
|
|
|
|
|
|
// the queryParams extracted from the [real] query-string of the URI
|
2017-12-26 01:03:18 +00:00
|
|
|
realQueryParams: PropTypes.object,
|
2016-08-11 10:00:15 +00:00
|
|
|
|
|
|
|
// the initial queryParams extracted from the hash-fragment of the URI
|
2017-12-26 01:03:18 +00:00
|
|
|
startingFragmentQueryParams: PropTypes.object,
|
2016-08-11 10:00:15 +00:00
|
|
|
|
2017-06-16 13:33:14 +00:00
|
|
|
// called when we have completed a token login
|
2017-12-26 01:03:18 +00:00
|
|
|
onTokenLoginCompleted: PropTypes.func,
|
2016-08-12 10:41:06 +00:00
|
|
|
|
2017-03-08 10:25:54 +00:00
|
|
|
// Represents the screen to display as a result of parsing the initial
|
|
|
|
// window.location
|
2017-12-26 01:03:18 +00:00
|
|
|
initialScreenAfterLogin: PropTypes.shape({
|
|
|
|
screen: PropTypes.string.isRequired,
|
|
|
|
params: PropTypes.object,
|
2017-03-08 10:25:54 +00:00
|
|
|
}),
|
|
|
|
|
2016-08-12 10:41:06 +00:00
|
|
|
// displayname, if any, to set on the device when logging
|
|
|
|
// in/registering.
|
2017-12-26 01:03:18 +00:00
|
|
|
defaultDeviceDisplayName: PropTypes.string,
|
2017-03-02 14:40:55 +00:00
|
|
|
|
|
|
|
// A function that makes a registration URL
|
2017-12-26 01:03:18 +00:00
|
|
|
makeRegistrationUrl: PropTypes.func.isRequired,
|
2015-11-30 18:11:04 +00:00
|
|
|
},
|
2015-10-12 09:13:01 +00:00
|
|
|
|
2016-12-02 14:21:07 +00:00
|
|
|
childContextTypes: {
|
2017-12-26 01:03:18 +00:00
|
|
|
appConfig: PropTypes.object,
|
2016-12-02 14:21:07 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
getChildContext: function() {
|
|
|
|
return {
|
|
|
|
appConfig: this.props.config,
|
2017-01-20 14:22:27 +00:00
|
|
|
};
|
2016-12-02 14:21:07 +00:00
|
|
|
},
|
|
|
|
|
2015-06-11 17:25:29 +00:00
|
|
|
getInitialState: function() {
|
2017-05-19 12:53:11 +00:00
|
|
|
const s = {
|
2017-06-09 16:18:45 +00:00
|
|
|
// the master view we are showing.
|
2017-06-14 19:04:55 +00:00
|
|
|
view: VIEWS.LOADING,
|
2017-03-08 10:25:54 +00:00
|
|
|
|
2016-11-24 12:33:31 +00:00
|
|
|
// What the LoggedInView would be showing if visible
|
2016-11-24 16:39:48 +00:00
|
|
|
page_type: null,
|
2016-11-24 12:33:31 +00:00
|
|
|
|
2016-06-14 13:10:49 +00:00
|
|
|
// The ID of the room we're viewing. This is either populated directly
|
|
|
|
// in the case where we view a room by ID or by RoomView when it resolves
|
|
|
|
// what ID an alias points at.
|
|
|
|
currentRoomId: null,
|
2016-08-28 13:04:02 +00:00
|
|
|
|
|
|
|
// If we're trying to just view a user ID (i.e. /user URL), this is it
|
|
|
|
viewUserId: null,
|
2019-01-31 09:19:05 +00:00
|
|
|
// this is persisted as mx_lhs_size, loaded in LoggedInView
|
2017-08-25 11:10:13 +00:00
|
|
|
collapseLhs: false,
|
2018-12-17 14:56:35 +00:00
|
|
|
collapsedRhs: window.localStorage.getItem("mx_rhs_collapsed") === "true",
|
2017-10-25 10:09:48 +00:00
|
|
|
leftDisabled: false,
|
|
|
|
middleDisabled: false,
|
|
|
|
rightDisabled: false,
|
2016-08-15 22:01:02 +00:00
|
|
|
|
|
|
|
version: null,
|
|
|
|
newVersion: null,
|
2016-11-02 15:58:17 +00:00
|
|
|
hasNewVersion: false,
|
|
|
|
newVersionReleaseNotes: null,
|
2017-06-11 18:12:40 +00:00
|
|
|
checkingForUpdate: null,
|
2016-09-30 10:40:27 +00:00
|
|
|
|
2018-05-15 12:15:40 +00:00
|
|
|
showCookieBar: false,
|
|
|
|
|
2016-09-30 10:40:27 +00:00
|
|
|
// Parameters used in the registration dance with the IS
|
|
|
|
register_client_secret: null,
|
|
|
|
register_session_id: null,
|
|
|
|
register_hs_url: null,
|
|
|
|
register_is_url: null,
|
|
|
|
register_id_sid: null,
|
2018-02-08 21:51:07 +00:00
|
|
|
|
2019-01-21 22:11:10 +00:00
|
|
|
// Parameters used for setting up the authentication views
|
2018-12-05 06:34:57 +00:00
|
|
|
defaultServerName: this.props.config.default_server_name,
|
|
|
|
defaultHsUrl: this.props.config.default_hs_url,
|
|
|
|
defaultIsUrl: this.props.config.default_is_url,
|
|
|
|
defaultServerDiscoveryError: null,
|
|
|
|
|
2018-02-08 21:51:07 +00:00
|
|
|
// When showing Modal dialogs we need to set aria-hidden on the root app element
|
|
|
|
// and disable it when there are no dialogs
|
|
|
|
hideToSRUsers: false,
|
2018-09-07 11:18:25 +00:00
|
|
|
|
|
|
|
syncError: null, // If the current syncing status is ERROR, the error object, otherwise null.
|
2015-06-11 17:25:29 +00:00
|
|
|
};
|
2015-09-18 17:39:16 +00:00
|
|
|
return s;
|
2015-06-11 17:25:29 +00:00
|
|
|
},
|
|
|
|
|
2015-12-17 14:56:55 +00:00
|
|
|
getDefaultProps: function() {
|
|
|
|
return {
|
2016-08-11 10:00:15 +00:00
|
|
|
realQueryParams: {},
|
|
|
|
startingFragmentQueryParams: {},
|
2016-06-08 17:45:46 +00:00
|
|
|
config: {},
|
2017-06-16 13:33:14 +00:00
|
|
|
onTokenLoginCompleted: () => {},
|
2015-12-17 14:56:55 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2018-12-05 06:34:57 +00:00
|
|
|
getDefaultServerName: function() {
|
|
|
|
return this.state.defaultServerName;
|
|
|
|
},
|
|
|
|
|
2016-03-06 19:33:36 +00:00
|
|
|
getCurrentHsUrl: function() {
|
2016-03-17 11:33:25 +00:00
|
|
|
if (this.state.register_hs_url) {
|
|
|
|
return this.state.register_hs_url;
|
|
|
|
} else if (MatrixClientPeg.get()) {
|
2016-03-06 19:33:36 +00:00
|
|
|
return MatrixClientPeg.get().getHomeserverUrl();
|
2017-05-19 12:53:11 +00:00
|
|
|
} else {
|
2016-06-21 10:05:37 +00:00
|
|
|
return this.getDefaultHsUrl();
|
2016-03-06 19:33:36 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-12-05 06:34:57 +00:00
|
|
|
getDefaultHsUrl(defaultToMatrixDotOrg) {
|
|
|
|
defaultToMatrixDotOrg = typeof(defaultToMatrixDotOrg) !== 'boolean' ? true : defaultToMatrixDotOrg;
|
|
|
|
if (!this.state.defaultHsUrl && defaultToMatrixDotOrg) return "https://matrix.org";
|
|
|
|
return this.state.defaultHsUrl;
|
2016-06-21 10:05:37 +00:00
|
|
|
},
|
|
|
|
|
2016-05-27 13:57:43 +00:00
|
|
|
getFallbackHsUrl: function() {
|
|
|
|
return this.props.config.fallback_hs_url;
|
|
|
|
},
|
|
|
|
|
2016-03-06 19:33:36 +00:00
|
|
|
getCurrentIsUrl: function() {
|
2016-03-17 11:33:25 +00:00
|
|
|
if (this.state.register_is_url) {
|
|
|
|
return this.state.register_is_url;
|
|
|
|
} else if (MatrixClientPeg.get()) {
|
2016-03-06 19:33:36 +00:00
|
|
|
return MatrixClientPeg.get().getIdentityServerUrl();
|
2017-05-19 12:53:11 +00:00
|
|
|
} else {
|
2016-06-21 10:05:37 +00:00
|
|
|
return this.getDefaultIsUrl();
|
2016-03-06 19:33:36 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-06-21 10:05:37 +00:00
|
|
|
getDefaultIsUrl() {
|
2018-12-05 06:34:57 +00:00
|
|
|
return this.state.defaultIsUrl || "https://vector.im";
|
2016-06-21 10:05:37 +00:00
|
|
|
},
|
|
|
|
|
2015-12-21 12:55:13 +00:00
|
|
|
componentWillMount: function() {
|
2016-05-06 13:19:56 +00:00
|
|
|
SdkConfig.put(this.props.config);
|
2016-08-02 17:46:43 +00:00
|
|
|
|
2017-04-06 10:30:47 +00:00
|
|
|
// Used by _viewRoom before getting state from sync
|
|
|
|
this.firstSyncComplete = false;
|
2017-07-12 13:04:20 +00:00
|
|
|
this.firstSyncPromise = Promise.defer();
|
2017-04-06 10:30:47 +00:00
|
|
|
|
2016-08-03 08:53:02 +00:00
|
|
|
if (this.props.config.sync_timeline_limit) {
|
|
|
|
MatrixClientPeg.opts.initialSyncLimit = this.props.config.sync_timeline_limit;
|
|
|
|
}
|
2017-02-03 11:48:24 +00:00
|
|
|
|
2018-12-05 06:34:57 +00:00
|
|
|
// Set up the default URLs (async)
|
|
|
|
if (this.getDefaultServerName() && !this.getDefaultHsUrl(false)) {
|
2018-12-07 22:36:49 +00:00
|
|
|
this.setState({loadingDefaultHomeserver: true});
|
2018-12-05 06:34:57 +00:00
|
|
|
this._tryDiscoverDefaultHomeserver(this.getDefaultServerName());
|
2018-12-07 22:36:49 +00:00
|
|
|
} else if (this.getDefaultServerName() && this.getDefaultHsUrl(false)) {
|
|
|
|
// Ideally we would somehow only communicate this to the server admins, but
|
|
|
|
// given this is at login time we can't really do much besides hope that people
|
|
|
|
// will check their settings.
|
|
|
|
this.setState({
|
|
|
|
defaultServerName: null, // To un-hide any secrets people might be keeping
|
2019-01-11 01:18:21 +00:00
|
|
|
defaultServerDiscoveryError: _t(
|
|
|
|
"Invalid configuration: Cannot supply a default homeserver URL and " +
|
|
|
|
"a default server name",
|
|
|
|
),
|
2018-12-07 22:36:49 +00:00
|
|
|
});
|
2018-12-05 06:34:57 +00:00
|
|
|
}
|
|
|
|
|
2017-02-20 16:53:26 +00:00
|
|
|
// Set a default HS with query param `hs_url`
|
|
|
|
const paramHs = this.props.startingFragmentQueryParams.hs_url;
|
|
|
|
if (paramHs) {
|
|
|
|
console.log('Setting register_hs_url ', paramHs);
|
|
|
|
this.setState({
|
|
|
|
register_hs_url: paramHs,
|
|
|
|
});
|
|
|
|
}
|
2018-07-24 15:10:46 +00:00
|
|
|
// Set a default IS with query param `is_url`
|
|
|
|
const paramIs = this.props.startingFragmentQueryParams.is_url;
|
|
|
|
if (paramIs) {
|
|
|
|
console.log('Setting register_is_url ', paramIs);
|
|
|
|
this.setState({
|
|
|
|
register_is_url: paramIs,
|
|
|
|
});
|
|
|
|
}
|
2017-08-08 21:19:38 +00:00
|
|
|
|
|
|
|
// a thing to call showScreen with once login completes. this is kept
|
|
|
|
// outside this.state because updating it should never trigger a
|
|
|
|
// rerender.
|
|
|
|
this._screenAfterLogin = this.props.initialScreenAfterLogin;
|
|
|
|
|
|
|
|
this._windowWidth = 10000;
|
|
|
|
this.handleResize();
|
|
|
|
window.addEventListener('resize', this.handleResize);
|
2017-10-26 00:43:42 +00:00
|
|
|
|
2018-03-28 10:25:28 +00:00
|
|
|
this._pageChanging = false;
|
|
|
|
|
2017-11-14 15:28:34 +00:00
|
|
|
// check we have the right tint applied for this theme.
|
|
|
|
// N.B. we don't call the whole of setTheme() here as we may be
|
|
|
|
// racing with the theme CSS download finishing from index.js
|
2017-10-26 00:43:42 +00:00
|
|
|
Tinter.tint();
|
2015-12-21 12:55:13 +00:00
|
|
|
},
|
|
|
|
|
2015-06-12 13:59:33 +00:00
|
|
|
componentDidMount: function() {
|
2015-06-12 16:34:17 +00:00
|
|
|
this.dispatcherRef = dis.register(this.onAction);
|
2016-08-10 10:33:58 +00:00
|
|
|
|
2015-06-18 14:03:57 +00:00
|
|
|
this.focusComposer = false;
|
2015-12-04 11:34:50 +00:00
|
|
|
|
2015-10-27 09:58:55 +00:00
|
|
|
// this can technically be done anywhere but doing this here keeps all
|
|
|
|
// the routing url path logic together.
|
2016-08-28 01:05:23 +00:00
|
|
|
if (this.onAliasClick) {
|
|
|
|
linkifyMatrix.onAliasClick = this.onAliasClick;
|
|
|
|
}
|
|
|
|
if (this.onUserClick) {
|
|
|
|
linkifyMatrix.onUserClick = this.onUserClick;
|
|
|
|
}
|
2017-06-05 15:51:50 +00:00
|
|
|
if (this.onGroupClick) {
|
|
|
|
linkifyMatrix.onGroupClick = this.onGroupClick;
|
|
|
|
}
|
2015-11-30 18:11:04 +00:00
|
|
|
|
2017-06-16 13:33:14 +00:00
|
|
|
// the first thing to do is to try the token params in the query-string
|
|
|
|
Lifecycle.attemptTokenLogin(this.props.realQueryParams).then((loggedIn) => {
|
2017-11-16 13:19:36 +00:00
|
|
|
if (loggedIn) {
|
2017-06-16 13:33:14 +00:00
|
|
|
this.props.onTokenLoginCompleted();
|
2017-06-14 09:53:48 +00:00
|
|
|
|
2017-06-16 13:33:14 +00:00
|
|
|
// don't do anything else until the page reloads - just stay in
|
|
|
|
// the 'loading' state.
|
|
|
|
return;
|
|
|
|
}
|
2017-06-14 09:53:48 +00:00
|
|
|
|
2017-06-16 13:33:14 +00:00
|
|
|
// if the user has followed a login or register link, don't reanimate
|
|
|
|
// the old creds, but rather go straight to the relevant page
|
2017-08-08 21:19:38 +00:00
|
|
|
const firstScreen = this._screenAfterLogin ?
|
|
|
|
this._screenAfterLogin.screen : null;
|
2017-06-14 09:53:48 +00:00
|
|
|
|
2017-06-16 13:33:14 +00:00
|
|
|
if (firstScreen === 'login' ||
|
|
|
|
firstScreen === 'register' ||
|
|
|
|
firstScreen === 'forgot_password') {
|
|
|
|
this._showScreenAfterLogin();
|
|
|
|
return;
|
|
|
|
}
|
2017-02-03 14:34:24 +00:00
|
|
|
|
2017-07-12 13:02:00 +00:00
|
|
|
// the extra Promise.resolve() ensures that synchronous exceptions hit the same codepath as
|
2017-06-16 13:33:14 +00:00
|
|
|
// asynchronous ones.
|
2017-07-12 13:02:00 +00:00
|
|
|
return Promise.resolve().then(() => {
|
2017-06-16 13:33:14 +00:00
|
|
|
return Lifecycle.loadSession({
|
|
|
|
fragmentQueryParams: this.props.startingFragmentQueryParams,
|
|
|
|
enableGuest: this.props.enableGuest,
|
|
|
|
guestHsUrl: this.getCurrentHsUrl(),
|
|
|
|
guestIsUrl: this.getCurrentIsUrl(),
|
|
|
|
defaultDeviceDisplayName: this.props.defaultDeviceDisplayName,
|
|
|
|
});
|
2017-06-16 11:20:52 +00:00
|
|
|
}).then((loadedSession) => {
|
|
|
|
if (!loadedSession) {
|
2019-02-08 12:12:43 +00:00
|
|
|
// fall back to showing the welcome screen
|
|
|
|
dis.dispatch({action: "view_welcome_page"});
|
2017-06-16 11:20:52 +00:00
|
|
|
}
|
2016-09-01 10:08:40 +00:00
|
|
|
});
|
2018-04-27 10:25:13 +00:00
|
|
|
// Note we don't catch errors from this: we catch everything within
|
|
|
|
// loadSession as there's logic there to ask the user if they want
|
|
|
|
// to try logging out.
|
2018-04-27 16:52:25 +00:00
|
|
|
});
|
2018-05-15 12:15:40 +00:00
|
|
|
|
|
|
|
if (SettingsStore.getValue("showCookieBar")) {
|
|
|
|
this.setState({
|
|
|
|
showCookieBar: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SettingsStore.getValue("analyticsOptIn")) {
|
|
|
|
Analytics.enable();
|
|
|
|
}
|
2015-06-12 13:59:33 +00:00
|
|
|
},
|
|
|
|
|
2015-06-12 16:34:17 +00:00
|
|
|
componentWillUnmount: function() {
|
2016-08-11 12:50:38 +00:00
|
|
|
Lifecycle.stopMatrixClient();
|
2015-06-12 16:34:17 +00:00
|
|
|
dis.unregister(this.dispatcherRef);
|
2015-09-18 17:39:16 +00:00
|
|
|
window.removeEventListener("focus", this.onFocus);
|
2015-11-30 18:11:04 +00:00
|
|
|
window.removeEventListener('resize', this.handleResize);
|
2015-06-12 16:34:17 +00:00
|
|
|
},
|
|
|
|
|
2018-03-27 10:17:49 +00:00
|
|
|
componentWillUpdate: function(props, state) {
|
|
|
|
if (this.shouldTrackPageChange(this.state, state)) {
|
2018-03-28 09:25:28 +00:00
|
|
|
this.startPageChangeTimer();
|
2018-03-27 10:17:49 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
componentDidUpdate: function(prevProps, prevState) {
|
|
|
|
if (this.shouldTrackPageChange(prevState, this.state)) {
|
2018-03-28 09:25:28 +00:00
|
|
|
const durationMs = this.stopPageChangeTimer();
|
|
|
|
Analytics.trackPageChange(durationMs);
|
2018-03-27 10:17:49 +00:00
|
|
|
}
|
2015-06-18 14:03:57 +00:00
|
|
|
if (this.focusComposer) {
|
|
|
|
dis.dispatch({action: 'focus_composer'});
|
|
|
|
this.focusComposer = false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-03-28 09:25:28 +00:00
|
|
|
startPageChangeTimer() {
|
2018-06-04 08:38:21 +00:00
|
|
|
// Tor doesn't support performance
|
|
|
|
if (!performance || !performance.mark) return null;
|
|
|
|
|
2018-03-28 09:25:28 +00:00
|
|
|
// This shouldn't happen because componentWillUpdate and componentDidUpdate
|
|
|
|
// are used.
|
|
|
|
if (this._pageChanging) {
|
|
|
|
console.warn('MatrixChat.startPageChangeTimer: timer already started');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this._pageChanging = true;
|
|
|
|
performance.mark('riot_MatrixChat_page_change_start');
|
|
|
|
},
|
|
|
|
|
|
|
|
stopPageChangeTimer() {
|
2018-06-04 08:38:21 +00:00
|
|
|
// Tor doesn't support performance
|
|
|
|
if (!performance || !performance.mark) return null;
|
|
|
|
|
2018-03-28 09:25:28 +00:00
|
|
|
if (!this._pageChanging) {
|
|
|
|
console.warn('MatrixChat.stopPageChangeTimer: timer not started');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this._pageChanging = false;
|
|
|
|
performance.mark('riot_MatrixChat_page_change_stop');
|
|
|
|
performance.measure(
|
|
|
|
'riot_MatrixChat_page_change_delta',
|
|
|
|
'riot_MatrixChat_page_change_start',
|
|
|
|
'riot_MatrixChat_page_change_stop',
|
|
|
|
);
|
|
|
|
performance.clearMarks('riot_MatrixChat_page_change_start');
|
|
|
|
performance.clearMarks('riot_MatrixChat_page_change_stop');
|
|
|
|
const measurement = performance.getEntriesByName('riot_MatrixChat_page_change_delta').pop();
|
2018-05-03 13:08:10 +00:00
|
|
|
|
|
|
|
// In practice, sometimes the entries list is empty, so we get no measurement
|
|
|
|
if (!measurement) return null;
|
|
|
|
|
2018-03-28 09:25:28 +00:00
|
|
|
return measurement.duration;
|
|
|
|
},
|
|
|
|
|
2018-03-27 10:17:49 +00:00
|
|
|
shouldTrackPageChange(prevState, state) {
|
|
|
|
return prevState.currentRoomId !== state.currentRoomId ||
|
|
|
|
prevState.view !== state.view ||
|
|
|
|
prevState.page_type !== state.page_type;
|
|
|
|
},
|
|
|
|
|
2017-06-09 16:18:45 +00:00
|
|
|
setStateForNewView: function(state) {
|
2017-06-14 19:04:55 +00:00
|
|
|
if (state.view === undefined) {
|
|
|
|
throw new Error("setStateForNewView with no view!");
|
|
|
|
}
|
2016-09-30 10:56:32 +00:00
|
|
|
const newState = {
|
|
|
|
viewUserId: null,
|
2017-08-08 21:19:38 +00:00
|
|
|
};
|
|
|
|
Object.assign(newState, state);
|
|
|
|
this.setState(newState);
|
2016-09-30 10:56:32 +00:00
|
|
|
},
|
|
|
|
|
2015-06-12 16:34:17 +00:00
|
|
|
onAction: function(payload) {
|
2017-06-14 19:04:55 +00:00
|
|
|
// console.log(`MatrixClientPeg.onAction: ${payload.action}`);
|
2017-03-09 17:03:57 +00:00
|
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
|
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
2015-06-25 16:41:55 +00:00
|
|
|
|
2017-11-10 10:51:28 +00:00
|
|
|
// Start the onboarding process for certain actions
|
2017-11-10 11:13:52 +00:00
|
|
|
if (MatrixClientPeg.get() && MatrixClientPeg.get().isGuest() &&
|
2017-11-10 10:51:28 +00:00
|
|
|
ONBOARDING_FLOW_STARTERS.includes(payload.action)
|
|
|
|
) {
|
|
|
|
// This will cause `payload` to be dispatched later, once a
|
|
|
|
// sync has reached the "prepared" state. Setting a matrix ID
|
|
|
|
// will cause a full login and sync and finally the deferred
|
|
|
|
// action will be dispatched.
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'do_after_sync_prepared',
|
|
|
|
deferred_action: payload,
|
|
|
|
});
|
2018-09-05 16:07:39 +00:00
|
|
|
dis.dispatch({action: 'require_registration'});
|
2017-11-10 10:51:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:34:17 +00:00
|
|
|
switch (payload.action) {
|
|
|
|
case 'logout':
|
2016-08-02 13:04:20 +00:00
|
|
|
Lifecycle.logout();
|
2015-06-12 16:34:17 +00:00
|
|
|
break;
|
2018-09-05 16:07:39 +00:00
|
|
|
case 'require_registration':
|
|
|
|
startAnyRegistrationFlow(payload);
|
|
|
|
break;
|
2015-07-13 18:14:02 +00:00
|
|
|
case 'start_registration':
|
2018-09-05 16:07:39 +00:00
|
|
|
// This starts the full registration flow
|
2017-05-19 12:53:11 +00:00
|
|
|
this._startRegistration(payload.params || {});
|
2015-07-13 18:14:02 +00:00
|
|
|
break;
|
|
|
|
case 'start_login':
|
2017-06-09 16:18:45 +00:00
|
|
|
this.setStateForNewView({
|
|
|
|
view: VIEWS.LOGIN,
|
2015-07-13 18:14:02 +00:00
|
|
|
});
|
2015-07-15 18:25:36 +00:00
|
|
|
this.notifyNewScreen('login');
|
2015-10-08 21:25:33 +00:00
|
|
|
break;
|
2015-11-20 11:57:04 +00:00
|
|
|
case 'start_post_registration':
|
2017-06-14 19:04:55 +00:00
|
|
|
this.setState({
|
2017-06-09 16:18:45 +00:00
|
|
|
view: VIEWS.POST_REGISTRATION,
|
2015-11-20 11:57:04 +00:00
|
|
|
});
|
|
|
|
break;
|
2016-01-12 17:20:16 +00:00
|
|
|
case 'start_password_recovery':
|
2017-06-09 16:18:45 +00:00
|
|
|
this.setStateForNewView({
|
|
|
|
view: VIEWS.FORGOT_PASSWORD,
|
2016-01-12 17:20:16 +00:00
|
|
|
});
|
|
|
|
this.notifyNewScreen('forgot_password');
|
2015-12-13 13:49:28 +00:00
|
|
|
break;
|
2017-06-01 13:16:25 +00:00
|
|
|
case 'start_chat':
|
|
|
|
createRoom({
|
|
|
|
dmUserId: payload.user_id,
|
2015-12-13 13:49:28 +00:00
|
|
|
});
|
2015-07-13 18:14:02 +00:00
|
|
|
break;
|
2015-12-13 13:49:28 +00:00
|
|
|
case 'leave_room':
|
2017-05-19 12:53:11 +00:00
|
|
|
this._leaveRoom(payload.room_id);
|
2015-07-13 18:14:02 +00:00
|
|
|
break;
|
2017-03-09 17:03:57 +00:00
|
|
|
case 'reject_invite':
|
2017-07-27 16:19:18 +00:00
|
|
|
Modal.createTrackedDialog('Reject invitation', '', QuestionDialog, {
|
2017-05-23 14:16:31 +00:00
|
|
|
title: _t('Reject invitation'),
|
|
|
|
description: _t('Are you sure you want to reject the invitation?'),
|
2017-03-09 17:03:57 +00:00
|
|
|
onFinished: (confirm) => {
|
|
|
|
if (confirm) {
|
|
|
|
// FIXME: controller shouldn't be loading a view :(
|
|
|
|
const Loader = sdk.getComponent("elements.Spinner");
|
|
|
|
const modal = Modal.createDialog(Loader, null, 'mx_Dialog_spinner');
|
|
|
|
|
|
|
|
MatrixClientPeg.get().leave(payload.room_id).done(() => {
|
|
|
|
modal.close();
|
2017-06-16 10:27:47 +00:00
|
|
|
if (this.state.currentRoomId === payload.room_id) {
|
2017-03-09 17:03:57 +00:00
|
|
|
dis.dispatch({action: 'view_next_room'});
|
|
|
|
}
|
|
|
|
}, (err) => {
|
|
|
|
modal.close();
|
2017-08-10 12:49:11 +00:00
|
|
|
Modal.createTrackedDialog('Failed to reject invitation', '', ErrorDialog, {
|
2017-05-31 14:09:09 +00:00
|
|
|
title: _t('Failed to reject invitation'),
|
2017-05-19 12:53:11 +00:00
|
|
|
description: err.toString(),
|
2017-03-09 17:03:57 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2017-05-19 12:53:11 +00:00
|
|
|
},
|
2017-03-09 17:03:57 +00:00
|
|
|
});
|
|
|
|
break;
|
2016-09-16 01:37:06 +00:00
|
|
|
case 'view_user':
|
|
|
|
// FIXME: ugly hack to expand the RightPanel and then re-dispatch.
|
2018-12-17 14:30:39 +00:00
|
|
|
if (this.state.collapsedRhs) {
|
2016-09-16 01:37:06 +00:00
|
|
|
setTimeout(()=>{
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'show_right_panel',
|
|
|
|
});
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_user',
|
|
|
|
member: payload.member,
|
|
|
|
});
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
break;
|
2015-06-12 17:01:38 +00:00
|
|
|
case 'view_room':
|
2016-06-14 11:56:37 +00:00
|
|
|
// Takes either a room ID or room alias: if switching to a room the client is already
|
|
|
|
// known to be in (eg. user clicks on a room in the recents panel), supply the ID
|
|
|
|
// If the user is clicking on a room in the context of the alias being presented
|
|
|
|
// to them, supply the room alias. If both are supplied, the room ID will be ignored.
|
2016-06-20 15:30:51 +00:00
|
|
|
this._viewRoom(payload);
|
2015-06-12 17:01:38 +00:00
|
|
|
break;
|
2015-06-25 16:41:55 +00:00
|
|
|
case 'view_prev_room':
|
2017-05-19 12:53:11 +00:00
|
|
|
this._viewNextRoom(-1);
|
|
|
|
break;
|
2015-06-25 16:41:55 +00:00
|
|
|
case 'view_next_room':
|
2017-05-19 12:53:11 +00:00
|
|
|
this._viewNextRoom(1);
|
2015-09-18 17:39:16 +00:00
|
|
|
break;
|
|
|
|
case 'view_indexed_room':
|
2017-05-19 12:53:11 +00:00
|
|
|
this._viewIndexedRoom(payload.roomIndex);
|
2015-09-18 17:39:16 +00:00
|
|
|
break;
|
2019-01-22 00:49:48 +00:00
|
|
|
case 'view_user_settings': {
|
2019-02-04 20:25:26 +00:00
|
|
|
const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog");
|
|
|
|
Modal.createTrackedDialog('User settings', '', UserSettingsDialog, {}, 'mx_SettingsDialog');
|
|
|
|
|
2019-02-11 13:31:27 +00:00
|
|
|
// View the welcome or home page if we need something to look at
|
|
|
|
this._viewSomethingBehindModal();
|
2015-09-18 17:39:16 +00:00
|
|
|
break;
|
2019-01-22 00:49:48 +00:00
|
|
|
}
|
2015-09-18 17:39:16 +00:00
|
|
|
case 'view_create_room':
|
2017-06-05 16:45:01 +00:00
|
|
|
this._createRoom();
|
2015-09-18 17:39:16 +00:00
|
|
|
break;
|
2017-11-28 12:08:53 +00:00
|
|
|
case 'view_create_group': {
|
|
|
|
const CreateGroupDialog = sdk.getComponent("dialogs.CreateGroupDialog");
|
|
|
|
Modal.createTrackedDialog('Create Community', '', CreateGroupDialog);
|
|
|
|
}
|
|
|
|
break;
|
2019-01-29 14:40:19 +00:00
|
|
|
case 'view_room_directory': {
|
2019-01-29 14:34:58 +00:00
|
|
|
const RoomDirectory = sdk.getComponent("structures.RoomDirectory");
|
|
|
|
Modal.createTrackedDialog('Room directory', '', RoomDirectory, {
|
|
|
|
config: this.props.config,
|
|
|
|
}, 'mx_RoomDirectory_dialogWrapper');
|
2019-01-30 06:25:07 +00:00
|
|
|
|
2019-02-11 13:31:27 +00:00
|
|
|
// View the welcome or home page if we need something to look at
|
|
|
|
this._viewSomethingBehindModal();
|
2019-01-29 14:40:19 +00:00
|
|
|
}
|
|
|
|
break;
|
2017-06-28 12:56:18 +00:00
|
|
|
case 'view_my_groups':
|
|
|
|
this._setPage(PageTypes.MyGroups);
|
|
|
|
this.notifyNewScreen('groups');
|
|
|
|
break;
|
2017-06-05 15:51:50 +00:00
|
|
|
case 'view_group':
|
2018-05-29 12:16:39 +00:00
|
|
|
this._viewGroup(payload);
|
2017-06-05 15:51:50 +00:00
|
|
|
break;
|
2019-02-07 16:25:09 +00:00
|
|
|
case 'view_welcome_page':
|
|
|
|
this._viewWelcome();
|
|
|
|
break;
|
2016-11-13 14:10:46 +00:00
|
|
|
case 'view_home_page':
|
2018-05-29 12:16:39 +00:00
|
|
|
this._viewHome();
|
2016-11-13 14:10:46 +00:00
|
|
|
break;
|
2017-05-11 16:04:11 +00:00
|
|
|
case 'view_set_mxid':
|
2017-06-09 12:46:45 +00:00
|
|
|
this._setMxId(payload);
|
2017-05-11 16:04:11 +00:00
|
|
|
break;
|
2017-06-01 13:16:25 +00:00
|
|
|
case 'view_start_chat_or_reuse':
|
2017-07-10 18:32:02 +00:00
|
|
|
this._chatCreateOrReuse(payload.user_id, payload.go_home_on_cancel);
|
2017-06-01 13:16:25 +00:00
|
|
|
break;
|
2016-09-05 09:29:03 +00:00
|
|
|
case 'view_create_chat':
|
2017-11-10 10:51:28 +00:00
|
|
|
showStartChatInviteDialog();
|
2016-09-01 15:45:24 +00:00
|
|
|
break;
|
2016-09-13 13:28:03 +00:00
|
|
|
case 'view_invite':
|
2017-08-14 16:43:00 +00:00
|
|
|
showRoomInviteDialog(payload.roomId);
|
2016-09-13 13:28:03 +00:00
|
|
|
break;
|
2015-09-18 17:39:16 +00:00
|
|
|
case 'notifier_enabled':
|
|
|
|
this.forceUpdate();
|
2015-06-25 16:41:55 +00:00
|
|
|
break;
|
2015-10-11 12:49:44 +00:00
|
|
|
case 'hide_left_panel':
|
|
|
|
this.setState({
|
2017-08-25 11:10:13 +00:00
|
|
|
collapseLhs: true,
|
2015-10-11 12:49:44 +00:00
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'show_left_panel':
|
|
|
|
this.setState({
|
2017-08-25 11:10:13 +00:00
|
|
|
collapseLhs: false,
|
2015-10-11 12:49:44 +00:00
|
|
|
});
|
|
|
|
break;
|
2015-10-11 15:07:01 +00:00
|
|
|
case 'hide_right_panel':
|
2018-12-17 14:56:35 +00:00
|
|
|
window.localStorage.setItem("mx_rhs_collapsed", true);
|
2015-10-11 15:07:01 +00:00
|
|
|
this.setState({
|
2018-12-17 14:30:39 +00:00
|
|
|
collapsedRhs: true,
|
2015-10-11 15:07:01 +00:00
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'show_right_panel':
|
2018-12-17 14:56:35 +00:00
|
|
|
window.localStorage.setItem("mx_rhs_collapsed", false);
|
2015-10-11 15:07:01 +00:00
|
|
|
this.setState({
|
2018-12-17 14:30:39 +00:00
|
|
|
collapsedRhs: false,
|
2015-10-11 15:07:01 +00:00
|
|
|
});
|
|
|
|
break;
|
2017-10-25 10:09:48 +00:00
|
|
|
case 'panel_disable': {
|
2016-04-12 16:18:32 +00:00
|
|
|
this.setState({
|
2017-10-25 10:09:48 +00:00
|
|
|
leftDisabled: payload.leftDisabled || payload.sideDisabled || false,
|
|
|
|
middleDisabled: payload.middleDisabled || false,
|
|
|
|
rightDisabled: payload.rightDisabled || payload.sideDisabled || false,
|
2016-04-12 16:18:32 +00:00
|
|
|
});
|
2018-05-29 12:16:39 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-02-11 18:15:57 +00:00
|
|
|
case 'set_theme':
|
|
|
|
this._onSetTheme(payload.value);
|
|
|
|
break;
|
2017-03-27 15:39:04 +00:00
|
|
|
case 'on_logging_in':
|
2017-06-05 15:50:00 +00:00
|
|
|
// We are now logging in, so set the state to reflect that
|
2017-06-20 11:03:37 +00:00
|
|
|
// NB. This does not touch 'ready' since if our dispatches
|
|
|
|
// are delayed, the sync could already have completed
|
2017-06-14 19:04:55 +00:00
|
|
|
this.setStateForNewView({
|
|
|
|
view: VIEWS.LOGGING_IN,
|
|
|
|
});
|
2017-03-27 15:39:04 +00:00
|
|
|
break;
|
2016-08-02 13:04:20 +00:00
|
|
|
case 'on_logged_in':
|
2019-01-25 22:10:54 +00:00
|
|
|
this._onLoggedIn();
|
2016-08-02 13:04:20 +00:00
|
|
|
break;
|
|
|
|
case 'on_logged_out':
|
|
|
|
this._onLoggedOut();
|
|
|
|
break;
|
|
|
|
case 'will_start_client':
|
2017-06-23 09:48:21 +00:00
|
|
|
this.setState({ready: false}, () => {
|
|
|
|
// if the client is about to start, we are, by definition, not ready.
|
|
|
|
// Set ready to false now, then it'll be set to true when the sync
|
|
|
|
// listener we set below fires.
|
|
|
|
this._onWillStartClient();
|
|
|
|
});
|
2016-08-09 23:03:29 +00:00
|
|
|
break;
|
2017-11-05 03:13:23 +00:00
|
|
|
case 'client_started':
|
|
|
|
this._onClientStarted();
|
|
|
|
break;
|
2016-11-02 15:58:17 +00:00
|
|
|
case 'new_version':
|
|
|
|
this.onVersion(
|
|
|
|
payload.currentVersion, payload.newVersion,
|
2017-05-19 12:53:11 +00:00
|
|
|
payload.releaseNotes,
|
2016-11-02 15:58:17 +00:00
|
|
|
);
|
|
|
|
break;
|
2017-06-03 14:10:05 +00:00
|
|
|
case 'check_updates':
|
|
|
|
this.setState({ checkingForUpdate: payload.value });
|
|
|
|
break;
|
2017-06-16 15:12:52 +00:00
|
|
|
case 'send_event':
|
|
|
|
this.onSendEvent(payload.room_id, payload.event);
|
|
|
|
break;
|
2018-02-08 21:51:07 +00:00
|
|
|
case 'aria_hide_main_app':
|
|
|
|
this.setState({
|
|
|
|
hideToSRUsers: true,
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'aria_unhide_main_app':
|
|
|
|
this.setState({
|
|
|
|
hideToSRUsers: false,
|
|
|
|
});
|
|
|
|
break;
|
2018-05-15 12:15:40 +00:00
|
|
|
case 'accept_cookies':
|
|
|
|
SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, true);
|
|
|
|
SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false);
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
showCookieBar: false,
|
|
|
|
});
|
|
|
|
Analytics.enable();
|
|
|
|
break;
|
|
|
|
case 'reject_cookies':
|
|
|
|
SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, false);
|
|
|
|
SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false);
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
showCookieBar: false,
|
|
|
|
});
|
|
|
|
break;
|
2015-06-12 16:34:17 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-12-10 21:53:14 +00:00
|
|
|
_setPage: function(pageType) {
|
|
|
|
this.setState({
|
2015-12-14 11:07:59 +00:00
|
|
|
page_type: pageType,
|
2015-12-10 21:53:14 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
_startRegistration: function(params) {
|
2018-02-07 15:51:03 +00:00
|
|
|
const newState = {
|
2017-06-09 16:18:45 +00:00
|
|
|
view: VIEWS.REGISTER,
|
2018-02-07 15:51:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Only honour params if they are all present, otherwise we reset
|
|
|
|
// HS and IS URLs when switching to registration.
|
|
|
|
if (params.client_secret &&
|
|
|
|
params.session_id &&
|
|
|
|
params.hs_url &&
|
|
|
|
params.is_url &&
|
|
|
|
params.sid
|
|
|
|
) {
|
|
|
|
newState.register_client_secret = params.client_secret;
|
|
|
|
newState.register_session_id = params.session_id;
|
|
|
|
newState.register_hs_url = params.hs_url;
|
|
|
|
newState.register_is_url = params.is_url;
|
|
|
|
newState.register_id_sid = params.sid;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.setStateForNewView(newState);
|
2017-05-19 12:53:11 +00:00
|
|
|
this.notifyNewScreen('register');
|
|
|
|
},
|
|
|
|
|
2017-05-25 16:10:49 +00:00
|
|
|
// TODO: Move to RoomViewStore
|
2017-05-19 12:53:11 +00:00
|
|
|
_viewNextRoom: function(roomIndexDelta) {
|
|
|
|
const allRooms = RoomListSorter.mostRecentActivityFirst(
|
|
|
|
MatrixClientPeg.get().getRooms(),
|
|
|
|
);
|
2017-06-09 09:54:42 +00:00
|
|
|
// If there are 0 rooms or 1 room, view the home page because otherwise
|
|
|
|
// if there are 0, we end up trying to index into an empty array, and
|
|
|
|
// if there is 1, we end up viewing the same room.
|
|
|
|
if (allRooms.length < 2) {
|
2017-06-09 09:28:45 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_home_page',
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2017-05-19 12:53:11 +00:00
|
|
|
let roomIndex = -1;
|
|
|
|
for (let i = 0; i < allRooms.length; ++i) {
|
|
|
|
if (allRooms[i].roomId == this.state.currentRoomId) {
|
|
|
|
roomIndex = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
roomIndex = (roomIndex + roomIndexDelta) % allRooms.length;
|
|
|
|
if (roomIndex < 0) roomIndex = allRooms.length - 1;
|
2017-05-25 16:10:49 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_room',
|
|
|
|
room_id: allRooms[roomIndex].roomId,
|
|
|
|
});
|
2017-05-19 12:53:11 +00:00
|
|
|
},
|
|
|
|
|
2017-05-25 16:10:49 +00:00
|
|
|
// TODO: Move to RoomViewStore
|
2017-05-19 12:53:11 +00:00
|
|
|
_viewIndexedRoom: function(roomIndex) {
|
|
|
|
const allRooms = RoomListSorter.mostRecentActivityFirst(
|
|
|
|
MatrixClientPeg.get().getRooms(),
|
|
|
|
);
|
|
|
|
if (allRooms[roomIndex]) {
|
2017-05-25 16:10:49 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_room',
|
|
|
|
room_id: allRooms[roomIndex].roomId,
|
|
|
|
});
|
2017-05-19 12:53:11 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-02-01 16:31:12 +00:00
|
|
|
// switch view to the given room
|
|
|
|
//
|
2017-05-31 14:09:09 +00:00
|
|
|
// @param {Object} roomInfo Object containing data about the room to be joined
|
|
|
|
// @param {string=} roomInfo.room_id ID of the room to join. One of room_id or room_alias must be given.
|
|
|
|
// @param {string=} roomInfo.room_alias Alias of the room to join. One of room_id or room_alias must be given.
|
|
|
|
// @param {boolean=} roomInfo.auto_join If true, automatically attempt to join the room if not already a member.
|
|
|
|
// @param {string=} roomInfo.event_id ID of the event in this room to show: this will cause a switch to the
|
2016-06-20 17:05:58 +00:00
|
|
|
// context of that particular event.
|
2017-06-08 14:32:31 +00:00
|
|
|
// @param {boolean=} roomInfo.highlighted If true, add event_id to the hash of the URL
|
2017-06-08 16:54:41 +00:00
|
|
|
// and alter the EventTile to appear highlighted.
|
2017-05-31 14:09:09 +00:00
|
|
|
// @param {Object=} roomInfo.third_party_invite Object containing data about the third party
|
2016-03-17 18:38:25 +00:00
|
|
|
// we received to join the room, if any.
|
2017-05-31 14:09:09 +00:00
|
|
|
// @param {string=} roomInfo.third_party_invite.inviteSignUrl 3pid invite sign URL
|
|
|
|
// @param {string=} roomInfo.third_party_invite.invitedEmail The email address the invite was sent to
|
|
|
|
// @param {Object=} roomInfo.oob_data Object of additional data about the room
|
2016-03-01 18:23:57 +00:00
|
|
|
// that has been passed out-of-band (eg.
|
|
|
|
// room name and avatar from an invite email)
|
2017-05-31 14:09:09 +00:00
|
|
|
_viewRoom: function(roomInfo) {
|
2015-12-10 16:26:36 +00:00
|
|
|
this.focusComposer = true;
|
2016-02-01 16:31:12 +00:00
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
const newState = {
|
2019-02-11 13:49:18 +00:00
|
|
|
view: VIEWS.LOGGED_IN,
|
2017-09-08 17:56:57 +00:00
|
|
|
currentRoomId: roomInfo.room_id || null,
|
2016-11-03 18:42:26 +00:00
|
|
|
page_type: PageTypes.RoomView,
|
2017-05-31 14:09:09 +00:00
|
|
|
thirdPartyInvite: roomInfo.third_party_invite,
|
|
|
|
roomOobData: roomInfo.oob_data,
|
2018-10-19 19:30:38 +00:00
|
|
|
viaServers: roomInfo.via_servers,
|
2015-12-10 16:26:36 +00:00
|
|
|
};
|
2016-02-01 16:31:12 +00:00
|
|
|
|
2017-06-07 21:41:02 +00:00
|
|
|
if (roomInfo.room_alias) {
|
|
|
|
console.log(
|
|
|
|
`Switching to room alias ${roomInfo.room_alias} at event ` +
|
2017-06-08 13:33:58 +00:00
|
|
|
roomInfo.event_id,
|
2017-06-07 21:41:02 +00:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
console.log(`Switching to room id ${roomInfo.room_id} at event ` +
|
2017-06-08 13:33:58 +00:00
|
|
|
roomInfo.event_id,
|
2017-06-07 21:41:02 +00:00
|
|
|
);
|
2016-02-01 16:31:12 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 10:30:47 +00:00
|
|
|
// Wait for the first sync to complete so that if a room does have an alias,
|
|
|
|
// it would have been retrieved.
|
2017-07-12 13:02:00 +00:00
|
|
|
let waitFor = Promise.resolve(null);
|
2017-04-06 10:44:15 +00:00
|
|
|
if (!this.firstSyncComplete) {
|
2017-04-06 10:30:47 +00:00
|
|
|
if (!this.firstSyncPromise) {
|
2017-05-31 14:09:09 +00:00
|
|
|
console.warn('Cannot view a room before first sync. room_id:', roomInfo.room_id);
|
2017-04-06 10:30:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
waitFor = this.firstSyncPromise.promise;
|
|
|
|
}
|
|
|
|
|
|
|
|
waitFor.done(() => {
|
2017-05-31 14:09:09 +00:00
|
|
|
let presentedId = roomInfo.room_alias || roomInfo.room_id;
|
|
|
|
const room = MatrixClientPeg.get().getRoom(roomInfo.room_id);
|
2015-12-10 16:26:36 +00:00
|
|
|
if (room) {
|
2017-04-06 10:30:47 +00:00
|
|
|
const theAlias = Rooms.getDisplayAliasForRoom(room);
|
2015-12-10 16:26:36 +00:00
|
|
|
if (theAlias) presentedId = theAlias;
|
2017-04-06 10:30:47 +00:00
|
|
|
|
|
|
|
// Store this as the ID of the last room accessed. This is so that we can
|
|
|
|
// persist which room is being stored across refreshes and browser quits.
|
|
|
|
if (localStorage) {
|
|
|
|
localStorage.setItem('mx_last_room_id', room.roomId);
|
|
|
|
}
|
2015-12-10 16:26:36 +00:00
|
|
|
}
|
2016-01-08 03:22:38 +00:00
|
|
|
|
2017-06-08 13:17:49 +00:00
|
|
|
if (roomInfo.event_id && roomInfo.highlighted) {
|
2017-05-31 14:09:09 +00:00
|
|
|
presentedId += "/" + roomInfo.event_id;
|
2016-02-01 16:31:12 +00:00
|
|
|
}
|
2017-04-06 10:30:47 +00:00
|
|
|
this.notifyNewScreen('room/' + presentedId);
|
2015-12-10 16:26:36 +00:00
|
|
|
newState.ready = true;
|
2017-04-06 10:30:47 +00:00
|
|
|
this.setState(newState);
|
|
|
|
});
|
2015-12-10 16:26:36 +00:00
|
|
|
},
|
|
|
|
|
2018-05-29 12:16:39 +00:00
|
|
|
_viewGroup: function(payload) {
|
|
|
|
const groupId = payload.group_id;
|
|
|
|
this.setState({
|
|
|
|
currentGroupId: groupId,
|
|
|
|
currentGroupIsNew: payload.group_is_new,
|
|
|
|
});
|
|
|
|
this._setPage(PageTypes.GroupView);
|
|
|
|
this.notifyNewScreen('group/' + groupId);
|
|
|
|
},
|
|
|
|
|
2019-02-11 13:31:27 +00:00
|
|
|
_viewSomethingBehindModal() {
|
|
|
|
if (this.state.view !== VIEWS.LOGGED_IN) {
|
|
|
|
this._viewWelcome();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!this.state.currentGroupId && !this.state.currentRoomId) {
|
|
|
|
this._viewHome();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-02-07 16:25:09 +00:00
|
|
|
_viewWelcome() {
|
|
|
|
this.setStateForNewView({
|
|
|
|
view: VIEWS.WELCOME,
|
|
|
|
});
|
|
|
|
this.notifyNewScreen('welcome');
|
|
|
|
},
|
|
|
|
|
2018-05-29 12:16:39 +00:00
|
|
|
_viewHome: function() {
|
2019-01-03 21:22:16 +00:00
|
|
|
// The home page requires the "logged in" view, so we'll set that.
|
Fix browser navigation not working between /home, /login, /register, etc
All of the anchors were pointed at `#` which, when clicked, would trigger a hash change in the browser. This change races the change made by the screen handling where the screen handling ends up losing. Because the hash is then tracked as empty rather than `#/login` (for example), the state machine considers future changes as no-ops and doesn't do anything with them.
By using `preventDefault` and `stopPropagation` on the anchor click events, we prevent the browser from automatically going to an empty hash, which then means the screen handling isn't racing the browser, and the hash change state machine doesn't no-op.
After applying that fix, going between pages worked great unless you were going from /login to /home. This is because the MatrixChat state machine was now out of sync (a `view` of `LOGIN` but a `page` of `HomePage` - an invalid state). All we have to do here is ensure the right view is used when navigating to the homepage.
Fixes https://github.com/vector-im/riot-web/issues/4061
Note: the concerns in 4061 about logging out upon entering the view appear to have been solved. Navigating to the login page doesn't obliterate your session, at least in my testing.
2018-12-21 00:26:13 +00:00
|
|
|
this.setStateForNewView({
|
|
|
|
view: VIEWS.LOGGED_IN,
|
|
|
|
});
|
2018-05-29 12:16:39 +00:00
|
|
|
this._setPage(PageTypes.HomePage);
|
|
|
|
this.notifyNewScreen('home');
|
|
|
|
},
|
|
|
|
|
2017-06-09 12:46:45 +00:00
|
|
|
_setMxId: function(payload) {
|
2017-05-11 16:04:11 +00:00
|
|
|
const SetMxIdDialog = sdk.getComponent('views.dialogs.SetMxIdDialog');
|
2017-07-27 16:19:18 +00:00
|
|
|
const close = Modal.createTrackedDialog('Set MXID', '', SetMxIdDialog, {
|
2017-05-11 16:04:11 +00:00
|
|
|
homeserverUrl: MatrixClientPeg.get().getHomeserverUrl(),
|
|
|
|
onFinished: (submitted, credentials) => {
|
|
|
|
if (!submitted) {
|
2017-06-05 17:37:38 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'cancel_after_sync_prepared',
|
|
|
|
});
|
2017-06-09 12:46:45 +00:00
|
|
|
if (payload.go_home_on_cancel) {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_home_page',
|
|
|
|
});
|
|
|
|
}
|
2017-05-11 16:04:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.onRegistered(credentials);
|
|
|
|
},
|
|
|
|
onDifferentServerClicked: (ev) => {
|
|
|
|
dis.dispatch({action: 'start_registration'});
|
|
|
|
close();
|
|
|
|
},
|
2017-05-29 00:32:31 +00:00
|
|
|
onLoginClick: (ev) => {
|
|
|
|
dis.dispatch({action: 'start_login'});
|
|
|
|
close();
|
2017-05-30 13:27:02 +00:00
|
|
|
},
|
2017-05-11 16:04:11 +00:00
|
|
|
}).close;
|
|
|
|
},
|
|
|
|
|
2017-06-05 16:45:01 +00:00
|
|
|
_createRoom: function() {
|
2017-08-17 12:33:07 +00:00
|
|
|
const CreateRoomDialog = sdk.getComponent('dialogs.CreateRoomDialog');
|
2017-08-17 12:39:19 +00:00
|
|
|
Modal.createTrackedDialog('Create Room', '', CreateRoomDialog, {
|
2017-08-02 12:41:26 +00:00
|
|
|
onFinished: (shouldCreate, name, noFederate) => {
|
2017-06-08 19:56:13 +00:00
|
|
|
if (shouldCreate) {
|
2017-08-02 13:00:24 +00:00
|
|
|
const createOpts = {};
|
2017-06-05 16:45:01 +00:00
|
|
|
if (name) createOpts.name = name;
|
2017-08-02 13:00:24 +00:00
|
|
|
if (noFederate) createOpts.creation_content = {'m.federate': false};
|
2017-06-05 16:45:01 +00:00
|
|
|
createRoom({createOpts}).done();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-07-11 10:02:23 +00:00
|
|
|
_chatCreateOrReuse: function(userId, goHomeOnCancel) {
|
|
|
|
if (goHomeOnCancel === undefined) goHomeOnCancel = true;
|
2017-07-10 18:32:02 +00:00
|
|
|
|
2017-06-01 13:16:25 +00:00
|
|
|
const ChatCreateOrReuseDialog = sdk.getComponent(
|
|
|
|
'views.dialogs.ChatCreateOrReuseDialog',
|
|
|
|
);
|
2017-06-02 10:42:47 +00:00
|
|
|
// Use a deferred action to reshow the dialog once the user has registered
|
2017-06-01 13:16:25 +00:00
|
|
|
if (MatrixClientPeg.get().isGuest()) {
|
2017-06-05 12:14:55 +00:00
|
|
|
// No point in making 2 DMs with welcome bot. This assumes view_set_mxid will
|
|
|
|
// result in a new DM with the welcome user.
|
|
|
|
if (userId !== this.props.config.welcomeUserId) {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'do_after_sync_prepared',
|
|
|
|
deferred_action: {
|
|
|
|
action: 'view_start_chat_or_reuse',
|
|
|
|
user_id: userId,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2017-06-01 13:16:25 +00:00
|
|
|
dis.dispatch({
|
2018-09-05 16:07:39 +00:00
|
|
|
action: 'require_registration',
|
2019-02-08 12:12:43 +00:00
|
|
|
// If the set_mxid dialog is cancelled, view /welcome because if the
|
|
|
|
// browser was pointing at /user/@someone:domain?action=chat, the URL
|
|
|
|
// needs to be reset so that they can revisit /user/.. // (and trigger
|
2017-06-09 12:46:45 +00:00
|
|
|
// `_chatCreateOrReuse` again)
|
2019-02-08 12:12:43 +00:00
|
|
|
go_welcome_on_cancel: true,
|
2017-06-01 13:16:25 +00:00
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-27 16:19:18 +00:00
|
|
|
const close = Modal.createTrackedDialog('Chat create or reuse', '', ChatCreateOrReuseDialog, {
|
2017-06-01 13:16:25 +00:00
|
|
|
userId: userId,
|
|
|
|
onFinished: (success) => {
|
2017-07-11 10:02:23 +00:00
|
|
|
if (!success && goHomeOnCancel) {
|
2017-06-01 13:16:25 +00:00
|
|
|
// Dialog cancelled, default to home
|
|
|
|
dis.dispatch({ action: 'view_home_page' });
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onNewDMClick: () => {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'start_chat',
|
|
|
|
user_id: userId,
|
|
|
|
});
|
|
|
|
// Close the dialog, indicate success (calls onFinished(true))
|
|
|
|
close(true);
|
|
|
|
},
|
|
|
|
onExistingRoomSelected: (roomId) => {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_room',
|
|
|
|
room_id: roomId,
|
|
|
|
});
|
|
|
|
close(true);
|
|
|
|
},
|
|
|
|
}).close;
|
|
|
|
},
|
|
|
|
|
2018-01-19 22:27:48 +00:00
|
|
|
_leaveRoomWarnings: function(roomId) {
|
|
|
|
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
|
|
|
|
// Show a warning if there are additional complications.
|
|
|
|
const joinRules = roomToLeave.currentState.getStateEvents('m.room.join_rules', '');
|
|
|
|
const warnings = [];
|
|
|
|
if (joinRules) {
|
|
|
|
const rule = joinRules.getContent().join_rule;
|
|
|
|
if (rule !== "public") {
|
|
|
|
warnings.push((
|
|
|
|
<span className="warning" key="non_public_warning">
|
2018-05-22 08:28:41 +00:00
|
|
|
{' '/* Whitespace, otherwise the sentences get smashed together */ }
|
2018-01-19 22:27:48 +00:00
|
|
|
{ _t("This room is not public. You will not be able to rejoin without an invite.") }
|
|
|
|
</span>
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return warnings;
|
|
|
|
},
|
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
_leaveRoom: function(roomId) {
|
|
|
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
|
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
|
|
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
|
2018-01-19 22:27:48 +00:00
|
|
|
const warnings = this._leaveRoomWarnings(roomId);
|
|
|
|
|
2017-07-27 16:19:18 +00:00
|
|
|
Modal.createTrackedDialog('Leave room', '', QuestionDialog, {
|
2017-06-02 09:47:08 +00:00
|
|
|
title: _t("Leave room"),
|
|
|
|
description: (
|
|
|
|
<span>
|
2017-09-28 10:21:06 +00:00
|
|
|
{ _t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name}) }
|
2018-01-19 22:27:48 +00:00
|
|
|
{ warnings }
|
2017-06-02 09:47:08 +00:00
|
|
|
</span>
|
|
|
|
),
|
2018-10-23 01:55:21 +00:00
|
|
|
button: _t("Leave"),
|
2017-05-19 12:53:11 +00:00
|
|
|
onFinished: (shouldLeave) => {
|
|
|
|
if (shouldLeave) {
|
|
|
|
const d = MatrixClientPeg.get().leave(roomId);
|
|
|
|
|
|
|
|
// FIXME: controller shouldn't be loading a view :(
|
|
|
|
const Loader = sdk.getComponent("elements.Spinner");
|
|
|
|
const modal = Modal.createDialog(Loader, null, 'mx_Dialog_spinner');
|
|
|
|
|
|
|
|
d.then(() => {
|
|
|
|
modal.close();
|
2017-05-24 15:56:13 +00:00
|
|
|
if (this.state.currentRoomId === roomId) {
|
2017-05-19 12:53:11 +00:00
|
|
|
dis.dispatch({action: 'view_next_room'});
|
|
|
|
}
|
|
|
|
}, (err) => {
|
|
|
|
modal.close();
|
|
|
|
console.error("Failed to leave room " + roomId + " " + err);
|
2018-05-24 15:54:48 +00:00
|
|
|
let title = _t("Failed to leave room");
|
|
|
|
let message = _t("Server may be unavailable, overloaded, or you hit a bug.");
|
|
|
|
if (err.errcode == 'M_CANNOT_LEAVE_SERVER_NOTICE_ROOM') {
|
|
|
|
title = _t("Can't leave Server Notices room");
|
|
|
|
message = _t(
|
2018-05-24 16:01:00 +00:00
|
|
|
"This room is used for important messages from the Homeserver, " +
|
2018-05-24 15:54:48 +00:00
|
|
|
"so you cannot leave it.",
|
|
|
|
);
|
|
|
|
} else if (err && err.message) {
|
|
|
|
message = err.message;
|
|
|
|
}
|
2017-08-10 12:49:11 +00:00
|
|
|
Modal.createTrackedDialog('Failed to leave room', '', ErrorDialog, {
|
2018-05-24 15:54:48 +00:00
|
|
|
title: title,
|
|
|
|
description: message,
|
2017-05-19 12:53:11 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
2016-08-09 23:03:29 +00:00
|
|
|
},
|
|
|
|
|
2017-01-17 19:13:23 +00:00
|
|
|
/**
|
|
|
|
* Called whenever someone changes the theme
|
2017-05-19 12:53:11 +00:00
|
|
|
*
|
|
|
|
* @param {string} theme new theme
|
2017-01-17 19:13:23 +00:00
|
|
|
*/
|
|
|
|
_onSetTheme: function(theme) {
|
|
|
|
if (!theme) {
|
2017-11-17 03:52:12 +00:00
|
|
|
theme = SettingsStore.getValue("theme");
|
2017-01-17 19:13:23 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 15:36:57 +00:00
|
|
|
// look for the stylesheet elements.
|
|
|
|
// styleElements is a map from style name to HTMLLinkElement.
|
2017-05-19 12:53:11 +00:00
|
|
|
const styleElements = Object.create(null);
|
|
|
|
let a;
|
|
|
|
for (let i = 0; (a = document.getElementsByTagName("link")[i]); i++) {
|
|
|
|
const href = a.getAttribute("href");
|
2017-01-19 15:36:57 +00:00
|
|
|
// shouldn't we be using the 'title' tag rather than the href?
|
2017-05-19 12:53:11 +00:00
|
|
|
const match = href.match(/^bundles\/.*\/theme-(.*)\.css$/);
|
2017-01-18 14:06:47 +00:00
|
|
|
if (match) {
|
2017-01-19 15:36:57 +00:00
|
|
|
styleElements[match[1]] = a;
|
2017-01-17 19:13:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-19 15:36:57 +00:00
|
|
|
if (!(theme in styleElements)) {
|
|
|
|
throw new Error("Unknown theme " + theme);
|
|
|
|
}
|
|
|
|
|
|
|
|
// disable all of them first, then enable the one we want. Chrome only
|
|
|
|
// bothers to do an update on a true->false transition, so this ensures
|
|
|
|
// that we get exactly one update, at the right time.
|
2017-11-14 15:28:34 +00:00
|
|
|
//
|
|
|
|
// ^ This comment was true when we used to use alternative stylesheets
|
|
|
|
// for the CSS. Nowadays we just set them all as disabled in index.html
|
|
|
|
// and enable them as needed. It might be cleaner to disable them all
|
|
|
|
// at the same time to prevent loading two themes simultaneously and
|
|
|
|
// having them interact badly... but this causes a flash of unstyled app
|
|
|
|
// which is even uglier. So we don't.
|
2017-01-19 15:36:57 +00:00
|
|
|
|
|
|
|
styleElements[theme].disabled = false;
|
|
|
|
|
2017-11-14 15:37:03 +00:00
|
|
|
const switchTheme = function() {
|
2017-11-15 09:56:44 +00:00
|
|
|
// we re-enable our theme here just in case we raced with another
|
|
|
|
// theme set request as per https://github.com/vector-im/riot-web/issues/5601.
|
|
|
|
// We could alternatively lock or similar to stop the race, but
|
|
|
|
// this is probably good enough for now.
|
|
|
|
styleElements[theme].disabled = false;
|
2017-11-14 15:28:34 +00:00
|
|
|
Object.values(styleElements).forEach((a) => {
|
|
|
|
if (a == styleElements[theme]) return;
|
|
|
|
a.disabled = true;
|
|
|
|
});
|
|
|
|
Tinter.setTheme(theme);
|
|
|
|
};
|
|
|
|
|
2017-11-14 16:07:48 +00:00
|
|
|
// turns out that Firefox preloads the CSS for link elements with
|
|
|
|
// the disabled attribute, but Chrome doesn't.
|
|
|
|
|
2017-11-14 16:04:11 +00:00
|
|
|
let cssLoaded = false;
|
|
|
|
|
2017-11-14 16:07:48 +00:00
|
|
|
styleElements[theme].onload = () => {
|
|
|
|
switchTheme();
|
|
|
|
};
|
|
|
|
|
2017-11-14 16:04:11 +00:00
|
|
|
for (let i = 0; i < document.styleSheets.length; i++) {
|
|
|
|
const ss = document.styleSheets[i];
|
|
|
|
if (ss && ss.href === styleElements[theme].href) {
|
|
|
|
cssLoaded = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cssLoaded) {
|
2017-11-14 16:07:48 +00:00
|
|
|
styleElements[theme].onload = undefined;
|
2017-11-14 15:28:34 +00:00
|
|
|
switchTheme();
|
|
|
|
}
|
2016-08-09 23:03:29 +00:00
|
|
|
},
|
|
|
|
|
2016-08-02 18:05:05 +00:00
|
|
|
/**
|
|
|
|
* Called when a new logged in session has started
|
|
|
|
*/
|
2019-01-25 22:10:54 +00:00
|
|
|
_onLoggedIn: async function() {
|
2019-01-02 20:07:10 +00:00
|
|
|
this.setStateForNewView({view: VIEWS.LOGGED_IN});
|
2019-01-25 22:10:54 +00:00
|
|
|
if (this._is_registered) {
|
2017-05-24 15:56:13 +00:00
|
|
|
this._is_registered = false;
|
2017-05-26 10:46:33 +00:00
|
|
|
|
2017-06-02 13:13:33 +00:00
|
|
|
if (this.props.config.welcomeUserId && getCurrentLanguage().startsWith("en")) {
|
2018-09-04 12:26:36 +00:00
|
|
|
const roomId = await createRoom({
|
2017-05-24 15:56:13 +00:00
|
|
|
dmUserId: this.props.config.welcomeUserId,
|
2017-06-05 13:07:24 +00:00
|
|
|
// Only view the welcome user if we're NOT looking at a room
|
|
|
|
andView: !this.state.currentRoomId,
|
2017-05-24 15:56:13 +00:00
|
|
|
});
|
2018-09-04 12:26:36 +00:00
|
|
|
// if successful, return because we're already
|
|
|
|
// viewing the welcomeUserId room
|
|
|
|
// else, if failed, fall through to view_home_page
|
|
|
|
if (roomId) {
|
|
|
|
return;
|
|
|
|
}
|
2017-05-12 16:39:38 +00:00
|
|
|
}
|
2017-04-06 16:10:32 +00:00
|
|
|
// The user has just logged in after registering
|
2017-05-24 16:55:36 +00:00
|
|
|
dis.dispatch({action: 'view_home_page'});
|
2017-03-15 12:02:08 +00:00
|
|
|
} else {
|
|
|
|
this._showScreenAfterLogin();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_showScreenAfterLogin: function() {
|
2017-03-08 10:25:54 +00:00
|
|
|
// If screenAfterLogin is set, use that, then null it so that a second login will
|
|
|
|
// result in view_home_page, _user_settings or _room_directory
|
2017-08-08 21:19:38 +00:00
|
|
|
if (this._screenAfterLogin && this._screenAfterLogin.screen) {
|
2017-03-08 10:25:54 +00:00
|
|
|
this.showScreen(
|
2017-08-08 21:19:38 +00:00
|
|
|
this._screenAfterLogin.screen,
|
|
|
|
this._screenAfterLogin.params,
|
2017-03-08 10:25:54 +00:00
|
|
|
);
|
2017-08-08 21:19:38 +00:00
|
|
|
this._screenAfterLogin = null;
|
2017-04-06 10:30:47 +00:00
|
|
|
} else if (localStorage && localStorage.getItem('mx_last_room_id')) {
|
|
|
|
// Before defaulting to directory, show the last viewed room
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_room',
|
|
|
|
room_id: localStorage.getItem('mx_last_room_id'),
|
|
|
|
});
|
2017-03-08 15:11:38 +00:00
|
|
|
} else {
|
2019-02-08 15:43:17 +00:00
|
|
|
if (MatrixClientPeg.get().isGuest()) {
|
2019-02-08 12:12:43 +00:00
|
|
|
dis.dispatch({action: 'view_welcome_page'});
|
|
|
|
} else {
|
|
|
|
dis.dispatch({action: 'view_home_page'});
|
|
|
|
}
|
2017-02-28 15:05:49 +00:00
|
|
|
}
|
2015-06-12 13:59:33 +00:00
|
|
|
},
|
|
|
|
|
2016-08-02 18:05:05 +00:00
|
|
|
/**
|
|
|
|
* Called when the session is logged out
|
|
|
|
*/
|
2016-08-02 13:04:20 +00:00
|
|
|
_onLoggedOut: function() {
|
|
|
|
this.notifyNewScreen('login');
|
2017-06-09 16:18:45 +00:00
|
|
|
this.setStateForNewView({
|
2017-06-14 19:04:55 +00:00
|
|
|
view: VIEWS.LOGIN,
|
2016-08-02 13:04:20 +00:00
|
|
|
ready: false,
|
2017-08-25 11:10:13 +00:00
|
|
|
collapseLhs: false,
|
2018-12-17 14:30:39 +00:00
|
|
|
collapsedRhs: false,
|
2016-11-24 14:58:37 +00:00
|
|
|
currentRoomId: null,
|
|
|
|
page_type: PageTypes.RoomDirectory,
|
2016-08-02 13:04:20 +00:00
|
|
|
});
|
2017-06-20 15:15:42 +00:00
|
|
|
this._setPageSubtitle();
|
2016-08-02 13:04:20 +00:00
|
|
|
},
|
|
|
|
|
2016-08-02 18:05:05 +00:00
|
|
|
/**
|
|
|
|
* Called just before the matrix client is started
|
2016-08-03 08:53:02 +00:00
|
|
|
* (useful for setting listeners)
|
2016-08-02 18:05:05 +00:00
|
|
|
*/
|
2016-08-02 13:04:20 +00:00
|
|
|
_onWillStartClient() {
|
2017-05-19 12:53:11 +00:00
|
|
|
const self = this;
|
2017-06-21 10:27:18 +00:00
|
|
|
|
|
|
|
// reset the 'have completed first sync' flag,
|
|
|
|
// since we're about to start the client and therefore about
|
|
|
|
// to do the first sync
|
|
|
|
this.firstSyncComplete = false;
|
2017-07-12 13:04:20 +00:00
|
|
|
this.firstSyncPromise = Promise.defer();
|
2017-05-19 12:53:11 +00:00
|
|
|
const cli = MatrixClientPeg.get();
|
2019-01-15 18:08:13 +00:00
|
|
|
const IncomingSasDialog = sdk.getComponent('views.dialogs.IncomingSasDialog');
|
2016-08-02 13:04:20 +00:00
|
|
|
|
2017-03-22 15:06:52 +00:00
|
|
|
// Allow the JS SDK to reap timeline events. This reduces the amount of
|
|
|
|
// memory consumed as the JS SDK stores multiple distinct copies of room
|
|
|
|
// state (each of which can be 10s of MBs) for each DISJOINT timeline. This is
|
|
|
|
// particularly noticeable when there are lots of 'limited' /sync responses
|
|
|
|
// such as when laptops unsleep.
|
|
|
|
// https://github.com/vector-im/riot-web/issues/3307#issuecomment-282895568
|
|
|
|
cli.setCanResetTimelineCallback(function(roomId) {
|
|
|
|
console.log("Request to reset timeline in room ", roomId, " viewing:", self.state.currentRoomId);
|
|
|
|
if (roomId !== self.state.currentRoomId) {
|
|
|
|
// It is safe to remove events from rooms we are not viewing.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// We are viewing the room which we want to reset. It is only safe to do
|
|
|
|
// this if we are not scrolled up in the view. To find out, delegate to
|
|
|
|
// the timeline panel. If the timeline panel doesn't exist, then we assume
|
|
|
|
// it is safe to reset the timeline.
|
2018-01-19 13:34:56 +00:00
|
|
|
if (!self._loggedInView || !self._loggedInView.child) {
|
2017-03-22 15:06:52 +00:00
|
|
|
return true;
|
|
|
|
}
|
2018-01-19 13:34:56 +00:00
|
|
|
return self._loggedInView.child.canResetTimelineInRoom(roomId);
|
2017-03-22 15:06:52 +00:00
|
|
|
});
|
|
|
|
|
2018-09-07 11:18:25 +00:00
|
|
|
cli.on('sync', function(state, prevState, data) {
|
2017-05-25 08:30:57 +00:00
|
|
|
// LifecycleStore and others cannot directly subscribe to matrix client for
|
|
|
|
// events because flux only allows store state changes during flux dispatches.
|
|
|
|
// So dispatch directly from here. Ideally we'd use a SyncStateStore that
|
|
|
|
// would do this dispatch and expose the sync state itself (by listening to
|
|
|
|
// its own dispatch).
|
2017-05-24 15:56:13 +00:00
|
|
|
dis.dispatch({action: 'sync_state', prevState, state});
|
2018-09-07 11:18:25 +00:00
|
|
|
|
2018-09-27 20:31:55 +00:00
|
|
|
if (state === "ERROR" || state === "RECONNECTING") {
|
2018-10-10 16:07:17 +00:00
|
|
|
if (data.error instanceof Matrix.InvalidStoreError) {
|
|
|
|
Lifecycle.handleInvalidStoreError(data.error);
|
|
|
|
}
|
2018-09-27 20:31:55 +00:00
|
|
|
self.setState({syncError: data.error || true});
|
2018-09-07 11:18:25 +00:00
|
|
|
} else if (self.state.syncError) {
|
|
|
|
self.setState({syncError: null});
|
|
|
|
}
|
|
|
|
|
2016-11-02 15:10:21 +00:00
|
|
|
self.updateStatusIndicator(state, prevState);
|
2015-12-15 14:23:58 +00:00
|
|
|
if (state === "SYNCING" && prevState === "SYNCING") {
|
|
|
|
return;
|
|
|
|
}
|
2015-11-12 15:15:00 +00:00
|
|
|
console.log("MatrixClient sync state => %s", state);
|
|
|
|
if (state !== "PREPARED") { return; }
|
2015-09-25 16:22:42 +00:00
|
|
|
|
2017-04-06 10:30:47 +00:00
|
|
|
self.firstSyncComplete = true;
|
|
|
|
self.firstSyncPromise.resolve();
|
2015-09-25 16:22:42 +00:00
|
|
|
|
2017-04-06 10:44:15 +00:00
|
|
|
dis.dispatch({action: 'focus_composer'});
|
|
|
|
self.setState({ready: true});
|
2015-06-12 13:59:33 +00:00
|
|
|
});
|
2015-09-18 17:39:16 +00:00
|
|
|
cli.on('Call.incoming', function(call) {
|
2017-08-24 12:05:17 +00:00
|
|
|
// we dispatch this synchronously to make sure that the event
|
|
|
|
// handlers on the call are set up immediately (so that if
|
|
|
|
// we get an immediate hangup, we don't get a stuck call)
|
2015-09-18 17:39:16 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'incoming_call',
|
2017-05-19 12:53:11 +00:00
|
|
|
call: call,
|
2017-08-24 12:05:17 +00:00
|
|
|
}, true);
|
2015-09-18 17:39:16 +00:00
|
|
|
});
|
2016-03-15 10:48:16 +00:00
|
|
|
cli.on('Session.logged_out', function(call) {
|
2018-07-15 21:33:00 +00:00
|
|
|
if (Lifecycle.isLoggingOut()) return;
|
2017-05-19 12:53:11 +00:00
|
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
2017-07-27 16:19:18 +00:00
|
|
|
Modal.createTrackedDialog('Signed out', '', ErrorDialog, {
|
2017-05-23 14:16:31 +00:00
|
|
|
title: _t('Signed Out'),
|
|
|
|
description: _t('For security, this session has been signed out. Please sign in again.'),
|
2016-03-15 10:48:16 +00:00
|
|
|
});
|
|
|
|
dis.dispatch({
|
2017-05-19 12:53:11 +00:00
|
|
|
action: 'logout',
|
2016-03-15 10:48:16 +00:00
|
|
|
});
|
|
|
|
});
|
2018-05-22 14:47:31 +00:00
|
|
|
cli.on('no_consent', function(message, consentUri) {
|
|
|
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
|
|
|
Modal.createTrackedDialog('No Consent Dialog', '', QuestionDialog, {
|
|
|
|
title: _t('Terms and Conditions'),
|
|
|
|
description: <div>
|
|
|
|
<p> { _t(
|
|
|
|
'To continue using the %(homeserverDomain)s homeserver ' +
|
|
|
|
'you must review and agree to our terms and conditions.',
|
|
|
|
{ homeserverDomain: cli.getDomain() },
|
|
|
|
) }
|
|
|
|
</p>
|
|
|
|
</div>,
|
|
|
|
button: _t('Review terms and conditions'),
|
|
|
|
cancelButton: _t('Dismiss'),
|
|
|
|
onFinished: (confirmed) => {
|
|
|
|
if (confirmed) {
|
|
|
|
window.open(consentUri, '_blank');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}, null, true);
|
|
|
|
});
|
|
|
|
|
2017-01-18 20:06:54 +00:00
|
|
|
cli.on("accountData", function(ev) {
|
|
|
|
if (ev.getType() === 'im.vector.web.settings') {
|
|
|
|
if (ev.getContent() && ev.getContent().theme) {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'set_theme',
|
|
|
|
value: ev.getContent().theme,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2015-06-25 16:41:55 +00:00
|
|
|
|
2018-07-05 12:54:44 +00:00
|
|
|
const dft = new DecryptionFailureTracker((total, errorCode) => {
|
|
|
|
Analytics.trackEvent('E2E', 'Decryption failure', errorCode, total);
|
|
|
|
}, (errorCode) => {
|
|
|
|
// Map JS-SDK error codes to tracker codes for aggregation
|
|
|
|
switch (errorCode) {
|
|
|
|
case 'MEGOLM_UNKNOWN_INBOUND_SESSION_ID':
|
|
|
|
return 'olm_keys_not_sent_error';
|
|
|
|
case 'OLM_UNKNOWN_MESSAGE_INDEX':
|
|
|
|
return 'olm_index_error';
|
|
|
|
case undefined:
|
|
|
|
return 'unexpected_error';
|
|
|
|
default:
|
|
|
|
return 'unspecified_error';
|
|
|
|
}
|
2018-06-12 13:13:09 +00:00
|
|
|
});
|
2018-06-15 16:08:11 +00:00
|
|
|
|
|
|
|
// Shelved for later date when we have time to think about persisting history of
|
|
|
|
// tracked events across sessions.
|
|
|
|
// dft.loadTrackedEventHashMap();
|
2018-06-12 13:13:09 +00:00
|
|
|
|
2018-06-15 16:58:43 +00:00
|
|
|
dft.start();
|
2018-06-15 12:33:07 +00:00
|
|
|
|
|
|
|
// When logging out, stop tracking failures and destroy state
|
2018-06-15 16:58:43 +00:00
|
|
|
cli.on("Session.logged_out", () => dft.stop());
|
2018-07-05 12:54:44 +00:00
|
|
|
cli.on("Event.decrypted", (e, err) => dft.eventDecrypted(e, err));
|
2018-06-15 12:33:07 +00:00
|
|
|
|
2017-05-19 08:54:29 +00:00
|
|
|
const krh = new KeyRequestHandler(cli);
|
|
|
|
cli.on("crypto.roomKeyRequest", (req) => {
|
|
|
|
krh.handleKeyRequest(req);
|
|
|
|
});
|
2017-06-01 16:49:24 +00:00
|
|
|
cli.on("crypto.roomKeyRequestCancellation", (req) => {
|
|
|
|
krh.handleKeyRequestCancellation(req);
|
|
|
|
});
|
2018-01-15 02:02:48 +00:00
|
|
|
|
2017-11-05 03:13:23 +00:00
|
|
|
cli.on("Room", (room) => {
|
2017-11-05 21:56:41 +00:00
|
|
|
if (MatrixClientPeg.get().isCryptoEnabled()) {
|
|
|
|
const blacklistEnabled = SettingsStore.getValueAt(
|
|
|
|
SettingLevel.ROOM_DEVICE,
|
|
|
|
"blacklistUnverifiedDevices",
|
|
|
|
room.roomId,
|
2017-11-09 00:41:32 +00:00
|
|
|
/*explicit=*/true,
|
2017-11-05 21:56:41 +00:00
|
|
|
);
|
|
|
|
room.setBlacklistUnverifiedDevices(blacklistEnabled);
|
|
|
|
}
|
2017-11-05 03:13:23 +00:00
|
|
|
});
|
2017-12-06 15:28:20 +00:00
|
|
|
cli.on("crypto.warning", (type) => {
|
|
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
|
|
switch (type) {
|
|
|
|
case 'CRYPTO_WARNING_OLD_VERSION_DETECTED':
|
|
|
|
Modal.createTrackedDialog('Crypto migrated', '', ErrorDialog, {
|
|
|
|
title: _t('Old cryptography data detected'),
|
|
|
|
description: _t(
|
|
|
|
"Data from an older version of Riot has been detected. "+
|
|
|
|
"This will have caused end-to-end cryptography to malfunction "+
|
|
|
|
"in the older version. End-to-end encrypted messages exchanged "+
|
|
|
|
"recently whilst using the older version may not be decryptable "+
|
2017-12-06 18:57:48 +00:00
|
|
|
"in this version. This may also cause messages exchanged with this "+
|
|
|
|
"version to fail. If you experience problems, log out and back in "+
|
|
|
|
"again. To retain message history, export and re-import your keys.",
|
2017-12-06 15:28:20 +00:00
|
|
|
),
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
2019-01-11 13:15:09 +00:00
|
|
|
cli.on("crypto.keyBackupFailed", async (errcode) => {
|
|
|
|
let haveNewVersion;
|
|
|
|
let newVersionInfo;
|
|
|
|
// if key backup is still enabled, there must be a new backup in place
|
|
|
|
if (MatrixClientPeg.get().getKeyBackupEnabled()) {
|
|
|
|
haveNewVersion = true;
|
|
|
|
} else {
|
|
|
|
// otherwise check the server to see if there's a new one
|
|
|
|
try {
|
|
|
|
newVersionInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
|
|
|
if (newVersionInfo !== null) haveNewVersion = true;
|
|
|
|
} catch (e) {
|
|
|
|
console.error("Saw key backup error but failed to check backup version!", e);
|
2019-01-10 21:13:44 +00:00
|
|
|
return;
|
2019-01-11 13:15:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (haveNewVersion) {
|
|
|
|
Modal.createTrackedDialogAsync('New Recovery Method', 'New Recovery Method',
|
|
|
|
import('../../async-components/views/dialogs/keybackup/NewRecoveryMethodDialog'),
|
2019-01-11 13:42:40 +00:00
|
|
|
{ newVersionInfo },
|
2019-01-11 13:15:09 +00:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
Modal.createTrackedDialogAsync('Recovery Method Removed', 'Recovery Method Removed',
|
|
|
|
import('../../async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog'),
|
|
|
|
);
|
2019-01-10 21:13:44 +00:00
|
|
|
}
|
2018-12-13 15:55:48 +00:00
|
|
|
});
|
2018-10-15 20:41:00 +00:00
|
|
|
|
2019-01-15 18:08:13 +00:00
|
|
|
cli.on("crypto.verification.start", (verifier) => {
|
|
|
|
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
|
|
|
|
verifier,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-10-15 20:41:00 +00:00
|
|
|
// Fire the tinter right on startup to ensure the default theme is applied
|
|
|
|
// A later sync can/will correct the tint to be the right value for the user
|
2018-10-23 04:07:41 +00:00
|
|
|
const colorScheme = SettingsStore.getValue("roomColor");
|
|
|
|
Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
|
2017-11-05 03:13:23 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called shortly after the matrix client has started. Useful for
|
|
|
|
* setting up anything that requires the client to be started.
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_onClientStarted: function() {
|
|
|
|
const cli = MatrixClientPeg.get();
|
|
|
|
|
2017-11-05 21:56:41 +00:00
|
|
|
if (cli.isCryptoEnabled()) {
|
|
|
|
const blacklistEnabled = SettingsStore.getValueAt(
|
|
|
|
SettingLevel.DEVICE,
|
2017-11-05 22:37:06 +00:00
|
|
|
"blacklistUnverifiedDevices",
|
2017-11-05 21:56:41 +00:00
|
|
|
);
|
|
|
|
cli.setGlobalBlacklistUnverifiedDevices(blacklistEnabled);
|
|
|
|
}
|
2015-07-15 18:25:36 +00:00
|
|
|
},
|
|
|
|
|
2015-07-16 11:44:04 +00:00
|
|
|
showScreen: function(screen, params) {
|
2015-07-15 19:33:12 +00:00
|
|
|
if (screen == 'register') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'start_registration',
|
2017-05-19 12:53:11 +00:00
|
|
|
params: params,
|
2015-07-15 19:33:12 +00:00
|
|
|
});
|
|
|
|
} else if (screen == 'login') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'start_login',
|
2017-05-19 12:53:11 +00:00
|
|
|
params: params,
|
2015-07-15 19:33:12 +00:00
|
|
|
});
|
2016-01-12 17:20:16 +00:00
|
|
|
} else if (screen == 'forgot_password') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'start_password_recovery',
|
2017-05-19 12:53:11 +00:00
|
|
|
params: params,
|
2016-01-12 17:20:16 +00:00
|
|
|
});
|
2015-11-11 01:01:48 +00:00
|
|
|
} else if (screen == 'new') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_create_room',
|
|
|
|
});
|
|
|
|
} else if (screen == 'settings') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_user_settings',
|
|
|
|
});
|
2019-02-07 16:25:09 +00:00
|
|
|
} else if (screen == 'welcome') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_welcome_page',
|
|
|
|
});
|
2016-11-13 14:10:46 +00:00
|
|
|
} else if (screen == 'home') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_home_page',
|
|
|
|
});
|
2017-05-30 13:27:02 +00:00
|
|
|
} else if (screen == 'start') {
|
|
|
|
this.showScreen('home');
|
|
|
|
dis.dispatch({
|
2018-09-05 17:08:49 +00:00
|
|
|
action: 'require_registration',
|
2017-05-30 13:27:02 +00:00
|
|
|
});
|
2015-11-11 01:01:48 +00:00
|
|
|
} else if (screen == 'directory') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_room_directory',
|
|
|
|
});
|
2017-06-28 12:56:18 +00:00
|
|
|
} else if (screen == 'groups') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_my_groups',
|
|
|
|
});
|
2015-11-20 11:57:04 +00:00
|
|
|
} else if (screen == 'post_registration') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'start_post_registration',
|
|
|
|
});
|
2015-09-18 17:39:16 +00:00
|
|
|
} else if (screen.indexOf('room/') == 0) {
|
2017-05-19 12:53:11 +00:00
|
|
|
const segments = screen.substring(5).split('/');
|
|
|
|
const roomString = segments[0];
|
|
|
|
const eventId = segments[1]; // undefined if no event id given
|
2016-03-01 18:23:57 +00:00
|
|
|
|
2016-03-17 18:38:25 +00:00
|
|
|
// FIXME: sort_out caseConsistency
|
2017-05-19 12:53:11 +00:00
|
|
|
const thirdPartyInvite = {
|
2016-03-17 18:38:25 +00:00
|
|
|
inviteSignUrl: params.signurl,
|
|
|
|
invitedEmail: params.email,
|
|
|
|
};
|
2017-05-19 12:53:11 +00:00
|
|
|
const oobData = {
|
2016-03-01 18:23:57 +00:00
|
|
|
name: params.room_name,
|
|
|
|
avatarUrl: params.room_avatar_url,
|
|
|
|
inviterName: params.inviter_name,
|
|
|
|
};
|
|
|
|
|
2018-10-19 19:30:38 +00:00
|
|
|
// on our URLs there might be a ?via=matrix.org or similar to help
|
|
|
|
// joins to the room succeed. We'll pass these through as an array
|
|
|
|
// to other levels. If there's just one ?via= then params.via is a
|
|
|
|
// single string. If someone does something like ?via=one.com&via=two.com
|
|
|
|
// then params.via is an array of strings.
|
|
|
|
let via = [];
|
|
|
|
if (params.via) {
|
|
|
|
if (typeof(params.via) === 'string') via = [params.via];
|
|
|
|
else via = params.via;
|
|
|
|
}
|
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
const payload = {
|
2016-06-10 14:12:42 +00:00
|
|
|
action: 'view_room',
|
|
|
|
event_id: eventId,
|
2018-10-19 19:30:38 +00:00
|
|
|
via_servers: via,
|
2017-06-08 16:57:37 +00:00
|
|
|
// If an event ID is given in the URL hash, notify RoomViewStore to mark
|
|
|
|
// it as highlighted, which will propagate to RoomView and highlight the
|
|
|
|
// associated EventTile.
|
2017-06-08 13:17:49 +00:00
|
|
|
highlighted: Boolean(eventId),
|
2017-05-19 12:53:11 +00:00
|
|
|
third_party_invite: thirdPartyInvite,
|
|
|
|
oob_data: oobData,
|
2016-06-10 14:12:42 +00:00
|
|
|
};
|
2015-09-18 17:39:16 +00:00
|
|
|
if (roomString[0] == '#') {
|
2016-06-10 14:12:42 +00:00
|
|
|
payload.room_alias = roomString;
|
2015-09-18 17:39:16 +00:00
|
|
|
} else {
|
2016-06-10 14:12:42 +00:00
|
|
|
payload.room_id = roomString;
|
2016-06-09 17:49:06 +00:00
|
|
|
}
|
|
|
|
|
2019-02-11 13:49:18 +00:00
|
|
|
dis.dispatch(payload);
|
2016-08-28 00:55:42 +00:00
|
|
|
} else if (screen.indexOf('user/') == 0) {
|
2017-05-19 12:53:11 +00:00
|
|
|
const userId = screen.substring(5);
|
2017-06-01 13:16:25 +00:00
|
|
|
|
2017-08-14 13:41:03 +00:00
|
|
|
// Wait for the first sync so that `getRoom` gives us a room object if it's
|
|
|
|
// in the sync response
|
2017-08-14 13:37:49 +00:00
|
|
|
const waitFor = this.firstSyncPromise ?
|
|
|
|
this.firstSyncPromise.promise : Promise.resolve();
|
|
|
|
waitFor.then(() => {
|
|
|
|
if (params.action === 'chat') {
|
|
|
|
this._chatCreateOrReuse(userId);
|
|
|
|
return;
|
|
|
|
}
|
2017-06-01 13:16:25 +00:00
|
|
|
|
2017-08-14 13:37:49 +00:00
|
|
|
this._setPage(PageTypes.UserView);
|
|
|
|
this.notifyNewScreen('user/' + userId);
|
|
|
|
const member = new Matrix.RoomMember(null, userId);
|
2016-08-28 00:55:42 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_user',
|
|
|
|
member: member,
|
|
|
|
});
|
2017-08-14 13:37:49 +00:00
|
|
|
});
|
2017-06-05 15:51:50 +00:00
|
|
|
} else if (screen.indexOf('group/') == 0) {
|
|
|
|
const groupId = screen.substring(6);
|
|
|
|
|
|
|
|
// TODO: Check valid group ID
|
|
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_group',
|
|
|
|
group_id: groupId,
|
|
|
|
});
|
2017-05-19 12:53:11 +00:00
|
|
|
} else {
|
2016-03-06 19:33:36 +00:00
|
|
|
console.info("Ignoring showScreen for '%s'", screen);
|
2015-11-20 14:26:49 +00:00
|
|
|
}
|
2015-07-15 18:25:36 +00:00
|
|
|
},
|
|
|
|
|
2015-12-17 15:12:09 +00:00
|
|
|
notifyNewScreen: function(screen) {
|
2015-07-15 18:25:36 +00:00
|
|
|
if (this.props.onNewScreen) {
|
2015-12-17 15:12:09 +00:00
|
|
|
this.props.onNewScreen(screen);
|
2015-07-15 18:25:36 +00:00
|
|
|
}
|
2015-11-30 18:11:04 +00:00
|
|
|
},
|
|
|
|
|
2016-08-28 01:05:23 +00:00
|
|
|
onAliasClick: function(event, alias) {
|
|
|
|
event.preventDefault();
|
|
|
|
dis.dispatch({action: 'view_room', room_alias: alias});
|
|
|
|
},
|
|
|
|
|
|
|
|
onUserClick: function(event, userId) {
|
|
|
|
event.preventDefault();
|
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
const member = new Matrix.RoomMember(null, userId);
|
2016-08-28 01:05:23 +00:00
|
|
|
if (!member) { return; }
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_user',
|
|
|
|
member: member,
|
|
|
|
});
|
|
|
|
},
|
2015-11-30 18:11:04 +00:00
|
|
|
|
2017-06-05 15:51:50 +00:00
|
|
|
onGroupClick: function(event, groupId) {
|
|
|
|
event.preventDefault();
|
|
|
|
dis.dispatch({action: 'view_group', group_id: groupId});
|
|
|
|
},
|
|
|
|
|
2015-11-30 18:11:04 +00:00
|
|
|
onLogoutClick: function(event) {
|
|
|
|
dis.dispatch({
|
2017-05-19 12:53:11 +00:00
|
|
|
action: 'logout',
|
2015-11-30 18:11:04 +00:00
|
|
|
});
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
},
|
|
|
|
|
|
|
|
handleResize: function(e) {
|
2017-05-19 12:53:11 +00:00
|
|
|
const hideLhsThreshold = 1000;
|
|
|
|
const showLhsThreshold = 1000;
|
|
|
|
const hideRhsThreshold = 820;
|
|
|
|
const showRhsThreshold = 820;
|
2015-11-30 18:11:04 +00:00
|
|
|
|
2017-08-08 21:19:38 +00:00
|
|
|
if (this._windowWidth > hideLhsThreshold && window.innerWidth <= hideLhsThreshold) {
|
2015-11-30 18:11:04 +00:00
|
|
|
dis.dispatch({ action: 'hide_left_panel' });
|
|
|
|
}
|
2017-08-08 21:19:38 +00:00
|
|
|
if (this._windowWidth <= showLhsThreshold && window.innerWidth > showLhsThreshold) {
|
2015-11-30 18:11:04 +00:00
|
|
|
dis.dispatch({ action: 'show_left_panel' });
|
|
|
|
}
|
2017-08-08 21:19:38 +00:00
|
|
|
if (this._windowWidth > hideRhsThreshold && window.innerWidth <= hideRhsThreshold) {
|
2015-11-30 18:11:04 +00:00
|
|
|
dis.dispatch({ action: 'hide_right_panel' });
|
|
|
|
}
|
2017-08-08 21:19:38 +00:00
|
|
|
if (this._windowWidth <= showRhsThreshold && window.innerWidth > showRhsThreshold) {
|
2015-11-30 18:11:04 +00:00
|
|
|
dis.dispatch({ action: 'show_right_panel' });
|
|
|
|
}
|
|
|
|
|
2017-08-08 21:19:38 +00:00
|
|
|
this._windowWidth = window.innerWidth;
|
2015-11-30 18:11:04 +00:00
|
|
|
},
|
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
onRoomCreated: function(roomId) {
|
2015-11-30 18:11:04 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: "view_room",
|
2017-05-19 12:53:11 +00:00
|
|
|
room_id: roomId,
|
2015-11-30 18:11:04 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
onRegisterClick: function() {
|
|
|
|
this.showScreen("register");
|
|
|
|
},
|
|
|
|
|
|
|
|
onLoginClick: function() {
|
|
|
|
this.showScreen("login");
|
|
|
|
},
|
|
|
|
|
2016-01-12 17:20:16 +00:00
|
|
|
onForgotPasswordClick: function() {
|
|
|
|
this.showScreen("forgot_password");
|
|
|
|
},
|
|
|
|
|
2017-06-19 09:22:18 +00:00
|
|
|
// returns a promise which resolves to the new MatrixClient
|
2019-01-25 22:10:54 +00:00
|
|
|
onRegistered: function(credentials) {
|
|
|
|
// XXX: This should be in state or ideally store(s) because we risk not
|
2017-05-24 15:56:13 +00:00
|
|
|
// rendering the most up-to-date view of state otherwise.
|
2017-02-28 15:05:49 +00:00
|
|
|
this._is_registered = true;
|
2017-06-19 09:22:18 +00:00
|
|
|
return Lifecycle.setLoggedIn(credentials);
|
2017-02-13 14:36:03 +00:00
|
|
|
},
|
|
|
|
|
2015-11-30 18:11:04 +00:00
|
|
|
onFinishPostRegistration: function() {
|
|
|
|
// Don't confuse this with "PageType" which is the middle window to show
|
|
|
|
this.setState({
|
2017-06-14 19:04:55 +00:00
|
|
|
view: VIEWS.LOGGED_IN,
|
2015-11-30 18:11:04 +00:00
|
|
|
});
|
|
|
|
this.showScreen("settings");
|
|
|
|
},
|
|
|
|
|
2016-11-02 15:58:17 +00:00
|
|
|
onVersion: function(current, latest, releaseNotes) {
|
2016-02-03 16:16:52 +00:00
|
|
|
this.setState({
|
2016-02-03 16:51:53 +00:00
|
|
|
version: current,
|
2016-08-15 22:01:02 +00:00
|
|
|
newVersion: latest,
|
2016-11-02 15:58:17 +00:00
|
|
|
hasNewVersion: current !== latest,
|
|
|
|
newVersionReleaseNotes: releaseNotes,
|
2017-06-11 18:12:40 +00:00
|
|
|
checkingForUpdate: null,
|
2016-02-03 16:16:52 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-06-16 15:12:52 +00:00
|
|
|
onSendEvent: function(roomId, event) {
|
|
|
|
const cli = MatrixClientPeg.get();
|
|
|
|
if (!cli) {
|
|
|
|
dis.dispatch({action: 'message_send_failed'});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cli.sendEvent(roomId, event.getType(), event.getContent()).done(() => {
|
|
|
|
dis.dispatch({action: 'message_sent'});
|
|
|
|
}, (err) => {
|
|
|
|
dis.dispatch({action: 'message_send_failed'});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-06-20 14:31:12 +00:00
|
|
|
_setPageSubtitle: function(subtitle='') {
|
|
|
|
document.title = `Riot ${subtitle}`;
|
|
|
|
},
|
|
|
|
|
2016-11-02 15:10:21 +00:00
|
|
|
updateStatusIndicator: function(state, prevState) {
|
2017-05-19 12:53:11 +00:00
|
|
|
let notifCount = 0;
|
2015-12-21 12:55:13 +00:00
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
const rooms = MatrixClientPeg.get().getRooms();
|
|
|
|
for (let i = 0; i < rooms.length; ++i) {
|
2016-01-13 13:00:03 +00:00
|
|
|
if (rooms[i].hasMembershipState(MatrixClientPeg.get().credentials.userId, 'invite')) {
|
2016-05-17 10:14:12 +00:00
|
|
|
notifCount++;
|
2016-01-21 10:23:18 +00:00
|
|
|
} else if (rooms[i].getUnreadNotificationCount()) {
|
2016-05-17 10:14:12 +00:00
|
|
|
// if we were summing unread notifs:
|
|
|
|
// notifCount += rooms[i].getUnreadNotificationCount();
|
|
|
|
// instead, we just count the number of rooms with notifs.
|
|
|
|
notifCount++;
|
2016-01-07 10:38:44 +00:00
|
|
|
}
|
2015-12-21 12:55:13 +00:00
|
|
|
}
|
2016-03-16 01:02:49 +00:00
|
|
|
|
2016-11-02 15:10:21 +00:00
|
|
|
if (PlatformPeg.get()) {
|
|
|
|
PlatformPeg.get().setErrorStatus(state === 'ERROR');
|
|
|
|
PlatformPeg.get().setNotificationCount(notifCount);
|
2016-01-27 15:19:25 +00:00
|
|
|
}
|
2016-11-02 15:10:21 +00:00
|
|
|
|
2017-06-20 14:31:12 +00:00
|
|
|
let subtitle = '';
|
2017-06-07 10:40:46 +00:00
|
|
|
if (state === "ERROR") {
|
2017-06-20 14:31:12 +00:00
|
|
|
subtitle += `[${_t("Offline")}] `;
|
2017-06-07 10:40:46 +00:00
|
|
|
}
|
|
|
|
if (notifCount > 0) {
|
2017-06-20 14:31:12 +00:00
|
|
|
subtitle += `[${notifCount}]`;
|
2017-06-07 10:40:46 +00:00
|
|
|
}
|
|
|
|
|
2017-06-20 14:31:12 +00:00
|
|
|
this._setPageSubtitle(subtitle);
|
2015-12-21 12:55:13 +00:00
|
|
|
},
|
|
|
|
|
2018-05-29 12:16:39 +00:00
|
|
|
onCloseAllSettings() {
|
|
|
|
dis.dispatch({ action: 'close_settings' });
|
2015-12-23 11:47:56 +00:00
|
|
|
},
|
|
|
|
|
2018-02-07 15:51:03 +00:00
|
|
|
onServerConfigChange(config) {
|
|
|
|
const newState = {};
|
|
|
|
if (config.hsUrl) {
|
|
|
|
newState.register_hs_url = config.hsUrl;
|
|
|
|
}
|
|
|
|
if (config.isUrl) {
|
|
|
|
newState.register_is_url = config.isUrl;
|
|
|
|
}
|
|
|
|
this.setState(newState);
|
|
|
|
},
|
|
|
|
|
2018-12-05 06:34:57 +00:00
|
|
|
_tryDiscoverDefaultHomeserver: async function(serverName) {
|
2018-12-13 21:45:08 +00:00
|
|
|
try {
|
|
|
|
const discovery = await AutoDiscovery.findClientConfig(serverName);
|
|
|
|
const state = discovery["m.homeserver"].state;
|
|
|
|
if (state !== AutoDiscovery.SUCCESS) {
|
|
|
|
console.error("Failed to discover homeserver on startup:", discovery);
|
|
|
|
this.setState({
|
|
|
|
defaultServerDiscoveryError: discovery["m.homeserver"].error,
|
|
|
|
loadingDefaultHomeserver: false,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
const hsUrl = discovery["m.homeserver"].base_url;
|
|
|
|
const isUrl = discovery["m.identity_server"].state === AutoDiscovery.SUCCESS
|
|
|
|
? discovery["m.identity_server"].base_url
|
|
|
|
: "https://vector.im";
|
|
|
|
this.setState({
|
|
|
|
defaultHsUrl: hsUrl,
|
|
|
|
defaultIsUrl: isUrl,
|
|
|
|
loadingDefaultHomeserver: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e);
|
2018-12-07 22:36:49 +00:00
|
|
|
this.setState({
|
2018-12-13 21:45:08 +00:00
|
|
|
defaultServerDiscoveryError: _t("Unknown error discovering homeserver"),
|
2018-12-07 22:36:49 +00:00
|
|
|
loadingDefaultHomeserver: false,
|
|
|
|
});
|
2018-12-05 06:34:57 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-02-24 11:41:23 +00:00
|
|
|
_makeRegistrationUrl: function(params) {
|
|
|
|
if (this.props.startingFragmentQueryParams.referrer) {
|
|
|
|
params.referrer = this.props.startingFragmentQueryParams.referrer;
|
|
|
|
}
|
|
|
|
return this.props.makeRegistrationUrl(params);
|
|
|
|
},
|
|
|
|
|
2017-12-15 15:24:37 +00:00
|
|
|
_collectLoggedInView: function(ref) {
|
|
|
|
this._loggedInView = ref;
|
|
|
|
},
|
|
|
|
|
2015-11-30 18:11:04 +00:00
|
|
|
render: function() {
|
2017-06-14 19:04:55 +00:00
|
|
|
// console.log(`Rendering MatrixChat with view ${this.state.view}`);
|
|
|
|
|
2019-01-11 01:18:21 +00:00
|
|
|
if (
|
|
|
|
this.state.view === VIEWS.LOADING ||
|
|
|
|
this.state.view === VIEWS.LOGGING_IN ||
|
|
|
|
this.state.loadingDefaultHomeserver
|
|
|
|
) {
|
2017-03-29 14:24:47 +00:00
|
|
|
const Spinner = sdk.getComponent('elements.Spinner');
|
2016-08-09 23:03:29 +00:00
|
|
|
return (
|
2016-08-10 10:33:58 +00:00
|
|
|
<div className="mx_MatrixChat_splash">
|
|
|
|
<Spinner />
|
|
|
|
</div>
|
2016-08-09 23:03:29 +00:00
|
|
|
);
|
|
|
|
}
|
2017-05-19 12:53:11 +00:00
|
|
|
|
2015-11-30 18:11:04 +00:00
|
|
|
// needs to be before normal PageTypes as you are logged in technically
|
2017-06-09 16:18:45 +00:00
|
|
|
if (this.state.view === VIEWS.POST_REGISTRATION) {
|
2019-01-21 22:11:10 +00:00
|
|
|
const PostRegistration = sdk.getComponent('structures.auth.PostRegistration');
|
2015-11-30 18:11:04 +00:00
|
|
|
return (
|
|
|
|
<PostRegistration
|
|
|
|
onComplete={this.onFinishPostRegistration} />
|
|
|
|
);
|
2017-05-17 17:49:59 +00:00
|
|
|
}
|
|
|
|
|
2017-06-15 16:36:57 +00:00
|
|
|
if (this.state.view === VIEWS.LOGGED_IN) {
|
2018-10-10 16:07:17 +00:00
|
|
|
// store errors stop the client syncing and require user intervention, so we'll
|
|
|
|
// be showing a dialog. Don't show anything else.
|
|
|
|
const isStoreError = this.state.syncError && this.state.syncError instanceof Matrix.InvalidStoreError;
|
|
|
|
|
2017-06-15 16:36:57 +00:00
|
|
|
// `ready` and `view==LOGGED_IN` may be set before `page_type` (because the
|
|
|
|
// latter is set via the dispatcher). If we don't yet have a `page_type`,
|
|
|
|
// keep showing the spinner for now.
|
2018-10-10 16:07:17 +00:00
|
|
|
if (this.state.ready && this.state.page_type && !isStoreError) {
|
2017-06-15 16:36:57 +00:00
|
|
|
/* for now, we stuff the entirety of our props and state into the LoggedInView.
|
|
|
|
* we should go through and figure out what we actually need to pass down, as well
|
|
|
|
* as using something like redux to avoid having a billion bits of state kicking around.
|
|
|
|
*/
|
|
|
|
const LoggedInView = sdk.getComponent('structures.LoggedInView');
|
|
|
|
return (
|
2017-12-15 15:24:37 +00:00
|
|
|
<LoggedInView ref={this._collectLoggedInView} matrixClient={MatrixClientPeg.get()}
|
2017-06-15 16:36:57 +00:00
|
|
|
onRoomCreated={this.onRoomCreated}
|
2018-05-29 12:16:39 +00:00
|
|
|
onCloseAllSettings={this.onCloseAllSettings}
|
2017-06-15 16:36:57 +00:00
|
|
|
onRegistered={this.onRegistered}
|
|
|
|
currentRoomId={this.state.currentRoomId}
|
2018-05-15 12:15:40 +00:00
|
|
|
showCookieBar={this.state.showCookieBar}
|
2017-06-15 16:36:57 +00:00
|
|
|
{...this.props}
|
|
|
|
{...this.state}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// we think we are logged in, but are still waiting for the /sync to complete
|
|
|
|
const Spinner = sdk.getComponent('elements.Spinner');
|
2018-09-07 11:18:25 +00:00
|
|
|
let errorBox;
|
2018-10-10 16:07:17 +00:00
|
|
|
if (this.state.syncError && !isStoreError) {
|
2018-09-07 11:18:25 +00:00
|
|
|
errorBox = <div className="mx_MatrixChat_syncError">
|
|
|
|
{messageForSyncError(this.state.syncError)}
|
|
|
|
</div>;
|
|
|
|
}
|
2017-06-15 16:36:57 +00:00
|
|
|
return (
|
|
|
|
<div className="mx_MatrixChat_splash">
|
2018-09-07 11:18:25 +00:00
|
|
|
{errorBox}
|
2017-06-15 16:36:57 +00:00
|
|
|
<Spinner />
|
2017-09-28 10:21:06 +00:00
|
|
|
<a href="#" className="mx_MatrixChat_splashButtons" onClick={this.onLogoutClick}>
|
2017-06-15 16:36:57 +00:00
|
|
|
{ _t('Logout') }
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-07 16:25:09 +00:00
|
|
|
if (this.state.view === VIEWS.WELCOME) {
|
|
|
|
const Welcome = sdk.getComponent('auth.Welcome');
|
|
|
|
return <Welcome />;
|
|
|
|
}
|
|
|
|
|
2017-06-15 16:36:57 +00:00
|
|
|
if (this.state.view === VIEWS.REGISTER) {
|
2019-01-21 22:11:10 +00:00
|
|
|
const Registration = sdk.getComponent('structures.auth.Registration');
|
2015-11-30 18:11:04 +00:00
|
|
|
return (
|
|
|
|
<Registration
|
|
|
|
clientSecret={this.state.register_client_secret}
|
|
|
|
sessionId={this.state.register_session_id}
|
|
|
|
idSid={this.state.register_id_sid}
|
2016-08-11 10:00:15 +00:00
|
|
|
email={this.props.startingFragmentQueryParams.email}
|
2018-12-05 06:34:57 +00:00
|
|
|
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
|
2016-06-21 10:05:37 +00:00
|
|
|
defaultHsUrl={this.getDefaultHsUrl()}
|
|
|
|
defaultIsUrl={this.getDefaultIsUrl()}
|
2016-06-02 10:50:00 +00:00
|
|
|
brand={this.props.config.brand}
|
2016-03-15 13:48:46 +00:00
|
|
|
customHsUrl={this.getCurrentHsUrl()}
|
|
|
|
customIsUrl={this.getCurrentIsUrl()}
|
2017-03-02 14:47:47 +00:00
|
|
|
makeRegistrationUrl={this._makeRegistrationUrl}
|
2015-11-30 18:11:04 +00:00
|
|
|
onLoggedIn={this.onRegistered}
|
2016-03-06 19:33:36 +00:00
|
|
|
onLoginClick={this.onLoginClick}
|
2018-02-07 15:51:03 +00:00
|
|
|
onServerConfigChange={this.onServerConfigChange}
|
2016-03-15 21:04:11 +00:00
|
|
|
/>
|
2015-11-30 18:11:04 +00:00
|
|
|
);
|
2017-06-15 16:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (this.state.view === VIEWS.FORGOT_PASSWORD) {
|
2019-01-21 22:11:10 +00:00
|
|
|
const ForgotPassword = sdk.getComponent('structures.auth.ForgotPassword');
|
2016-01-12 17:20:16 +00:00
|
|
|
return (
|
|
|
|
<ForgotPassword
|
2018-12-05 06:34:57 +00:00
|
|
|
defaultServerName={this.getDefaultServerName()}
|
|
|
|
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
|
2016-06-21 10:05:37 +00:00
|
|
|
defaultHsUrl={this.getDefaultHsUrl()}
|
|
|
|
defaultIsUrl={this.getDefaultIsUrl()}
|
2016-03-15 13:48:46 +00:00
|
|
|
customHsUrl={this.getCurrentHsUrl()}
|
|
|
|
customIsUrl={this.getCurrentIsUrl()}
|
2016-03-06 19:33:36 +00:00
|
|
|
onComplete={this.onLoginClick}
|
|
|
|
onLoginClick={this.onLoginClick} />
|
2016-01-12 17:20:16 +00:00
|
|
|
);
|
2017-06-15 16:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this.state.view === VIEWS.LOGIN) {
|
2019-01-21 22:11:10 +00:00
|
|
|
const Login = sdk.getComponent('structures.auth.Login');
|
2017-03-29 15:23:18 +00:00
|
|
|
return (
|
2015-11-30 18:11:04 +00:00
|
|
|
<Login
|
2016-08-02 18:02:07 +00:00
|
|
|
onLoggedIn={Lifecycle.setLoggedIn}
|
2015-11-30 18:11:04 +00:00
|
|
|
onRegisterClick={this.onRegisterClick}
|
2018-12-05 06:34:57 +00:00
|
|
|
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
|
2016-06-21 10:05:37 +00:00
|
|
|
defaultHsUrl={this.getDefaultHsUrl()}
|
|
|
|
defaultIsUrl={this.getDefaultIsUrl()}
|
2016-03-15 13:48:46 +00:00
|
|
|
customHsUrl={this.getCurrentHsUrl()}
|
|
|
|
customIsUrl={this.getCurrentIsUrl()}
|
2016-05-27 13:57:43 +00:00
|
|
|
fallbackHsUrl={this.getFallbackHsUrl()}
|
2016-08-12 10:41:06 +00:00
|
|
|
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
2016-04-22 16:05:48 +00:00
|
|
|
onForgotPasswordClick={this.onForgotPasswordClick}
|
2016-08-11 12:05:16 +00:00
|
|
|
enableGuest={this.props.enableGuest}
|
2018-02-07 15:51:03 +00:00
|
|
|
onServerConfigChange={this.onServerConfigChange}
|
2016-09-01 10:08:40 +00:00
|
|
|
/>
|
2015-11-30 18:11:04 +00:00
|
|
|
);
|
|
|
|
}
|
2017-06-15 16:36:57 +00:00
|
|
|
|
2017-06-16 10:51:12 +00:00
|
|
|
console.error(`Unknown view ${this.state.view}`);
|
2017-05-19 12:53:11 +00:00
|
|
|
},
|
2015-11-30 18:11:04 +00:00
|
|
|
});
|