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
|
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
|
|
|
|
|
|
|
import q from 'q';
|
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
import React from 'react';
|
|
|
|
import Matrix from "matrix-js-sdk";
|
|
|
|
|
2017-05-27 19:47:09 +00:00
|
|
|
import Analytics from "../../Analytics";
|
2017-05-29 13:26:29 +00:00
|
|
|
import UserSettingsStore from '../../UserSettingsStore';
|
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';
|
|
|
|
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-05-24 15:56:13 +00:00
|
|
|
import LifecycleStore from '../../stores/LifecycleStore';
|
|
|
|
import RoomViewStore from '../../stores/RoomViewStore';
|
2017-05-19 12:53:11 +00:00
|
|
|
import PageTypes from '../../PageTypes';
|
|
|
|
|
|
|
|
import createRoom from "../../createRoom";
|
2017-03-01 14:33:25 +00:00
|
|
|
import * as UDEHandler from '../../UnknownDeviceErrorHandler';
|
2017-06-02 13:13:33 +00:00
|
|
|
import { _t, getCurrentLanguage } from '../../languageHandler';
|
2016-06-08 22:03:46 +00:00
|
|
|
|
2015-11-30 18:11:04 +00:00
|
|
|
module.exports = React.createClass({
|
|
|
|
displayName: 'MatrixChat',
|
|
|
|
|
|
|
|
propTypes: {
|
2016-06-08 17:45:46 +00:00
|
|
|
config: React.PropTypes.object,
|
2015-11-30 18:11:04 +00:00
|
|
|
ConferenceHandler: React.PropTypes.any,
|
|
|
|
onNewScreen: React.PropTypes.func,
|
2015-12-17 14:56:55 +00:00
|
|
|
registrationUrl: React.PropTypes.string,
|
2016-01-05 11:39:36 +00:00
|
|
|
enableGuest: React.PropTypes.bool,
|
2016-08-11 10:00:15 +00:00
|
|
|
|
|
|
|
// the queryParams extracted from the [real] query-string of the URI
|
|
|
|
realQueryParams: React.PropTypes.object,
|
|
|
|
|
|
|
|
// the initial queryParams extracted from the hash-fragment of the URI
|
|
|
|
startingFragmentQueryParams: React.PropTypes.object,
|
|
|
|
|
|
|
|
// called when the session load completes
|
|
|
|
onLoadCompleted: React.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
|
|
|
|
initialScreenAfterLogin: React.PropTypes.shape({
|
|
|
|
screen: React.PropTypes.string.isRequired,
|
|
|
|
params: React.PropTypes.object,
|
|
|
|
}),
|
|
|
|
|
2016-08-12 10:41:06 +00:00
|
|
|
// displayname, if any, to set on the device when logging
|
|
|
|
// in/registering.
|
|
|
|
defaultDeviceDisplayName: React.PropTypes.string,
|
2017-03-02 14:40:55 +00:00
|
|
|
|
|
|
|
// A function that makes a registration URL
|
|
|
|
makeRegistrationUrl: React.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: {
|
|
|
|
appConfig: React.PropTypes.object,
|
|
|
|
},
|
|
|
|
|
2015-09-18 17:39:16 +00:00
|
|
|
AuxPanel: {
|
|
|
|
RoomSettings: "room_settings",
|
|
|
|
},
|
|
|
|
|
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 = {
|
2016-08-09 23:03:29 +00:00
|
|
|
loading: true,
|
|
|
|
screen: undefined,
|
2017-03-08 10:25:54 +00:00
|
|
|
screenAfterLogin: this.props.initialScreenAfterLogin,
|
|
|
|
|
|
|
|
// Stashed guest credentials if the user logs out
|
|
|
|
// whilst logged in as a guest user (so they can change
|
|
|
|
// their mind & log back in)
|
|
|
|
guestCreds: null,
|
2016-08-09 23:03:29 +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,
|
|
|
|
|
2017-03-27 16:14:39 +00:00
|
|
|
loggedIn: false,
|
|
|
|
loggingIn: false,
|
2015-10-11 12:49:44 +00:00
|
|
|
collapse_lhs: false,
|
2015-10-11 15:07:01 +00:00
|
|
|
collapse_rhs: false,
|
2015-09-18 17:39:16 +00:00
|
|
|
ready: false,
|
2016-01-17 03:59:31 +00:00
|
|
|
width: 10000,
|
2017-05-18 23:20:32 +00:00
|
|
|
leftOpacity: 1.0,
|
2016-04-12 16:18:32 +00:00
|
|
|
middleOpacity: 1.0,
|
2017-05-18 23:20:32 +00:00
|
|
|
rightOpacity: 1.0,
|
2016-08-15 22:01:02 +00:00
|
|
|
|
|
|
|
version: null,
|
|
|
|
newVersion: null,
|
2016-11-02 15:58:17 +00:00
|
|
|
hasNewVersion: false,
|
|
|
|
newVersionReleaseNotes: null,
|
2016-09-29 16:23:07 +00:00
|
|
|
|
2016-09-30 10:37:50 +00:00
|
|
|
// The username to default to when upgrading an account from a guest
|
2016-09-29 16:23:07 +00:00
|
|
|
upgradeUsername: null,
|
2016-09-30 10:37:50 +00:00
|
|
|
// The access token we had for our guest account, used when upgrading to a normal account
|
2016-09-29 16:23:07 +00:00
|
|
|
guestAccessToken: null,
|
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,
|
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: {},
|
2016-08-11 10:00:15 +00:00
|
|
|
onLoadCompleted: () => {},
|
2015-12-17 14:56:55 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
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 if (window.localStorage && window.localStorage.getItem("mx_hs_url")) {
|
2016-03-06 19:33:36 +00:00
|
|
|
return window.localStorage.getItem("mx_hs_url");
|
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
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-06-21 10:05:37 +00:00
|
|
|
getDefaultHsUrl() {
|
|
|
|
return this.props.config.default_hs_url || "https://matrix.org";
|
|
|
|
},
|
|
|
|
|
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 if (window.localStorage && window.localStorage.getItem("mx_is_url")) {
|
2016-03-06 19:33:36 +00:00
|
|
|
return window.localStorage.getItem("mx_is_url");
|
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() {
|
|
|
|
return this.props.config.default_is_url || "https://vector.im";
|
|
|
|
},
|
|
|
|
|
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-05-24 15:56:13 +00:00
|
|
|
RoomViewStore.addListener(this._onRoomViewStoreUpdated);
|
|
|
|
this._onRoomViewStoreUpdated();
|
|
|
|
|
2017-05-29 13:26:29 +00:00
|
|
|
if (!UserSettingsStore.getLocalSetting('analyticsOptOut', false)) Analytics.enable();
|
|
|
|
|
2017-04-06 10:30:47 +00:00
|
|
|
// Used by _viewRoom before getting state from sync
|
|
|
|
this.firstSyncComplete = false;
|
|
|
|
this.firstSyncPromise = q.defer();
|
|
|
|
|
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
|
|
|
|
2017-02-10 15:09:45 +00:00
|
|
|
// To enable things like riot.im/geektime in a nicer way than rewriting the URL
|
|
|
|
// and appending a team token query parameter, use the first path segment to
|
|
|
|
// indicate a team, with "public" team tokens stored in the config teamTokenMap.
|
|
|
|
let routedTeamToken = null;
|
|
|
|
if (this.props.config.teamTokenMap) {
|
|
|
|
const teamName = window.location.pathname.split('/')[1];
|
2017-02-13 11:48:03 +00:00
|
|
|
if (teamName && this.props.config.teamTokenMap.hasOwnProperty(teamName)) {
|
2017-02-10 15:09:45 +00:00
|
|
|
routedTeamToken = this.props.config.teamTokenMap[teamName];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 11:39:22 +00:00
|
|
|
// Persist the team token across refreshes using sessionStorage. A new window or
|
|
|
|
// tab will not persist sessionStorage, but refreshes will.
|
2017-02-10 11:31:04 +00:00
|
|
|
if (this.props.startingFragmentQueryParams.team_token) {
|
|
|
|
window.sessionStorage.setItem(
|
|
|
|
'mx_team_token',
|
|
|
|
this.props.startingFragmentQueryParams.team_token,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-02-03 11:48:24 +00:00
|
|
|
// Use the locally-stored team token first, then as a fall-back, check to see if
|
|
|
|
// a referral link was used, which will contain a query parameter `team_token`.
|
2017-02-10 15:09:45 +00:00
|
|
|
this._teamToken = routedTeamToken ||
|
|
|
|
window.localStorage.getItem('mx_team_token') ||
|
2017-02-10 11:31:04 +00:00
|
|
|
window.sessionStorage.getItem('mx_team_token');
|
2017-02-10 15:09:45 +00:00
|
|
|
|
2017-02-14 12:56:29 +00:00
|
|
|
// Some users have ended up with "undefined" as their local storage team token,
|
|
|
|
// treat that as undefined.
|
|
|
|
if (this._teamToken === "undefined") {
|
|
|
|
this._teamToken = undefined;
|
|
|
|
}
|
|
|
|
|
2017-02-10 15:09:45 +00:00
|
|
|
if (this._teamToken) {
|
|
|
|
console.info(`Team token set to ${this._teamToken}`);
|
|
|
|
}
|
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,
|
|
|
|
});
|
|
|
|
}
|
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);
|
2017-02-22 16:42:14 +00:00
|
|
|
UDEHandler.startListening();
|
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;
|
|
|
|
}
|
2015-11-30 18:11:04 +00:00
|
|
|
|
|
|
|
window.addEventListener('resize', this.handleResize);
|
|
|
|
this.handleResize();
|
2016-08-10 10:33:58 +00:00
|
|
|
|
2017-02-07 15:24:57 +00:00
|
|
|
if (this.props.config.teamServerConfig &&
|
|
|
|
this.props.config.teamServerConfig.teamServerURL
|
|
|
|
) {
|
|
|
|
Lifecycle.initRtsClient(this.props.config.teamServerConfig.teamServerURL);
|
|
|
|
}
|
2017-02-03 14:34:24 +00:00
|
|
|
|
2016-09-01 21:45:09 +00:00
|
|
|
// the extra q() ensures that synchronous exceptions hit the same codepath as
|
|
|
|
// asynchronous ones.
|
2016-09-01 10:08:40 +00:00
|
|
|
q().then(() => {
|
|
|
|
return Lifecycle.loadSession({
|
|
|
|
realQueryParams: this.props.realQueryParams,
|
|
|
|
fragmentQueryParams: this.props.startingFragmentQueryParams,
|
|
|
|
enableGuest: this.props.enableGuest,
|
|
|
|
guestHsUrl: this.getCurrentHsUrl(),
|
|
|
|
guestIsUrl: this.getCurrentIsUrl(),
|
|
|
|
defaultDeviceDisplayName: this.props.defaultDeviceDisplayName,
|
|
|
|
});
|
|
|
|
}).catch((e) => {
|
|
|
|
console.error("Unable to load session", e);
|
2016-08-10 10:33:58 +00:00
|
|
|
}).done(()=>{
|
|
|
|
// stuff this through the dispatcher so that it happens
|
|
|
|
// after the on_logged_in action.
|
|
|
|
dis.dispatch({action: 'load_completed'});
|
|
|
|
});
|
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);
|
2017-02-22 16:42:14 +00:00
|
|
|
UDEHandler.stopListening();
|
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
|
|
|
},
|
|
|
|
|
2015-06-18 14:03:57 +00:00
|
|
|
componentDidUpdate: function() {
|
|
|
|
if (this.focusComposer) {
|
|
|
|
dis.dispatch({action: 'focus_composer'});
|
|
|
|
this.focusComposer = false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-09-30 10:56:32 +00:00
|
|
|
setStateForNewScreen: function(state) {
|
|
|
|
const newState = {
|
|
|
|
screen: undefined,
|
|
|
|
viewUserId: null,
|
2017-03-27 16:14:39 +00:00
|
|
|
loggedIn: false,
|
2016-09-30 10:56:32 +00:00
|
|
|
ready: false,
|
|
|
|
upgradeUsername: null,
|
|
|
|
guestAccessToken: null,
|
|
|
|
};
|
2016-10-01 09:34:21 +00:00
|
|
|
Object.assign(newState, state);
|
2016-09-30 13:05:01 +00:00
|
|
|
this.setState(newState);
|
2016-09-30 10:56:32 +00:00
|
|
|
},
|
|
|
|
|
2015-06-12 16:34:17 +00:00
|
|
|
onAction: function(payload) {
|
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
|
|
|
|
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;
|
2015-07-13 18:14:02 +00:00
|
|
|
case 'start_registration':
|
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-03-14 15:13:36 +00:00
|
|
|
if (MatrixClientPeg.get() &&
|
|
|
|
MatrixClientPeg.get().isGuest()
|
|
|
|
) {
|
2017-03-08 10:25:54 +00:00
|
|
|
this.setState({
|
|
|
|
guestCreds: MatrixClientPeg.getCredentials(),
|
|
|
|
});
|
|
|
|
}
|
2016-09-30 10:56:32 +00:00
|
|
|
this.setStateForNewScreen({
|
2016-03-17 02:09:49 +00:00
|
|
|
screen: '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-03-27 16:14:39 +00:00
|
|
|
this.setState({ // don't clobber loggedIn status
|
2017-05-19 12:53:11 +00:00
|
|
|
screen: 'post_registration',
|
2015-11-20 11:57:04 +00:00
|
|
|
});
|
|
|
|
break;
|
2016-01-07 17:23:32 +00:00
|
|
|
case 'start_upgrade_registration':
|
2017-02-27 18:22:26 +00:00
|
|
|
// also stash our credentials, then if we restore the session,
|
|
|
|
// we can just do it the same way whether we started upgrade
|
|
|
|
// registration or explicitly logged out
|
2016-09-30 10:56:32 +00:00
|
|
|
this.setStateForNewScreen({
|
2017-03-08 10:25:54 +00:00
|
|
|
guestCreds: MatrixClientPeg.getCredentials(),
|
2016-01-07 17:23:32 +00:00
|
|
|
screen: "register",
|
|
|
|
upgradeUsername: MatrixClientPeg.get().getUserIdLocalpart(),
|
2016-03-15 21:04:11 +00:00
|
|
|
guestAccessToken: MatrixClientPeg.get().getAccessToken(),
|
2016-01-07 17:23:32 +00:00
|
|
|
});
|
2017-02-27 18:22:26 +00:00
|
|
|
|
|
|
|
// stop the client: if we are syncing whilst the registration
|
|
|
|
// is completed in another browser, we'll be 401ed for using
|
|
|
|
// a guest access token for a non-guest account.
|
2017-03-02 14:39:25 +00:00
|
|
|
// It will be restarted in onReturnToGuestClick
|
2017-02-27 18:22:26 +00:00
|
|
|
Lifecycle.stopMatrixClient();
|
|
|
|
|
2016-01-07 17:23:32 +00:00
|
|
|
this.notifyNewScreen('register');
|
|
|
|
break;
|
2016-01-12 17:20:16 +00:00
|
|
|
case 'start_password_recovery':
|
2016-09-30 10:56:32 +00:00
|
|
|
this.setStateForNewScreen({
|
2016-09-29 16:23:07 +00:00
|
|
|
screen: '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,
|
|
|
|
});
|
|
|
|
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':
|
|
|
|
Modal.createDialog(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();
|
|
|
|
if (this.currentRoomId === payload.room_id) {
|
|
|
|
dis.dispatch({action: 'view_next_room'});
|
|
|
|
}
|
|
|
|
}, (err) => {
|
|
|
|
modal.close();
|
|
|
|
Modal.createDialog(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.
|
|
|
|
if (this.state.collapse_rhs) {
|
|
|
|
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;
|
|
|
|
case 'view_user_settings':
|
2017-05-26 12:18:44 +00:00
|
|
|
if (MatrixClientPeg.get().isGuest()) {
|
2017-06-05 12:41:52 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'do_after_sync_prepared',
|
|
|
|
deferred_action: {
|
|
|
|
action: 'view_user_settings',
|
|
|
|
},
|
|
|
|
});
|
2017-05-26 12:18:44 +00:00
|
|
|
dis.dispatch({action: 'view_set_mxid'});
|
|
|
|
break;
|
|
|
|
}
|
2016-11-03 18:42:26 +00:00
|
|
|
this._setPage(PageTypes.UserSettings);
|
2015-11-11 01:01:48 +00:00
|
|
|
this.notifyNewScreen('settings');
|
2015-09-18 17:39:16 +00:00
|
|
|
break;
|
|
|
|
case 'view_create_room':
|
2017-06-05 16:45:01 +00:00
|
|
|
this._createRoom();
|
2015-09-18 17:39:16 +00:00
|
|
|
break;
|
|
|
|
case 'view_room_directory':
|
2016-11-03 18:42:26 +00:00
|
|
|
this._setPage(PageTypes.RoomDirectory);
|
2015-11-11 01:01:48 +00:00
|
|
|
this.notifyNewScreen('directory');
|
2015-09-18 17:39:16 +00:00
|
|
|
break;
|
2016-11-13 14:10:46 +00:00
|
|
|
case 'view_home_page':
|
|
|
|
this._setPage(PageTypes.HomePage);
|
|
|
|
this.notifyNewScreen('home');
|
|
|
|
break;
|
2017-05-11 16:04:11 +00:00
|
|
|
case 'view_set_mxid':
|
|
|
|
this._setMxId();
|
|
|
|
break;
|
2017-06-01 13:16:25 +00:00
|
|
|
case 'view_start_chat_or_reuse':
|
|
|
|
this._chatCreateOrReuse(payload.user_id);
|
|
|
|
break;
|
2016-09-05 09:29:03 +00:00
|
|
|
case 'view_create_chat':
|
|
|
|
this._createChat();
|
2016-09-01 15:45:24 +00:00
|
|
|
break;
|
2016-09-13 13:28:03 +00:00
|
|
|
case 'view_invite':
|
|
|
|
this._invite(payload.roomId);
|
|
|
|
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({
|
|
|
|
collapse_lhs: true,
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'show_left_panel':
|
|
|
|
this.setState({
|
|
|
|
collapse_lhs: false,
|
|
|
|
});
|
|
|
|
break;
|
2015-10-11 15:07:01 +00:00
|
|
|
case 'hide_right_panel':
|
|
|
|
this.setState({
|
|
|
|
collapse_rhs: true,
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'show_right_panel':
|
|
|
|
this.setState({
|
|
|
|
collapse_rhs: false,
|
|
|
|
});
|
|
|
|
break;
|
2017-05-18 23:20:32 +00:00
|
|
|
case 'ui_opacity': {
|
|
|
|
const sideDefault = payload.sideOpacity >= 0.0 ? payload.sideOpacity : 1.0;
|
2016-04-12 16:18:32 +00:00
|
|
|
this.setState({
|
2017-05-18 23:20:32 +00:00
|
|
|
leftOpacity: payload.leftOpacity >= 0.0 ? payload.leftOpacity : sideDefault,
|
|
|
|
middleOpacity: payload.middleOpacity || 1.0,
|
|
|
|
rightOpacity: payload.rightOpacity >= 0.0 ? payload.rightOpacity : sideDefault,
|
2016-04-12 16:18:32 +00:00
|
|
|
});
|
2017-05-18 23:20:32 +00:00
|
|
|
break; }
|
2017-01-17 19:13:23 +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
|
|
|
|
// and also that we're not ready (we'll be marked as logged
|
|
|
|
// in once the login completes, then ready once the sync
|
|
|
|
// completes).
|
2017-06-05 15:17:32 +00:00
|
|
|
this.setState({loggingIn: true, ready: false});
|
2017-03-27 15:39:04 +00:00
|
|
|
break;
|
2016-08-02 13:04:20 +00:00
|
|
|
case 'on_logged_in':
|
2017-05-12 16:39:38 +00:00
|
|
|
this._onLoggedIn(payload.teamToken);
|
2016-08-02 13:04:20 +00:00
|
|
|
break;
|
|
|
|
case 'on_logged_out':
|
|
|
|
this._onLoggedOut();
|
|
|
|
break;
|
|
|
|
case 'will_start_client':
|
|
|
|
this._onWillStartClient();
|
|
|
|
break;
|
2016-08-09 23:03:29 +00:00
|
|
|
case 'load_completed':
|
|
|
|
this._onLoadCompleted();
|
|
|
|
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;
|
2015-06-12 16:34:17 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-05-24 15:56:13 +00:00
|
|
|
_onRoomViewStoreUpdated: function() {
|
|
|
|
this.setState({ currentRoomId: RoomViewStore.getRoomId() });
|
|
|
|
},
|
|
|
|
|
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) {
|
|
|
|
this.setStateForNewScreen({
|
|
|
|
screen: 'register',
|
|
|
|
// these params may be undefined, but if they are,
|
|
|
|
// unset them from our state: we don't want to
|
|
|
|
// resume a previous registration session if the
|
|
|
|
// user just clicked 'register'
|
|
|
|
register_client_secret: params.client_secret,
|
|
|
|
register_session_id: params.session_id,
|
|
|
|
register_hs_url: params.hs_url,
|
|
|
|
register_is_url: params.is_url,
|
|
|
|
register_id_sid: params.sid,
|
|
|
|
});
|
|
|
|
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(),
|
|
|
|
);
|
|
|
|
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 {boolean=} roomInfo.show_settings Makes RoomView show the room settings dialog.
|
|
|
|
// @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 = {
|
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,
|
|
|
|
autoJoin: roomInfo.auto_join,
|
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-06-14 11:56:37 +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.
|
|
|
|
let waitFor = q(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
|
|
|
},
|
|
|
|
|
2017-05-11 16:04:11 +00:00
|
|
|
_setMxId: function() {
|
|
|
|
const SetMxIdDialog = sdk.getComponent('views.dialogs.SetMxIdDialog');
|
|
|
|
const close = Modal.createDialog(SetMxIdDialog, {
|
|
|
|
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-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;
|
|
|
|
},
|
|
|
|
|
2016-09-05 09:29:03 +00:00
|
|
|
_createChat: function() {
|
2017-05-11 16:04:11 +00:00
|
|
|
if (MatrixClientPeg.get().isGuest()) {
|
2017-06-05 12:41:52 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'do_after_sync_prepared',
|
|
|
|
deferred_action: {
|
|
|
|
action: 'view_create_chat',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
dis.dispatch({action: 'view_set_mxid'});
|
2017-05-11 16:04:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const ChatInviteDialog = sdk.getComponent("dialogs.ChatInviteDialog");
|
2016-09-05 11:03:16 +00:00
|
|
|
Modal.createDialog(ChatInviteDialog, {
|
2017-05-23 14:16:31 +00:00
|
|
|
title: _t('Start a chat'),
|
|
|
|
description: _t("Who would you like to communicate with?"),
|
|
|
|
placeholder: _t("Email, name or matrix ID"),
|
2017-05-31 14:09:09 +00:00
|
|
|
button: _t("Start Chat"),
|
2016-09-01 15:45:24 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-06-05 16:45:01 +00:00
|
|
|
_createRoom: function() {
|
|
|
|
if (MatrixClientPeg.get().isGuest()) {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'do_after_sync_prepared',
|
|
|
|
deferred_action: {
|
|
|
|
action: 'view_create_room',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
dis.dispatch({action: 'view_set_mxid'});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const TextInputDialog = sdk.getComponent("dialogs.TextInputDialog");
|
|
|
|
Modal.createDialog(TextInputDialog, {
|
|
|
|
title: _t('Create Room'),
|
|
|
|
description: _t('Room name (optional)'),
|
|
|
|
button: _t('Create Room'),
|
|
|
|
onFinished: (should_create, name) => {
|
|
|
|
if (should_create) {
|
|
|
|
const createOpts = {};
|
|
|
|
if (name) createOpts.name = name;
|
|
|
|
createRoom({createOpts}).done();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-06-01 13:16:25 +00:00
|
|
|
_chatCreateOrReuse: function(userId) {
|
|
|
|
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({
|
|
|
|
action: 'view_set_mxid',
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const close = Modal.createDialog(ChatCreateOrReuseDialog, {
|
|
|
|
userId: userId,
|
|
|
|
onFinished: (success) => {
|
|
|
|
if (!success) {
|
|
|
|
// 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;
|
|
|
|
},
|
|
|
|
|
2016-09-13 13:30:37 +00:00
|
|
|
_invite: function(roomId) {
|
2017-05-19 12:53:11 +00:00
|
|
|
const ChatInviteDialog = sdk.getComponent("dialogs.ChatInviteDialog");
|
2016-09-13 13:28:03 +00:00
|
|
|
Modal.createDialog(ChatInviteDialog, {
|
2017-05-23 14:16:31 +00:00
|
|
|
title: _t('Invite new room members'),
|
|
|
|
description: _t('Who would you like to add to this room?'),
|
|
|
|
button: _t('Send Invites'),
|
|
|
|
placeholder: _t("Email, name or matrix ID"),
|
2016-09-13 13:30:37 +00:00
|
|
|
roomId: roomId,
|
2016-09-01 15:45:24 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
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);
|
|
|
|
Modal.createDialog(QuestionDialog, {
|
2017-06-02 09:47:08 +00:00
|
|
|
title: _t("Leave room"),
|
|
|
|
description: (
|
|
|
|
<span>
|
2017-06-02 10:16:08 +00:00
|
|
|
{_t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name})}
|
2017-06-02 09:47:08 +00:00
|
|
|
</span>
|
|
|
|
),
|
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);
|
|
|
|
Modal.createDialog(ErrorDialog, {
|
2017-05-30 14:09:57 +00:00
|
|
|
title: _t("Failed to leave room"),
|
2017-05-19 12:53:11 +00:00
|
|
|
description: (err && err.message ? err.message :
|
2017-05-30 14:09:57 +00:00
|
|
|
_t("Server may be unavailable, overloaded, or you hit a bug.")),
|
2017-05-19 12:53:11 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2016-08-09 23:03:29 +00:00
|
|
|
/**
|
|
|
|
* Called when the sessionloader has finished
|
|
|
|
*/
|
|
|
|
_onLoadCompleted: function() {
|
2016-08-11 10:00:15 +00:00
|
|
|
this.props.onLoadCompleted();
|
2016-08-09 23:03:29 +00:00
|
|
|
this.setState({loading: false});
|
2017-03-15 12:02:08 +00:00
|
|
|
|
2017-04-06 10:30:47 +00:00
|
|
|
// Show screens (like 'register') that need to be shown without _onLoggedIn
|
2017-03-15 12:02:08 +00:00
|
|
|
// being called. 'register' needs to be routed here when the email confirmation
|
|
|
|
// link is clicked on.
|
2017-03-15 13:05:03 +00:00
|
|
|
if (this.state.screenAfterLogin &&
|
|
|
|
['register'].indexOf(this.state.screenAfterLogin.screen) !== -1) {
|
2017-03-15 12:02:08 +00:00
|
|
|
this._showScreenAfterLogin();
|
|
|
|
}
|
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) {
|
|
|
|
theme = 'light';
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
Object.values(styleElements).forEach((a) => {
|
|
|
|
a.disabled = true;
|
|
|
|
});
|
|
|
|
styleElements[theme].disabled = false;
|
|
|
|
|
2017-01-17 19:13:23 +00:00
|
|
|
if (theme === 'dark') {
|
|
|
|
// abuse the tinter to change all the SVG's #fff to #2d2d2d
|
|
|
|
// XXX: obviously this shouldn't be hardcoded here.
|
2017-01-18 14:06:47 +00:00
|
|
|
Tinter.tintSvgWhite('#2d2d2d');
|
2017-05-19 12:53:11 +00:00
|
|
|
} else {
|
2017-01-18 14:06:47 +00:00
|
|
|
Tinter.tintSvgWhite('#ffffff');
|
2017-01-17 19:13:23 +00:00
|
|
|
}
|
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
|
2017-05-19 12:53:11 +00:00
|
|
|
*
|
|
|
|
* @param {string} teamToken
|
2016-08-02 18:05:05 +00:00
|
|
|
*/
|
2017-05-12 11:02:45 +00:00
|
|
|
_onLoggedIn: function(teamToken) {
|
2015-07-13 18:14:02 +00:00
|
|
|
this.setState({
|
2017-03-08 10:25:54 +00:00
|
|
|
guestCreds: null,
|
2017-03-27 16:14:39 +00:00
|
|
|
loggedIn: true,
|
2017-03-27 15:39:04 +00:00
|
|
|
loggingIn: false,
|
2015-07-13 18:14:02 +00:00
|
|
|
});
|
2017-02-28 15:05:49 +00:00
|
|
|
|
2017-03-15 12:02:08 +00:00
|
|
|
if (teamToken) {
|
2017-04-06 16:10:32 +00:00
|
|
|
// A team member has logged in, not a guest
|
2017-03-15 12:02:08 +00:00
|
|
|
this._teamToken = teamToken;
|
|
|
|
dis.dispatch({action: 'view_home_page'});
|
|
|
|
} else if (this._is_registered) {
|
2017-05-24 15:56:13 +00:00
|
|
|
this._is_registered = false;
|
2017-06-06 10:43:07 +00:00
|
|
|
// reset the 'have completed first sync' flag,
|
|
|
|
// since we've just logged in and will be about to sync
|
2017-06-06 10:36:33 +00:00
|
|
|
this.firstSyncComplete = false;
|
|
|
|
this.firstSyncPromise = q.defer();
|
2017-05-26 10:46:33 +00:00
|
|
|
|
2017-05-26 10:47:55 +00:00
|
|
|
// Set the display name = user ID localpart
|
2017-05-26 10:46:33 +00:00
|
|
|
MatrixClientPeg.get().setDisplayName(
|
2017-06-05 13:07:24 +00:00
|
|
|
MatrixClientPeg.get().getUserIdLocalpart(),
|
2017-05-26 10:46:33 +00:00
|
|
|
);
|
|
|
|
|
2017-06-02 13:13:33 +00:00
|
|
|
if (this.props.config.welcomeUserId && getCurrentLanguage().startsWith("en")) {
|
2017-05-24 15:56:13 +00:00
|
|
|
createRoom({
|
|
|
|
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
|
|
|
});
|
2017-05-12 16:39:38 +00:00
|
|
|
return;
|
|
|
|
}
|
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-03-08 10:45:07 +00:00
|
|
|
if (this.state.screenAfterLogin && this.state.screenAfterLogin.screen) {
|
2017-03-08 10:25:54 +00:00
|
|
|
this.showScreen(
|
|
|
|
this.state.screenAfterLogin.screen,
|
2017-05-19 12:53:11 +00:00
|
|
|
this.state.screenAfterLogin.params,
|
2017-03-08 10:25:54 +00:00
|
|
|
);
|
2017-03-15 12:02:08 +00:00
|
|
|
this.notifyNewScreen(this.state.screenAfterLogin.screen);
|
2017-03-08 10:25:54 +00:00
|
|
|
this.setState({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 {
|
2017-05-24 16:55:36 +00:00
|
|
|
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');
|
2016-09-30 10:56:32 +00:00
|
|
|
this.setStateForNewScreen({
|
2017-03-27 16:14:39 +00:00
|
|
|
loggedIn: false,
|
2016-08-02 13:04:20 +00:00
|
|
|
ready: false,
|
2016-09-29 16:23:07 +00:00
|
|
|
collapse_lhs: false,
|
|
|
|
collapse_rhs: false,
|
2016-11-24 14:58:37 +00:00
|
|
|
currentRoomId: null,
|
|
|
|
page_type: PageTypes.RoomDirectory,
|
2016-08-02 13:04:20 +00:00
|
|
|
});
|
2017-02-28 15:05:49 +00:00
|
|
|
this._teamToken = null;
|
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;
|
|
|
|
const cli = MatrixClientPeg.get();
|
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.
|
|
|
|
if (!self.refs.loggedInView) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return self.refs.loggedInView.canResetTimelineInRoom(roomId);
|
|
|
|
});
|
|
|
|
|
2015-12-15 14:23:58 +00:00
|
|
|
cli.on('sync', function(state, prevState) {
|
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});
|
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) {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'incoming_call',
|
2017-05-19 12:53:11 +00:00
|
|
|
call: call,
|
2015-09-18 17:39:16 +00:00
|
|
|
});
|
|
|
|
});
|
2016-03-15 10:48:16 +00:00
|
|
|
cli.on('Session.logged_out', function(call) {
|
2017-05-19 12:53:11 +00:00
|
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
2016-03-15 10:48:16 +00:00
|
|
|
Modal.createDialog(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
|
|
|
});
|
|
|
|
});
|
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-11 17:25:29 +00:00
|
|
|
},
|
2015-06-25 16:41:55 +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',
|
|
|
|
});
|
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({
|
|
|
|
action: 'view_set_mxid',
|
|
|
|
});
|
2015-11-11 01:01:48 +00:00
|
|
|
} else if (screen == 'directory') {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_room_directory',
|
|
|
|
});
|
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,
|
|
|
|
};
|
|
|
|
|
2017-05-19 12:53:11 +00:00
|
|
|
const payload = {
|
2016-06-10 14:12:42 +00:00
|
|
|
action: 'view_room',
|
|
|
|
event_id: eventId,
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// we can't view a room unless we're logged in
|
|
|
|
// (a guest account is fine)
|
2017-03-29 14:02:28 +00:00
|
|
|
if (this.state.loggedIn) {
|
2016-06-09 17:49:06 +00:00
|
|
|
dis.dispatch(payload);
|
2015-09-25 16:22:42 +00:00
|
|
|
}
|
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
|
|
|
|
|
|
|
if (params.action === 'chat') {
|
|
|
|
this._chatCreateOrReuse(userId);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-28 13:04:02 +00:00
|
|
|
this.setState({ viewUserId: userId });
|
2016-11-03 18:42:26 +00:00
|
|
|
this._setPage(PageTypes.UserView);
|
2016-08-28 13:04:02 +00:00
|
|
|
this.notifyNewScreen('user/' + userId);
|
2017-05-19 12:53:11 +00:00
|
|
|
const member = new Matrix.RoomMember(null, userId);
|
2016-08-28 00:55:42 +00:00
|
|
|
if (member) {
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_user',
|
|
|
|
member: member,
|
|
|
|
});
|
|
|
|
}
|
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
|
|
|
}
|
2017-05-27 19:47:09 +00:00
|
|
|
Analytics.trackPageChange();
|
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
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
if (this.state.width > hideLhsThreshold && window.innerWidth <= hideLhsThreshold) {
|
|
|
|
dis.dispatch({ action: 'hide_left_panel' });
|
|
|
|
}
|
|
|
|
if (this.state.width <= showLhsThreshold && window.innerWidth > showLhsThreshold) {
|
|
|
|
dis.dispatch({ action: 'show_left_panel' });
|
|
|
|
}
|
|
|
|
if (this.state.width > hideRhsThreshold && window.innerWidth <= hideRhsThreshold) {
|
|
|
|
dis.dispatch({ action: 'hide_right_panel' });
|
|
|
|
}
|
|
|
|
if (this.state.width <= showRhsThreshold && window.innerWidth > showRhsThreshold) {
|
|
|
|
dis.dispatch({ action: 'show_right_panel' });
|
|
|
|
}
|
|
|
|
|
|
|
|
this.setState({width: window.innerWidth});
|
|
|
|
},
|
|
|
|
|
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");
|
|
|
|
},
|
|
|
|
|
2016-03-15 21:04:11 +00:00
|
|
|
onReturnToGuestClick: function() {
|
|
|
|
// reanimate our guest login
|
2017-03-08 10:25:54 +00:00
|
|
|
if (this.state.guestCreds) {
|
|
|
|
Lifecycle.setLoggedIn(this.state.guestCreds);
|
|
|
|
this.setState({guestCreds: null});
|
2016-08-02 13:04:20 +00:00
|
|
|
}
|
2016-03-15 21:04:11 +00:00
|
|
|
},
|
|
|
|
|
2017-02-28 15:05:49 +00:00
|
|
|
onRegistered: function(credentials, teamToken) {
|
2017-05-24 15:56:13 +00:00
|
|
|
// XXX: These both should be in state or ideally store(s) because we risk not
|
|
|
|
// rendering the most up-to-date view of state otherwise.
|
2017-02-28 15:05:49 +00:00
|
|
|
// teamToken may not be truthy
|
|
|
|
this._teamToken = teamToken;
|
|
|
|
this._is_registered = true;
|
2016-08-02 18:02:07 +00:00
|
|
|
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-05-19 12:53:11 +00:00
|
|
|
screen: undefined,
|
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,
|
2016-02-03 16:16:52 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
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-07 10:40:46 +00:00
|
|
|
let title = "Riot ";
|
|
|
|
if (state === "ERROR") {
|
|
|
|
title += `[${_t("Offline")}] `;
|
|
|
|
}
|
|
|
|
if (notifCount > 0) {
|
|
|
|
title += `[${notifCount}]`;
|
|
|
|
}
|
|
|
|
|
|
|
|
document.title = title;
|
2015-12-21 12:55:13 +00:00
|
|
|
},
|
|
|
|
|
2015-12-23 11:47:56 +00:00
|
|
|
onUserSettingsClose: function() {
|
|
|
|
// XXX: use browser history instead to find the previous room?
|
2016-04-15 21:16:19 +00:00
|
|
|
// or maintain a this.state.pageHistory in _setPage()?
|
2016-06-14 10:37:04 +00:00
|
|
|
if (this.state.currentRoomId) {
|
2015-12-23 11:47:56 +00:00
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_room',
|
2016-06-14 10:37:04 +00:00
|
|
|
room_id: this.state.currentRoomId,
|
2015-12-23 11:47:56 +00:00
|
|
|
});
|
2017-05-19 12:53:11 +00:00
|
|
|
} else {
|
2015-12-23 11:47:56 +00:00
|
|
|
dis.dispatch({
|
2016-05-05 14:30:56 +00:00
|
|
|
action: 'view_room_directory',
|
2015-12-23 11:47:56 +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);
|
|
|
|
},
|
|
|
|
|
2015-11-30 18:11:04 +00:00
|
|
|
render: function() {
|
2017-03-27 16:14:39 +00:00
|
|
|
// `loading` might be set to false before `loggedIn = true`, causing the default
|
2017-03-27 15:39:04 +00:00
|
|
|
// (`<Login>`) to be visible for a few MS (say, whilst a request is in-flight to
|
|
|
|
// the RTS). So in the meantime, use `loggingIn`, which is true between
|
|
|
|
// actions `on_logging_in` and `on_logged_in`.
|
|
|
|
if (this.state.loading || this.state.loggingIn) {
|
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-05-19 12:53:11 +00:00
|
|
|
if (this.state.screen == 'post_registration') {
|
2017-03-29 14:24:47 +00:00
|
|
|
const PostRegistration = sdk.getComponent('structures.login.PostRegistration');
|
2015-11-30 18:11:04 +00:00
|
|
|
return (
|
|
|
|
<PostRegistration
|
|
|
|
onComplete={this.onFinishPostRegistration} />
|
|
|
|
);
|
2017-05-17 17:49:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// `ready` and `loggedIn` 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.
|
|
|
|
if (this.state.loggedIn && this.state.ready && this.state.page_type) {
|
2016-11-03 18:42:26 +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.
|
|
|
|
*/
|
2017-03-29 14:24:47 +00:00
|
|
|
const LoggedInView = sdk.getComponent('structures.LoggedInView');
|
2016-02-08 17:20:52 +00:00
|
|
|
return (
|
2016-11-03 18:42:26 +00:00
|
|
|
<LoggedInView ref="loggedInView" matrixClient={MatrixClientPeg.get()}
|
|
|
|
onRoomCreated={this.onRoomCreated}
|
|
|
|
onUserSettingsClose={this.onUserSettingsClose}
|
2017-04-28 12:22:55 +00:00
|
|
|
onRegistered={this.onRegistered}
|
2017-05-24 15:56:13 +00:00
|
|
|
currentRoomId={this.state.currentRoomId}
|
2017-02-03 11:48:24 +00:00
|
|
|
teamToken={this._teamToken}
|
2016-11-03 18:42:26 +00:00
|
|
|
{...this.props}
|
|
|
|
{...this.state}
|
|
|
|
/>
|
2017-01-20 14:22:27 +00:00
|
|
|
);
|
2017-03-27 16:14:39 +00:00
|
|
|
} else if (this.state.loggedIn) {
|
2016-08-09 23:03:29 +00:00
|
|
|
// we think we are logged in, but are still waiting for the /sync to complete
|
2017-03-29 14:24:47 +00:00
|
|
|
const Spinner = sdk.getComponent('elements.Spinner');
|
2015-11-30 18:11:04 +00:00
|
|
|
return (
|
|
|
|
<div className="mx_MatrixChat_splash">
|
|
|
|
<Spinner />
|
2016-08-09 23:03:29 +00:00
|
|
|
<a href="#" className="mx_MatrixChat_splashButtons" onClick={ this.onLogoutClick }>
|
2017-05-23 14:16:31 +00:00
|
|
|
{ _t('Logout') }
|
2016-08-09 23:03:29 +00:00
|
|
|
</a>
|
2015-11-30 18:11:04 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
} else if (this.state.screen == 'register') {
|
2017-03-29 14:24:47 +00:00
|
|
|
const Registration = sdk.getComponent('structures.login.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}
|
2017-01-31 11:13:05 +00:00
|
|
|
referrer={this.props.startingFragmentQueryParams.referrer}
|
2016-01-07 17:23:32 +00:00
|
|
|
username={this.state.upgradeUsername}
|
|
|
|
guestAccessToken={this.state.guestAccessToken}
|
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}
|
2017-01-30 15:50:31 +00:00
|
|
|
teamServerConfig={this.props.config.teamServerConfig}
|
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}
|
2016-08-12 10:41:06 +00:00
|
|
|
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
2015-11-30 18:11:04 +00:00
|
|
|
onLoggedIn={this.onRegistered}
|
2016-03-06 19:33:36 +00:00
|
|
|
onLoginClick={this.onLoginClick}
|
2016-03-15 21:04:11 +00:00
|
|
|
onRegisterClick={this.onRegisterClick}
|
2017-03-08 10:25:54 +00:00
|
|
|
onCancelClick={this.state.guestCreds ? this.onReturnToGuestClick : null}
|
2016-03-15 21:04:11 +00:00
|
|
|
/>
|
2015-11-30 18:11:04 +00:00
|
|
|
);
|
2016-01-12 17:20:16 +00:00
|
|
|
} else if (this.state.screen == 'forgot_password') {
|
2017-03-29 14:24:47 +00:00
|
|
|
const ForgotPassword = sdk.getComponent('structures.login.ForgotPassword');
|
2016-01-12 17:20:16 +00:00
|
|
|
return (
|
|
|
|
<ForgotPassword
|
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}
|
2017-01-10 15:16:39 +00:00
|
|
|
onRegisterClick={this.onRegisterClick}
|
2016-03-06 19:33:36 +00:00
|
|
|
onLoginClick={this.onLoginClick} />
|
2016-01-12 17:20:16 +00:00
|
|
|
);
|
2015-11-30 18:11:04 +00:00
|
|
|
} else {
|
2017-03-29 14:24:47 +00:00
|
|
|
const Login = sdk.getComponent('structures.login.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}
|
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}
|
2017-03-08 10:25:54 +00:00
|
|
|
onCancelClick={this.state.guestCreds ? this.onReturnToGuestClick : null}
|
2016-09-01 10:08:40 +00:00
|
|
|
/>
|
2015-11-30 18:11:04 +00:00
|
|
|
);
|
|
|
|
}
|
2017-05-19 12:53:11 +00:00
|
|
|
},
|
2015-11-30 18:11:04 +00:00
|
|
|
});
|