2015-06-23 16:41:25 +01:00
|
|
|
|
/*
|
2024-09-09 14:57:16 +01:00
|
|
|
|
Copyright 2024 New Vector Ltd.
|
2024-01-04 18:12:08 +00:00
|
|
|
|
Copyright 2015-2024 The Matrix.org Foundation C.I.C.
|
2015-06-23 16:41:25 +01:00
|
|
|
|
|
2024-09-09 14:57:16 +01:00
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|
|
|
|
|
Please see LICENSE files in the repository root for full details.
|
2015-06-23 16:41:25 +01:00
|
|
|
|
*/
|
2016-09-01 11:08:40 +01:00
|
|
|
|
|
2023-02-28 10:31:48 +00:00
|
|
|
|
import React, { createRef } from "react";
|
2022-02-22 12:18:08 +00:00
|
|
|
|
import {
|
|
|
|
|
|
ClientEvent,
|
|
|
|
|
|
createClient,
|
|
|
|
|
|
EventType,
|
|
|
|
|
|
HttpApiEvent,
|
|
|
|
|
|
MatrixClient,
|
2023-08-07 09:24:58 +01:00
|
|
|
|
MatrixEvent,
|
2023-08-08 11:12:12 +01:00
|
|
|
|
RoomType,
|
2023-08-10 09:01:14 +01:00
|
|
|
|
SyncState,
|
2024-05-20 10:53:50 -04:00
|
|
|
|
SyncStateData,
|
2024-03-25 12:48:48 +00:00
|
|
|
|
TimelineEvents,
|
2022-02-22 12:18:08 +00:00
|
|
|
|
} from "matrix-js-sdk/src/matrix";
|
2021-12-06 09:39:33 +11:00
|
|
|
|
import { defer, IDeferred, QueryDict } from "matrix-js-sdk/src/utils";
|
2021-12-09 09:10:23 +00:00
|
|
|
|
import { logger } from "matrix-js-sdk/src/logger";
|
2022-02-01 18:24:17 +01:00
|
|
|
|
import { throttle } from "lodash";
|
2022-02-22 12:18:08 +00:00
|
|
|
|
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
|
2024-07-04 16:50:07 +01:00
|
|
|
|
import { KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
|
2021-07-01 22:50:06 +01:00
|
|
|
|
|
2019-12-07 13:07:52 +00:00
|
|
|
|
// what-input helps improve keyboard accessibility
|
|
|
|
|
|
import "what-input";
|
2019-09-27 10:05:08 +01:00
|
|
|
|
|
2023-02-28 10:31:48 +00:00
|
|
|
|
import type NewRecoveryMethodDialog from "../../async-components/views/dialogs/security/NewRecoveryMethodDialog";
|
|
|
|
|
|
import type RecoveryMethodRemovedDialog from "../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog";
|
2022-02-09 14:25:58 +00:00
|
|
|
|
import PosthogTrackers from "../../PosthogTrackers";
|
2018-07-06 11:00:39 +01:00
|
|
|
|
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
|
2021-12-17 11:02:06 +00:00
|
|
|
|
import { IMatrixClientCreds, MatrixClientPeg } from "../../MatrixClientPeg";
|
2017-05-19 13:53:11 +01:00
|
|
|
|
import PlatformPeg from "../../PlatformPeg";
|
2023-10-13 10:43:39 +01:00
|
|
|
|
import SdkConfig, { ConfigOptions } from "../../SdkConfig";
|
2020-05-13 20:41:41 -06:00
|
|
|
|
import dis from "../../dispatcher/dispatcher";
|
2019-03-12 17:29:16 +01:00
|
|
|
|
import Notifier from "../../Notifier";
|
2017-05-19 13:53:11 +01:00
|
|
|
|
import Modal from "../../Modal";
|
2020-05-13 21:03:12 -06:00
|
|
|
|
import { showRoomInviteDialog, showStartChatInviteDialog } from "../../RoomInvite";
|
2017-05-19 13:53:11 +01:00
|
|
|
|
import * as Rooms from "../../Rooms";
|
|
|
|
|
|
import * as Lifecycle from "../../Lifecycle";
|
2017-05-26 11:50:32 +01:00
|
|
|
|
// LifecycleStore is not used but does listen to and dispatch actions
|
2019-09-27 09:00:54 +01:00
|
|
|
|
import "../../stores/LifecycleStore";
|
2022-01-13 10:55:25 -05:00
|
|
|
|
import "../../stores/AutoRageshakeStore";
|
2021-09-27 12:40:34 +02:00
|
|
|
|
import PageType from "../../PageTypes";
|
2021-06-29 13:11:58 +01:00
|
|
|
|
import createRoom, { IOpts } from "../../createRoom";
|
2024-02-12 15:04:13 +00:00
|
|
|
|
import { _t, _td } from "../../languageHandler";
|
2020-07-28 16:37:09 -06:00
|
|
|
|
import SettingsStore from "../../settings/SettingsStore";
|
2020-01-31 12:28:14 +00:00
|
|
|
|
import ThemeController from "../../settings/controllers/ThemeController";
|
2021-06-16 10:24:51 +01:00
|
|
|
|
import { startAnyRegistrationFlow } from "../../Registration";
|
2019-03-12 16:36:12 +01:00
|
|
|
|
import ResizeNotifier from "../../utils/ResizeNotifier";
|
2022-07-14 15:03:34 +02:00
|
|
|
|
import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils";
|
2020-05-28 13:55:07 +01:00
|
|
|
|
import ThemeWatcher from "../../settings/watchers/ThemeWatcher";
|
|
|
|
|
|
import { FontWatcher } from "../../settings/watchers/FontWatcher";
|
2019-11-12 11:43:18 +00:00
|
|
|
|
import { storeRoomAliasInCache } from "../../RoomAliasCache";
|
2020-01-16 20:23:47 +00:00
|
|
|
|
import ToastStore from "../../stores/ToastStore";
|
2020-02-20 00:38:08 +00:00
|
|
|
|
import * as StorageManager from "../../utils/StorageManager";
|
2022-07-13 15:43:44 +02:00
|
|
|
|
import { UseCase } from "../../settings/enums/UseCase";
|
2020-04-22 13:22:33 +01:00
|
|
|
|
import type LoggedInViewType from "./LoggedInView";
|
2021-12-17 11:02:06 +00:00
|
|
|
|
import LoggedInView from "./LoggedInView";
|
2020-05-13 21:03:12 -06:00
|
|
|
|
import { Action } from "../../dispatcher/actions";
|
2020-05-22 22:04:21 +01:00
|
|
|
|
import { hideToast as hideAnalyticsToast, showToast as showAnalyticsToast } from "../../toasts/AnalyticsToast";
|
2021-06-29 13:11:58 +01:00
|
|
|
|
import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast";
|
2020-06-08 08:20:15 -06:00
|
|
|
|
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
2020-07-13 17:01:50 +01:00
|
|
|
|
import ErrorDialog from "../views/dialogs/ErrorDialog";
|
2021-12-17 11:02:06 +00:00
|
|
|
|
import {
|
|
|
|
|
|
RoomNotificationStateStore,
|
|
|
|
|
|
UPDATE_STATUS_INDICATOR,
|
|
|
|
|
|
} from "../../stores/notifications/RoomNotificationStateStore";
|
2020-07-28 11:53:43 -06:00
|
|
|
|
import { SettingLevel } from "../../settings/SettingLevel";
|
2020-09-11 19:49:48 -06:00
|
|
|
|
import ThreepidInviteStore, { IThreepidInvite, IThreepidInviteWireFormat } from "../../stores/ThreepidInviteStore";
|
2021-06-29 13:11:58 +01:00
|
|
|
|
import { UIFeature } from "../../settings/UIFeature";
|
2020-12-23 19:02:01 +00:00
|
|
|
|
import DialPadModal from "../views/voip/DialPadModal";
|
2021-01-28 17:21:36 +00:00
|
|
|
|
import { showToast as showMobileGuideToast } from "../../toasts/MobileGuideToast";
|
2021-02-16 15:17:51 -07:00
|
|
|
|
import { shouldUseLoginForWelcome } from "../../utils/pages";
|
2021-03-18 23:28:59 -06:00
|
|
|
|
import RoomListStore from "../../stores/room-list/RoomListStore";
|
2021-06-29 13:11:58 +01:00
|
|
|
|
import { RoomUpdateCause } from "../../stores/room-list/models";
|
2024-04-12 17:15:17 +02:00
|
|
|
|
import { ModuleRunner } from "../../modules/ModuleRunner";
|
2021-07-03 11:57:05 +02:00
|
|
|
|
import Spinner from "../views/elements/Spinner";
|
|
|
|
|
|
import QuestionDialog from "../views/dialogs/QuestionDialog";
|
2022-03-24 16:42:53 -06:00
|
|
|
|
import UserSettingsDialog from "../views/dialogs/UserSettingsDialog";
|
2021-07-03 11:57:05 +02:00
|
|
|
|
import CreateRoomDialog from "../views/dialogs/CreateRoomDialog";
|
|
|
|
|
|
import KeySignatureUploadFailedDialog from "../views/dialogs/KeySignatureUploadFailedDialog";
|
|
|
|
|
|
import IncomingSasDialog from "../views/dialogs/IncomingSasDialog";
|
|
|
|
|
|
import CompleteSecurity from "./auth/CompleteSecurity";
|
|
|
|
|
|
import Welcome from "../views/auth/Welcome";
|
|
|
|
|
|
import ForgotPassword from "./auth/ForgotPassword";
|
|
|
|
|
|
import E2eSetup from "./auth/E2eSetup";
|
|
|
|
|
|
import Registration from "./auth/Registration";
|
|
|
|
|
|
import Login from "./auth/Login";
|
|
|
|
|
|
import ErrorBoundary from "../views/elements/ErrorBoundary";
|
2021-07-03 12:24:07 +02:00
|
|
|
|
import VerificationRequestToast from "../views/toasts/VerificationRequestToast";
|
2021-05-19 10:07:02 +01:00
|
|
|
|
import PerformanceMonitor, { PerformanceEntryNames } from "../../performance";
|
2021-05-25 09:50:09 +01:00
|
|
|
|
import UIStore, { UI_EVENTS } from "../../stores/UIStore";
|
2021-07-03 11:57:05 +02:00
|
|
|
|
import SoftLogout from "./auth/SoftLogout";
|
2021-07-14 14:58:18 +01:00
|
|
|
|
import { makeRoomPermalink } from "../../utils/permalinks/Permalinks";
|
|
|
|
|
|
import { copyPlaintext } from "../../utils/strings";
|
2021-08-03 11:55:02 +01:00
|
|
|
|
import { PosthogAnalytics } from "../../PosthogAnalytics";
|
2021-08-16 13:06:19 +01:00
|
|
|
|
import { initSentry } from "../../sentry";
|
2022-08-30 15:13:39 -04:00
|
|
|
|
import LegacyCallHandler from "../../LegacyCallHandler";
|
2021-09-29 14:04:02 +01:00
|
|
|
|
import { showSpaceInvite } from "../../utils/space";
|
2024-01-04 18:12:08 +00:00
|
|
|
|
import { ButtonEvent } from "../views/elements/AccessibleButton";
|
2021-12-06 09:25:05 +00:00
|
|
|
|
import { ActionPayload } from "../../dispatcher/payloads";
|
2021-12-17 11:02:06 +00:00
|
|
|
|
import { SummarizedNotificationState } from "../../stores/notifications/SummarizedNotificationState";
|
2022-02-09 14:25:58 +00:00
|
|
|
|
import Views from "../../Views";
|
2024-04-10 14:13:08 +01:00
|
|
|
|
import { FocusNextType, ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
|
2022-02-22 11:04:27 +01:00
|
|
|
|
import { ViewHomePagePayload } from "../../dispatcher/payloads/ViewHomePagePayload";
|
|
|
|
|
|
import { AfterLeaveRoomPayload } from "../../dispatcher/payloads/AfterLeaveRoomPayload";
|
|
|
|
|
|
import { DoAfterSyncPreparedPayload } from "../../dispatcher/payloads/DoAfterSyncPreparedPayload";
|
|
|
|
|
|
import { ViewStartChatOrReusePayload } from "../../dispatcher/payloads/ViewStartChatOrReusePayload";
|
2022-03-24 15:25:44 -06:00
|
|
|
|
import { leaveRoomBehaviour } from "../../utils/leave-behaviour";
|
2022-08-30 15:13:39 -04:00
|
|
|
|
import { CallStore } from "../../stores/CallStore";
|
2022-05-26 10:19:00 +01:00
|
|
|
|
import { IRoomStateEventsActionPayload } from "../../actions/MatrixActionCreators";
|
2022-07-23 14:13:49 +02:00
|
|
|
|
import { ShowThreadPayload } from "../../dispatcher/payloads/ShowThreadPayload";
|
|
|
|
|
|
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
|
|
|
|
|
|
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
|
|
|
|
|
import { TimelineRenderingType } from "../../contexts/RoomContext";
|
2022-07-13 15:43:44 +02:00
|
|
|
|
import { UseCaseSelection } from "../views/elements/UseCaseSelection";
|
2022-07-14 15:03:34 +02:00
|
|
|
|
import { ValidatedServerConfig } from "../../utils/ValidatedServerConfig";
|
2022-07-20 09:26:25 +02:00
|
|
|
|
import { isLocalRoom } from "../../utils/localRoom/isLocalRoom";
|
2024-05-20 10:53:50 -04:00
|
|
|
|
import { SDKContext, SdkContextClass } from "../../contexts/SDKContext";
|
2022-10-11 11:10:55 +02:00
|
|
|
|
import { viewUserDeviceSettings } from "../../actions/handlers/viewUserDeviceSettings";
|
2023-01-24 11:58:37 +01:00
|
|
|
|
import { cleanUpBroadcasts, VoiceBroadcastResumer } from "../../voice-broadcast";
|
2022-11-09 10:50:01 +00:00
|
|
|
|
import GenericToast from "../views/toasts/GenericToast";
|
2023-08-21 10:39:20 +01:00
|
|
|
|
import RovingSpotlightDialog from "../views/dialogs/spotlight/SpotlightDialog";
|
2023-01-30 10:54:05 +01:00
|
|
|
|
import { findDMForUser } from "../../utils/dm/findDMForUser";
|
2023-02-03 08:59:21 +00:00
|
|
|
|
import { Linkify } from "../../HtmlUtils";
|
2024-01-15 15:25:48 +00:00
|
|
|
|
import { NotificationLevel } from "../../stores/notifications/NotificationLevel";
|
2023-02-28 10:31:48 +00:00
|
|
|
|
import { UserTab } from "../views/dialogs/UserTab";
|
2023-06-27 21:42:31 +12:00
|
|
|
|
import { shouldSkipSetupEncryption } from "../../utils/crypto/shouldSkipSetupEncryption";
|
2023-08-21 10:39:20 +01:00
|
|
|
|
import { Filter } from "../views/dialogs/spotlight/Filter";
|
2023-08-24 09:28:43 +01:00
|
|
|
|
import { checkSessionLockFree, getSessionLock } from "../../utils/SessionLock";
|
|
|
|
|
|
import { SessionLockStolenView } from "./auth/SessionLockStolenView";
|
|
|
|
|
|
import { ConfirmSessionLockTheftView } from "./auth/ConfirmSessionLockTheftView";
|
2024-01-04 18:12:08 +00:00
|
|
|
|
import { LoginSplashView } from "./auth/LoginSplashView";
|
2024-08-07 09:35:57 +01:00
|
|
|
|
import { cleanUpDraftsIfRequired } from "../../DraftCleaner";
|
2023-04-28 16:56:26 +02:00
|
|
|
|
|
2022-02-09 14:25:58 +00:00
|
|
|
|
// legacy export
|
|
|
|
|
|
export { default as Views } from "../../Views";
|
2016-06-08 23:03:46 +01:00
|
|
|
|
|
2024-09-13 12:12:04 +01:00
|
|
|
|
const AUTH_SCREENS = ["register", "mobile_register", "login", "forgot_password", "start_sso", "start_cas", "welcome"];
|
2020-11-16 15:56:54 +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 = [Action.ViewUserSettings, "view_create_chat", "view_create_room"];
|
|
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
interface IScreen {
|
2020-04-27 23:59:07 +01:00
|
|
|
|
screen: string;
|
2021-07-16 13:11:43 +01:00
|
|
|
|
params?: QueryDict;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
}
|
2017-06-14 20:04:55 +01:00
|
|
|
|
|
2022-08-09 12:55:49 +01:00
|
|
|
|
interface IProps {
|
2023-10-13 10:43:39 +01:00
|
|
|
|
config: ConfigOptions;
|
2020-09-09 16:52:46 +01:00
|
|
|
|
onNewScreen: (screen: string, replaceLast: boolean) => void;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
enableGuest?: boolean;
|
|
|
|
|
|
// the queryParams extracted from the [real] query-string of the URI
|
2023-05-09 18:24:40 +01:00
|
|
|
|
realQueryParams: QueryDict;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
// the initial queryParams extracted from the hash-fragment of the URI
|
2021-07-16 13:11:43 +01:00
|
|
|
|
startingFragmentQueryParams?: QueryDict;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
// called when we have completed a token login
|
2023-04-20 09:49:10 +01:00
|
|
|
|
onTokenLoginCompleted: () => void;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
// Represents the screen to display as a result of parsing the initial window.location
|
|
|
|
|
|
initialScreenAfterLogin?: IScreen;
|
|
|
|
|
|
// displayname, if any, to set on the device when logging in/registering.
|
2020-06-18 14:32:43 +01:00
|
|
|
|
defaultDeviceDisplayName?: string;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
}
|
2016-08-11 11:00:15 +01:00
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
interface IState {
|
|
|
|
|
|
// the master view we are showing.
|
2020-04-23 10:12:50 +01:00
|
|
|
|
view: Views;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
// What the LoggedInView would be showing if visible
|
2020-08-29 01:11:08 +01:00
|
|
|
|
// eslint-disable-next-line camelcase
|
2021-09-27 12:40:34 +02:00
|
|
|
|
page_type?: PageType;
|
2020-04-22 13:08:33 +01: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.
|
2023-03-10 14:55:06 +00:00
|
|
|
|
currentRoomId: string | null;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
// If we're trying to just view a user ID (i.e. /user URL), this is it
|
2023-03-10 14:55:06 +00:00
|
|
|
|
currentUserId: string | null;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
// this is persisted as mx_lhs_size, loaded in LoggedInView
|
|
|
|
|
|
collapseLhs: boolean;
|
|
|
|
|
|
// Parameters used in the registration dance with the IS
|
2020-08-29 01:11:08 +01:00
|
|
|
|
// eslint-disable-next-line camelcase
|
2020-04-22 13:08:33 +01:00
|
|
|
|
register_client_secret?: string;
|
2020-08-29 01:11:08 +01:00
|
|
|
|
// eslint-disable-next-line camelcase
|
2020-04-22 13:08:33 +01:00
|
|
|
|
register_session_id?: string;
|
2020-08-29 01:11:08 +01:00
|
|
|
|
// eslint-disable-next-line camelcase
|
2020-04-22 13:08:33 +01:00
|
|
|
|
register_id_sid?: string;
|
2024-09-13 12:12:04 +01:00
|
|
|
|
isMobileRegistration?: boolean;
|
2020-04-22 13:08:33 +01: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: boolean;
|
2023-03-10 14:55:06 +00:00
|
|
|
|
syncError: Error | null;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
resizeNotifier: ResizeNotifier;
|
|
|
|
|
|
serverConfig?: ValidatedServerConfig;
|
|
|
|
|
|
ready: boolean;
|
2021-07-01 23:23:03 +01:00
|
|
|
|
threepidInvite?: IThreepidInvite;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
roomOobData?: object;
|
|
|
|
|
|
pendingInitialSync?: boolean;
|
2020-11-02 17:24:47 +00:00
|
|
|
|
justRegistered?: boolean;
|
2021-03-01 17:54:53 +00:00
|
|
|
|
roomJustCreatedOpts?: IOpts;
|
2021-10-20 06:55:22 -06:00
|
|
|
|
forceTimeline?: boolean; // see props
|
2020-04-22 13:08:33 +01:00
|
|
|
|
}
|
2016-08-11 11:00:15 +01:00
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
2022-12-16 12:29:59 +00:00
|
|
|
|
public static displayName = "MatrixChat";
|
2016-08-12 11:41:06 +01:00
|
|
|
|
|
2022-12-16 12:29:59 +00:00
|
|
|
|
public static defaultProps = {
|
2020-04-22 11:55:03 +01:00
|
|
|
|
realQueryParams: {},
|
|
|
|
|
|
startingFragmentQueryParams: {},
|
|
|
|
|
|
config: {},
|
2023-01-12 13:25:14 +00:00
|
|
|
|
onTokenLoginCompleted: (): void => {},
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2017-03-08 10:25:54 +00:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private firstSyncComplete = false;
|
|
|
|
|
|
private firstSyncPromise: IDeferred<void>;
|
2017-03-02 14:40:55 +00:00
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
private screenAfterLogin?: IScreen;
|
2021-01-27 12:50:12 +00:00
|
|
|
|
private tokenLogin?: boolean;
|
2024-04-10 14:13:08 +01:00
|
|
|
|
// What to focus on next component update, if anything
|
|
|
|
|
|
private focusNext: FocusNextType;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
private subTitleStatus: string;
|
2021-05-28 10:03:46 +01:00
|
|
|
|
private prevWindowWidth: number;
|
2023-05-10 08:41:55 +01:00
|
|
|
|
private voiceBroadcastResumer?: VoiceBroadcastResumer;
|
2015-10-12 10:13:01 +01:00
|
|
|
|
|
2020-04-22 13:22:33 +01:00
|
|
|
|
private readonly loggedInView: React.RefObject<LoggedInViewType>;
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private readonly dispatcherRef: string;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
private readonly themeWatcher: ThemeWatcher;
|
2020-05-07 18:01:20 +01:00
|
|
|
|
private readonly fontWatcher: FontWatcher;
|
2022-10-19 13:07:03 +01:00
|
|
|
|
private readonly stores: SdkContextClass;
|
2017-03-08 10:25:54 +00:00
|
|
|
|
|
2022-12-16 12:29:59 +00:00
|
|
|
|
public constructor(props: IProps) {
|
2021-12-17 11:02:06 +00:00
|
|
|
|
super(props);
|
2022-10-19 13:07:03 +01:00
|
|
|
|
this.stores = SdkContextClass.instance;
|
|
|
|
|
|
this.stores.constructEagerStores();
|
2016-11-24 12:33:31 +00:00
|
|
|
|
|
2020-04-22 11:55:03 +01:00
|
|
|
|
this.state = {
|
2020-04-23 10:12:50 +01:00
|
|
|
|
view: Views.LOADING,
|
2017-08-25 12:10:13 +01:00
|
|
|
|
collapseLhs: false,
|
2023-03-10 14:55:06 +00:00
|
|
|
|
currentRoomId: null,
|
|
|
|
|
|
currentUserId: null,
|
2016-08-16 03:31:02 +05:30
|
|
|
|
|
2018-02-08 22:51:07 +01:00
|
|
|
|
hideToSRUsers: false,
|
2024-09-13 12:12:04 +01:00
|
|
|
|
isMobileRegistration: false,
|
2018-09-07 12:18:25 +01:00
|
|
|
|
|
|
|
|
|
|
syncError: null, // If the current syncing status is ERROR, the error object, otherwise null.
|
2019-03-12 16:36:12 +01:00
|
|
|
|
resizeNotifier: new ResizeNotifier(),
|
2020-04-22 13:08:33 +01:00
|
|
|
|
ready: false,
|
2015-06-11 18:25:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.loggedInView = createRef();
|
2015-12-17 14:56:55 +00:00
|
|
|
|
|
2016-05-06 14:19:56 +01:00
|
|
|
|
SdkConfig.put(this.props.config);
|
2016-08-02 18:46:43 +01:00
|
|
|
|
|
2017-04-06 11:30:47 +01:00
|
|
|
|
// Used by _viewRoom before getting state from sync
|
|
|
|
|
|
this.firstSyncComplete = false;
|
2019-11-12 11:45:28 +00:00
|
|
|
|
this.firstSyncPromise = defer();
|
2017-04-06 11:30:47 +01:00
|
|
|
|
|
2016-08-03 09:53:02 +01: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-08-08 22:19:38 +01:00
|
|
|
|
// a thing to call showScreen with once login completes. this is kept
|
|
|
|
|
|
// outside this.state because updating it should never trigger a
|
|
|
|
|
|
// rerender.
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.screenAfterLogin = this.props.initialScreenAfterLogin;
|
2020-09-11 19:49:48 -06:00
|
|
|
|
if (this.screenAfterLogin) {
|
|
|
|
|
|
const params = this.screenAfterLogin.params || {};
|
|
|
|
|
|
if (this.screenAfterLogin.screen.startsWith("room/") && params["signurl"] && params["email"]) {
|
|
|
|
|
|
// probably a threepid invite - try to store it
|
|
|
|
|
|
const roomId = this.screenAfterLogin.screen.substring("room/".length);
|
2021-07-16 13:11:43 +01:00
|
|
|
|
ThreepidInviteStore.instance.storeInvite(roomId, params as unknown as IThreepidInviteWireFormat);
|
2020-09-11 19:49:48 -06:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-08-08 22:19:38 +01:00
|
|
|
|
|
2021-05-28 10:03:46 +01:00
|
|
|
|
this.prevWindowWidth = UIStore.instance.windowWidth || 1000;
|
2021-05-25 09:50:09 +01:00
|
|
|
|
UIStore.instance.on(UI_EVENTS.Resize, this.handleResize);
|
2017-10-26 01:43:42 +01:00
|
|
|
|
|
2019-03-12 16:37:20 +01:00
|
|
|
|
// For PersistentElement
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
|
2019-07-04 15:14:00 -06:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
RoomNotificationStateStore.instance.on(UPDATE_STATUS_INDICATOR, this.onUpdateStatusIndicator);
|
|
|
|
|
|
|
2015-06-12 17:34:17 +01:00
|
|
|
|
this.dispatcherRef = dis.register(this.onAction);
|
2020-05-07 18:01:20 +01:00
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.themeWatcher = new ThemeWatcher();
|
2020-05-07 18:01:20 +01:00
|
|
|
|
this.fontWatcher = new FontWatcher();
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.themeWatcher.start();
|
2020-05-07 18:01:20 +01:00
|
|
|
|
this.fontWatcher.start();
|
2016-08-10 11:33:58 +01:00
|
|
|
|
|
2019-09-23 22:01:49 +01:00
|
|
|
|
// object field used for tracking the status info appended to the title tag.
|
|
|
|
|
|
// we don't do it as react state as i'm scared about triggering needless react refreshes.
|
|
|
|
|
|
this.subTitleStatus = "";
|
|
|
|
|
|
|
2023-08-14 13:52:08 +01:00
|
|
|
|
initSentry(SdkConfig.get("sentry"));
|
2017-06-14 10:53:48 +01:00
|
|
|
|
|
2023-08-24 09:28:43 +01:00
|
|
|
|
if (!checkSessionLockFree()) {
|
|
|
|
|
|
// another instance holds the lock; confirm its theft before proceeding
|
|
|
|
|
|
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.startInitSession();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Kick off a call to {@link initSession}, and handle any errors
|
|
|
|
|
|
*/
|
|
|
|
|
|
private startInitSession = (): void => {
|
2023-08-14 13:52:08 +01:00
|
|
|
|
this.initSession().catch((err) => {
|
|
|
|
|
|
// TODO: show an error screen, rather than a spinner of doom
|
|
|
|
|
|
logger.error("Error initialising Matrix session", err);
|
|
|
|
|
|
});
|
2023-08-24 09:28:43 +01:00
|
|
|
|
};
|
2017-06-14 10:53:48 +01:00
|
|
|
|
|
2023-08-14 13:52:08 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Do what we can to establish a Matrix session.
|
|
|
|
|
|
*
|
|
|
|
|
|
* * Special-case soft-logged-out sessions
|
|
|
|
|
|
* * If we have OIDC or token login parameters, follow them
|
|
|
|
|
|
* * If we have a guest access token in the query params, use that
|
|
|
|
|
|
* * If we have parameters in local storage, use them
|
|
|
|
|
|
* * Attempt to auto-register as a guest
|
|
|
|
|
|
* * If all else fails, present a login screen.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private async initSession(): Promise<void> {
|
2023-08-24 09:28:43 +01:00
|
|
|
|
// The Rust Crypto SDK will break if two Element instances try to use the same datastore at once, so
|
|
|
|
|
|
// make sure we are the only Element instance in town (on this browser/domain).
|
|
|
|
|
|
if (!(await getSessionLock(() => this.onSessionLockStolen()))) {
|
|
|
|
|
|
// we failed to get the lock. onSessionLockStolen should already have been called, so nothing left to do.
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-14 13:52:08 +01:00
|
|
|
|
// If the user was soft-logged-out, we want to make the SoftLogout component responsible for doing any
|
|
|
|
|
|
// token auth (rather than Lifecycle.attemptDelegatedAuthLogin), since SoftLogout knows about submitting the
|
|
|
|
|
|
// device ID and preserving the session.
|
|
|
|
|
|
//
|
|
|
|
|
|
// So, we start by special-casing soft-logged-out sessions.
|
|
|
|
|
|
if (Lifecycle.isSoftLogout()) {
|
|
|
|
|
|
// When the session loads it'll be detected as soft logged out and a dispatch
|
|
|
|
|
|
// will be sent out to say that, triggering this MatrixChat to show the soft
|
|
|
|
|
|
// logout page.
|
|
|
|
|
|
Lifecycle.loadSession();
|
|
|
|
|
|
return;
|
2019-07-08 12:43:16 -06:00
|
|
|
|
}
|
2018-05-15 13:15:40 +01:00
|
|
|
|
|
2023-08-14 13:52:08 +01:00
|
|
|
|
// Otherwise, the first thing to do is to try the token params in the query-string
|
|
|
|
|
|
const delegatedAuthSucceeded = await Lifecycle.attemptDelegatedAuthLogin(
|
|
|
|
|
|
this.props.realQueryParams,
|
|
|
|
|
|
this.props.defaultDeviceDisplayName,
|
|
|
|
|
|
this.getFragmentAfterLogin(),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// remove the loginToken or auth code from the URL regardless
|
|
|
|
|
|
if (
|
|
|
|
|
|
this.props.realQueryParams?.loginToken ||
|
|
|
|
|
|
this.props.realQueryParams?.code ||
|
|
|
|
|
|
this.props.realQueryParams?.state
|
|
|
|
|
|
) {
|
|
|
|
|
|
this.props.onTokenLoginCompleted();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (delegatedAuthSucceeded) {
|
|
|
|
|
|
// token auth/OIDC worked! Time to fire up the client.
|
|
|
|
|
|
this.tokenLogin = true;
|
|
|
|
|
|
|
|
|
|
|
|
// Create and start the client
|
|
|
|
|
|
// accesses the new credentials just set in storage during attemptDelegatedAuthLogin
|
|
|
|
|
|
// and sets logged in state
|
2024-09-11 16:13:04 +01:00
|
|
|
|
await Lifecycle.restoreSessionFromStorage({ ignoreGuest: true });
|
2023-08-14 13:52:08 +01:00
|
|
|
|
await this.postLoginSetup();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// if the user has followed a login or register link, don't reanimate
|
|
|
|
|
|
// the old creds, but rather go straight to the relevant page
|
|
|
|
|
|
const firstScreen = this.screenAfterLogin ? this.screenAfterLogin.screen : null;
|
|
|
|
|
|
const restoreSuccess = await this.loadSession();
|
|
|
|
|
|
if (restoreSuccess) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-03 16:19:54 +01:00
|
|
|
|
// If the first screen is an auth screen, we don't want to wait for login.
|
|
|
|
|
|
if (firstScreen !== null && AUTH_SCREENS.includes(firstScreen)) {
|
2023-08-14 13:52:08 +01:00
|
|
|
|
this.showScreenAfterLogin();
|
|
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2015-06-12 14:59:33 +01:00
|
|
|
|
|
2023-08-24 09:28:43 +01:00
|
|
|
|
private async onSessionLockStolen(): Promise<void> {
|
|
|
|
|
|
// switch to the LockStolenView. We deliberately do this immediately, rather than going through the dispatcher,
|
|
|
|
|
|
// because there can be a substantial queue in the dispatcher, and some of the events in it might require an
|
|
|
|
|
|
// active MatrixClient.
|
|
|
|
|
|
await new Promise<void>((resolve) => {
|
|
|
|
|
|
this.setState({ view: Views.LOCK_STOLEN }, resolve);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// now we can tell the Lifecycle routines to abort any active startup, and to stop the active client.
|
|
|
|
|
|
await Lifecycle.onSessionLockStolen();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private async postLoginSetup(): Promise<void> {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const cli = MatrixClientPeg.safeGet();
|
2021-01-27 12:50:12 +00:00
|
|
|
|
const cryptoEnabled = cli.isCryptoEnabled();
|
2021-01-28 11:00:04 +00:00
|
|
|
|
if (!cryptoEnabled) {
|
|
|
|
|
|
this.onLoggedIn();
|
|
|
|
|
|
}
|
2021-01-27 12:50:12 +00:00
|
|
|
|
|
2021-06-01 22:21:04 -06:00
|
|
|
|
const promisesList: Promise<any>[] = [this.firstSyncPromise.promise];
|
2022-12-09 14:14:06 +00:00
|
|
|
|
let crossSigningIsSetUp = false;
|
2021-01-27 12:50:12 +00:00
|
|
|
|
if (cryptoEnabled) {
|
2022-12-09 14:14:06 +00:00
|
|
|
|
// check if the user has previously published public cross-signing keys,
|
|
|
|
|
|
// as a proxy to figure out if it's worth prompting the user to verify
|
|
|
|
|
|
// from another device.
|
|
|
|
|
|
promisesList.push(
|
2023-01-12 13:25:14 +00:00
|
|
|
|
(async (): Promise<void> => {
|
2022-12-09 14:14:06 +00:00
|
|
|
|
crossSigningIsSetUp = await cli.userHasCrossSigningKeys();
|
|
|
|
|
|
})(),
|
|
|
|
|
|
);
|
2021-01-27 12:50:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now update the state to say we're waiting for the first sync to complete rather
|
|
|
|
|
|
// than for the login to finish.
|
|
|
|
|
|
this.setState({ pendingInitialSync: true });
|
|
|
|
|
|
|
|
|
|
|
|
await Promise.all(promisesList);
|
|
|
|
|
|
|
|
|
|
|
|
if (!cryptoEnabled) {
|
|
|
|
|
|
this.setState({ pendingInitialSync: false });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (crossSigningIsSetUp) {
|
2022-12-09 14:14:06 +00:00
|
|
|
|
// if the user has previously set up cross-signing, verify this device so we can fetch the
|
|
|
|
|
|
// private keys.
|
2024-04-12 17:15:17 +02:00
|
|
|
|
|
|
|
|
|
|
const cryptoExtension = ModuleRunner.instance.extensions.cryptoSetup;
|
|
|
|
|
|
if (cryptoExtension.SHOW_ENCRYPTION_SETUP_UI == false) {
|
2021-04-08 09:20:14 -06:00
|
|
|
|
this.onLoggedIn();
|
|
|
|
|
|
} else {
|
2021-06-29 13:11:58 +01:00
|
|
|
|
this.setStateForNewView({ view: Views.COMPLETE_SECURITY });
|
2021-04-08 09:20:14 -06:00
|
|
|
|
}
|
2023-06-27 21:42:31 +12:00
|
|
|
|
} else if (
|
|
|
|
|
|
(await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) &&
|
|
|
|
|
|
!shouldSkipSetupEncryption(cli)
|
|
|
|
|
|
) {
|
2022-12-09 14:14:06 +00:00
|
|
|
|
// if cross-signing is not yet set up, do so now if possible.
|
2021-01-27 12:50:12 +00:00
|
|
|
|
this.setStateForNewView({ view: Views.E2E_SETUP });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.onLoggedIn();
|
|
|
|
|
|
}
|
|
|
|
|
|
this.setState({ pendingInitialSync: false });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-18 09:22:43 +00:00
|
|
|
|
public setState<K extends keyof IState>(
|
|
|
|
|
|
state:
|
|
|
|
|
|
| ((prevState: Readonly<IState>, props: Readonly<IProps>) => Pick<IState, K> | IState | null)
|
|
|
|
|
|
| (Pick<IState, K> | IState | null),
|
|
|
|
|
|
callback?: () => void,
|
|
|
|
|
|
): void {
|
|
|
|
|
|
if (this.shouldTrackPageChange(this.state, { ...this.state, ...state })) {
|
2020-04-22 11:55:03 +01:00
|
|
|
|
this.startPageChangeTimer();
|
|
|
|
|
|
}
|
2022-11-18 09:22:43 +00:00
|
|
|
|
super.setState<K>(state, callback);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-01 18:24:17 +01:00
|
|
|
|
public componentDidMount(): void {
|
|
|
|
|
|
window.addEventListener("resize", this.onWindowResized);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-02-13 11:39:16 +00:00
|
|
|
|
public componentDidUpdate(prevProps: IProps, prevState: IState): void {
|
2020-04-22 11:55:03 +01:00
|
|
|
|
if (this.shouldTrackPageChange(prevState, this.state)) {
|
|
|
|
|
|
const durationMs = this.stopPageChangeTimer();
|
2023-04-28 09:45:36 +01:00
|
|
|
|
if (durationMs != null) {
|
|
|
|
|
|
PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs);
|
|
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2024-04-10 14:13:08 +01:00
|
|
|
|
if (this.focusNext === "composer") {
|
2021-07-08 17:36:31 +02:00
|
|
|
|
dis.fire(Action.FocusSendMessageComposer);
|
2024-04-10 14:13:08 +01:00
|
|
|
|
this.focusNext = undefined;
|
|
|
|
|
|
} else if (this.focusNext === "threadsPanel") {
|
|
|
|
|
|
dis.fire(Action.FocusThreadsPanel);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
public componentWillUnmount(): void {
|
2020-04-22 11:55:03 +01:00
|
|
|
|
Lifecycle.stopMatrixClient();
|
|
|
|
|
|
dis.unregister(this.dispatcherRef);
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.themeWatcher.stop();
|
2020-05-07 18:01:20 +01:00
|
|
|
|
this.fontWatcher.stop();
|
2021-05-25 09:50:09 +01:00
|
|
|
|
UIStore.destroy();
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.state.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize);
|
2022-02-01 18:24:17 +01:00
|
|
|
|
window.removeEventListener("resize", this.onWindowResized);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
|
2023-02-23 08:46:49 +01:00
|
|
|
|
this.stores.accountPasswordStore.clearPassword();
|
2023-05-10 08:41:55 +01:00
|
|
|
|
this.voiceBroadcastResumer?.destroy();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-01 18:24:17 +01:00
|
|
|
|
private onWindowResized = (): void => {
|
|
|
|
|
|
// XXX: This is a very unreliable way to detect whether or not the the devtools are open
|
|
|
|
|
|
this.warnInConsole();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private warnInConsole = throttle((): void => {
|
|
|
|
|
|
const largeFontSize = "50px";
|
|
|
|
|
|
const normalFontSize = "15px";
|
|
|
|
|
|
|
2023-10-02 16:13:00 +05:30
|
|
|
|
const waitText = _t("console_wait");
|
2023-09-21 09:11:26 +01:00
|
|
|
|
const scamText = _t("console_scam_warning");
|
|
|
|
|
|
const devText = _t("console_dev_note");
|
2022-02-01 18:24:17 +01:00
|
|
|
|
|
2022-02-04 14:30:18 +01:00
|
|
|
|
global.mx_rage_logger.bypassRageshake(
|
|
|
|
|
|
"log",
|
2022-02-01 18:24:17 +01:00
|
|
|
|
`%c${waitText}\n%c${scamText}\n%c${devText}`,
|
|
|
|
|
|
`font-size:${largeFontSize}; color:blue;`,
|
|
|
|
|
|
`font-size:${normalFontSize}; color:red;`,
|
|
|
|
|
|
`font-size:${normalFontSize};`,
|
|
|
|
|
|
);
|
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
2023-04-13 08:52:57 +01:00
|
|
|
|
private getFallbackHsUrl(): string | undefined {
|
2023-04-28 11:16:07 +01:00
|
|
|
|
if (this.getServerProperties().serverConfig?.isDefault) {
|
2023-04-13 08:52:57 +01:00
|
|
|
|
return this.props.config.fallback_hs_url;
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private getServerProperties(): { serverConfig: ValidatedServerConfig } {
|
2023-04-28 11:16:07 +01:00
|
|
|
|
const props = this.state.serverConfig || SdkConfig.get("validated_server_config")!;
|
2021-06-29 13:11:58 +01:00
|
|
|
|
return { serverConfig: props };
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-13 09:22:32 +01:00
|
|
|
|
private loadSession(): Promise<boolean> {
|
2019-03-07 17:04:50 -07:00
|
|
|
|
// the extra Promise.resolve() ensures that synchronous exceptions hit the same codepath as
|
|
|
|
|
|
// asynchronous ones.
|
|
|
|
|
|
return Promise.resolve()
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
return Lifecycle.loadSession({
|
|
|
|
|
|
fragmentQueryParams: this.props.startingFragmentQueryParams,
|
|
|
|
|
|
enableGuest: this.props.enableGuest,
|
2019-05-02 23:09:07 -06:00
|
|
|
|
guestHsUrl: this.getServerProperties().serverConfig.hsUrl,
|
|
|
|
|
|
guestIsUrl: this.getServerProperties().serverConfig.isUrl,
|
2019-03-07 17:04:50 -07:00
|
|
|
|
defaultDeviceDisplayName: this.props.defaultDeviceDisplayName,
|
|
|
|
|
|
});
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((loadedSession) => {
|
|
|
|
|
|
if (!loadedSession) {
|
2020-09-11 19:53:52 -06:00
|
|
|
|
// fall back to showing the welcome screen... unless we have a 3pid invite pending
|
2024-07-15 11:02:23 +01:00
|
|
|
|
if (
|
|
|
|
|
|
ThreepidInviteStore.instance.pickBestInvite() &&
|
|
|
|
|
|
SettingsStore.getValue(UIFeature.Registration)
|
|
|
|
|
|
) {
|
2021-06-29 13:11:58 +01:00
|
|
|
|
dis.dispatch({ action: "start_registration" });
|
2020-09-11 19:53:52 -06:00
|
|
|
|
} else {
|
2021-06-29 13:11:58 +01:00
|
|
|
|
dis.dispatch({ action: "view_welcome_page" });
|
2022-12-12 12:24:14 +01:00
|
|
|
|
}
|
2020-09-11 19:53:52 -06:00
|
|
|
|
}
|
2022-10-13 09:22:32 +01:00
|
|
|
|
return loadedSession;
|
2019-03-07 17:04:50 -07: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.
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2015-06-18 15:03:57 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private startPageChangeTimer(): void {
|
2021-05-19 10:07:02 +01:00
|
|
|
|
PerformanceMonitor.instance.start(PerformanceEntryNames.PAGE_CHANGE);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2018-03-28 10:25:28 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private stopPageChangeTimer(): number | null {
|
2021-05-19 10:07:02 +01:00
|
|
|
|
const perfMonitor = PerformanceMonitor.instance;
|
2018-06-04 09:38:21 +01:00
|
|
|
|
|
2021-05-19 10:07:02 +01:00
|
|
|
|
perfMonitor.stop(PerformanceEntryNames.PAGE_CHANGE);
|
2018-05-03 14:08:10 +01:00
|
|
|
|
|
2021-05-19 10:07:02 +01:00
|
|
|
|
const entries = perfMonitor.getEntries({
|
|
|
|
|
|
name: PerformanceEntryNames.PAGE_CHANGE,
|
|
|
|
|
|
});
|
|
|
|
|
|
const measurement = entries.pop();
|
2018-05-03 14:08:10 +01:00
|
|
|
|
|
2021-05-19 10:07:02 +01:00
|
|
|
|
return measurement ? measurement.duration : null;
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2018-03-28 10:25:28 +01:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private shouldTrackPageChange(prevState: IState, state: IState): boolean {
|
2018-03-27 11:17:49 +01:00
|
|
|
|
return (
|
|
|
|
|
|
prevState.currentRoomId !== state.currentRoomId ||
|
|
|
|
|
|
prevState.view !== state.view ||
|
|
|
|
|
|
prevState.page_type !== state.page_type
|
|
|
|
|
|
);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2018-03-27 11:17:49 +01:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private setStateForNewView(state: Partial<IState>): void {
|
2017-06-14 20:04:55 +01:00
|
|
|
|
if (state.view === undefined) {
|
|
|
|
|
|
throw new Error("setStateForNewView with no view!");
|
|
|
|
|
|
}
|
2023-02-13 11:39:16 +00:00
|
|
|
|
this.setState({
|
|
|
|
|
|
currentUserId: undefined,
|
2020-11-02 17:24:47 +00:00
|
|
|
|
justRegistered: false,
|
2023-02-13 11:39:16 +00:00
|
|
|
|
...state,
|
|
|
|
|
|
} as IState);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2016-09-30 11:56:32 +01:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private onAction = (payload: ActionPayload): void => {
|
2023-08-24 09:28:43 +01:00
|
|
|
|
// once the session lock has been stolen, don't try to do anything.
|
|
|
|
|
|
if (this.state.view === Views.LOCK_STOLEN) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-11-10 10:51:28 +00:00
|
|
|
|
// Start the onboarding process for certain actions
|
2021-12-06 09:25:05 +00:00
|
|
|
|
if (MatrixClientPeg.get()?.isGuest() && ONBOARDING_FLOW_STARTERS.includes(payload.action)) {
|
2017-11-10 10:51:28 +00:00
|
|
|
|
// 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({
|
2022-02-22 11:04:27 +01:00
|
|
|
|
action: Action.DoAfterSyncPrepared,
|
2017-11-10 10:51:28 +00:00
|
|
|
|
deferred_action: payload,
|
|
|
|
|
|
});
|
2021-06-29 13:11:58 +01:00
|
|
|
|
dis.dispatch({ action: "require_registration" });
|
2017-11-10 10:51:28 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-06-12 17:34:17 +01:00
|
|
|
|
switch (payload.action) {
|
2019-08-16 13:10:41 -06:00
|
|
|
|
case "MatrixActions.accountData":
|
|
|
|
|
|
// XXX: This is a collection of several hacks to solve a minor problem. We want to
|
2021-07-13 15:26:38 +01:00
|
|
|
|
// update our local state when the identity server changes, but don't want to put that in
|
2019-08-16 13:10:41 -06:00
|
|
|
|
// the js-sdk as we'd be then dictating how all consumers need to behave. However,
|
|
|
|
|
|
// this component is already bloated and we probably don't want this tiny logic in
|
|
|
|
|
|
// here, but there's no better place in the react-sdk for it. Additionally, we're
|
|
|
|
|
|
// abusing the MatrixActionCreator stuff to avoid errors on dispatches.
|
|
|
|
|
|
if (payload.event_type === "m.identity_server") {
|
|
|
|
|
|
const fullUrl = payload.event_content ? payload.event_content["base_url"] : null;
|
|
|
|
|
|
if (!fullUrl) {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
MatrixClientPeg.safeGet().setIdentityServerUrl(undefined);
|
2019-08-16 13:10:41 -06:00
|
|
|
|
localStorage.removeItem("mx_is_access_token");
|
|
|
|
|
|
localStorage.removeItem("mx_is_url");
|
|
|
|
|
|
} else {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
MatrixClientPeg.safeGet().setIdentityServerUrl(fullUrl);
|
2019-08-16 13:10:41 -06:00
|
|
|
|
localStorage.removeItem("mx_is_access_token"); // clear token
|
|
|
|
|
|
localStorage.setItem("mx_is_url", fullUrl); // XXX: Do we still need this?
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// redispatch the change with a more specific action
|
2021-06-29 13:11:58 +01:00
|
|
|
|
dis.dispatch({ action: "id_server_changed" });
|
2019-08-16 13:10:41 -06:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2015-06-12 17:34:17 +01:00
|
|
|
|
case "logout":
|
2022-08-30 15:13:39 -04:00
|
|
|
|
LegacyCallHandler.instance.hangupAllCalls();
|
2023-01-24 11:58:37 +01:00
|
|
|
|
Promise.all([
|
2024-06-17 13:00:41 +02:00
|
|
|
|
...[...CallStore.instance.connectedCalls].map((call) => call.disconnect()),
|
2023-01-24 11:58:37 +01:00
|
|
|
|
cleanUpBroadcasts(this.stores),
|
2023-10-16 10:35:25 +13:00
|
|
|
|
]).finally(() => Lifecycle.logout(this.stores.oidcClientStore));
|
2015-06-12 17:34:17 +01:00
|
|
|
|
break;
|
2018-09-05 17:07:39 +01:00
|
|
|
|
case "require_registration":
|
2021-12-06 09:25:05 +00:00
|
|
|
|
startAnyRegistrationFlow(payload as any);
|
2018-09-05 17:07:39 +01:00
|
|
|
|
break;
|
2024-09-13 12:12:04 +01:00
|
|
|
|
case "start_mobile_registration":
|
|
|
|
|
|
this.startRegistration(payload.params || {}, true);
|
|
|
|
|
|
break;
|
2015-07-13 19:14:02 +01:00
|
|
|
|
case "start_registration":
|
2019-07-04 16:51:55 -06:00
|
|
|
|
if (Lifecycle.isSoftLogout()) {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.onSoftLogout();
|
2019-07-04 16:51:55 -06:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2018-09-05 17:07:39 +01:00
|
|
|
|
// This starts the full registration flow
|
2019-06-10 10:24:06 +01:00
|
|
|
|
if (payload.screenAfterLogin) {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.screenAfterLogin = payload.screenAfterLogin;
|
2019-06-10 10:24:06 +01:00
|
|
|
|
}
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.startRegistration(payload.params || {});
|
2015-07-13 19:14:02 +01:00
|
|
|
|
break;
|
|
|
|
|
|
case "start_login":
|
2019-07-04 16:51:55 -06:00
|
|
|
|
if (Lifecycle.isSoftLogout()) {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.onSoftLogout();
|
2019-07-04 16:51:55 -06:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2019-06-10 10:24:06 +01:00
|
|
|
|
if (payload.screenAfterLogin) {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.screenAfterLogin = payload.screenAfterLogin;
|
2019-06-10 10:24:06 +01:00
|
|
|
|
}
|
2021-03-12 15:01:05 -07:00
|
|
|
|
this.viewLogin();
|
2015-11-20 11:57:04 +00:00
|
|
|
|
break;
|
2016-01-12 17:20:16 +00:00
|
|
|
|
case "start_password_recovery":
|
2017-06-09 17:18:45 +01:00
|
|
|
|
this.setStateForNewView({
|
2020-04-23 10:12:50 +01:00
|
|
|
|
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 14:16:25 +01:00
|
|
|
|
case "start_chat":
|
2023-06-15 15:11:49 +01:00
|
|
|
|
createRoom(MatrixClientPeg.safeGet(), {
|
2017-06-01 14:16:25 +01:00
|
|
|
|
dmUserId: payload.user_id,
|
2015-12-13 13:49:28 +00:00
|
|
|
|
});
|
2015-07-13 19:14:02 +01:00
|
|
|
|
break;
|
2015-12-13 13:49:28 +00:00
|
|
|
|
case "leave_room":
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.leaveRoom(payload.room_id);
|
2015-07-13 19:14:02 +01:00
|
|
|
|
break;
|
2020-07-13 16:35:03 +01:00
|
|
|
|
case "forget_room":
|
|
|
|
|
|
this.forgetRoom(payload.room_id);
|
|
|
|
|
|
break;
|
2021-07-14 14:58:18 +01:00
|
|
|
|
case "copy_room":
|
|
|
|
|
|
this.copyRoom(payload.room_id);
|
|
|
|
|
|
break;
|
2017-03-09 17:03:57 +00:00
|
|
|
|
case "reject_invite":
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(QuestionDialog, {
|
2023-10-02 16:13:00 +05:30
|
|
|
|
title: _t("reject_invitation_dialog|title"),
|
|
|
|
|
|
description: _t("reject_invitation_dialog|confirmation"),
|
2017-03-09 17:03:57 +00:00
|
|
|
|
onFinished: (confirm) => {
|
|
|
|
|
|
if (confirm) {
|
|
|
|
|
|
// FIXME: controller shouldn't be loading a view :(
|
2023-02-03 15:27:47 +00:00
|
|
|
|
const modal = Modal.createDialog(Spinner, undefined, "mx_Dialog_spinner");
|
2017-03-09 17:03:57 +00:00
|
|
|
|
|
2023-06-15 15:11:49 +01:00
|
|
|
|
MatrixClientPeg.safeGet()
|
2019-11-18 10:03:05 +00:00
|
|
|
|
.leave(payload.room_id)
|
|
|
|
|
|
.then(
|
|
|
|
|
|
() => {
|
2017-03-09 17:03:57 +00:00
|
|
|
|
modal.close();
|
2017-06-16 11:27:47 +01:00
|
|
|
|
if (this.state.currentRoomId === payload.room_id) {
|
2022-02-22 11:04:27 +01:00
|
|
|
|
dis.dispatch({ action: Action.ViewHomePage });
|
2017-03-09 17:03:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
(err) => {
|
|
|
|
|
|
modal.close();
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(ErrorDialog, {
|
2023-10-02 16:13:00 +05:30
|
|
|
|
title: _t("reject_invitation_dialog|failed"),
|
2017-05-19 13:53:11 +01:00
|
|
|
|
description: err.toString(),
|
2017-03-09 17:03:57 +00:00
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2017-05-19 13:53:11 +01:00
|
|
|
|
},
|
2017-03-09 17:03:57 +00:00
|
|
|
|
});
|
|
|
|
|
|
break;
|
2019-04-17 10:57:45 +02:00
|
|
|
|
case "view_user_info":
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.viewUser(payload.userId, payload.subAction);
|
2019-04-17 10:57:45 +02:00
|
|
|
|
break;
|
2022-05-26 10:19:00 +01:00
|
|
|
|
case "MatrixActions.RoomState.events": {
|
|
|
|
|
|
const event = (payload as IRoomStateEventsActionPayload).event;
|
|
|
|
|
|
if (
|
|
|
|
|
|
event.getType() === EventType.RoomCanonicalAlias &&
|
|
|
|
|
|
event.getRoomId() === this.state.currentRoomId
|
|
|
|
|
|
) {
|
|
|
|
|
|
// re-view the current room so we can update alias/id in the URL properly
|
|
|
|
|
|
this.viewRoom({
|
|
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
|
|
room_id: this.state.currentRoomId,
|
|
|
|
|
|
metricsTrigger: undefined, // room doesn't change
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2021-11-25 17:49:43 -03:00
|
|
|
|
case Action.ViewRoom: {
|
2016-06-14 12:56:37 +01: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.
|
2022-02-10 14:29:55 +00:00
|
|
|
|
const promise = this.viewRoom(payload as ViewRoomPayload);
|
2020-02-28 23:12:10 +00:00
|
|
|
|
if (payload.deferred_action) {
|
|
|
|
|
|
promise.then(() => {
|
|
|
|
|
|
dis.dispatch(payload.deferred_action);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2015-06-12 18:01:38 +01:00
|
|
|
|
break;
|
2020-02-28 23:12:10 +00:00
|
|
|
|
}
|
2022-10-11 11:10:55 +02:00
|
|
|
|
case Action.ViewUserDeviceSettings: {
|
2023-05-26 13:58:28 +12:00
|
|
|
|
viewUserDeviceSettings();
|
2022-10-11 11:10:55 +02:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2020-05-13 21:07:19 -06:00
|
|
|
|
case Action.ViewUserSettings: {
|
2020-06-08 08:20:15 -06:00
|
|
|
|
const tabPayload = payload as OpenToTabPayload;
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(
|
|
|
|
|
|
UserSettingsDialog,
|
2024-06-06 09:57:28 +01:00
|
|
|
|
{ ...payload.props, initialTabId: tabPayload.initialTabId as UserTab, sdkContext: this.stores },
|
2023-03-10 14:55:06 +00:00
|
|
|
|
/*className=*/ undefined,
|
2020-08-29 01:11:08 +01:00
|
|
|
|
/*isPriority=*/ false,
|
|
|
|
|
|
/*isStatic=*/ true,
|
|
|
|
|
|
);
|
2019-02-04 13:25:26 -07:00
|
|
|
|
|
2019-02-11 13:31:27 +00:00
|
|
|
|
// View the welcome or home page if we need something to look at
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.viewSomethingBehindModal();
|
2015-09-18 18:39:16 +01:00
|
|
|
|
break;
|
2019-01-21 17:49:48 -07:00
|
|
|
|
}
|
2015-09-18 18:39:16 +01:00
|
|
|
|
case "view_create_room":
|
2022-04-01 10:36:10 -04:00
|
|
|
|
this.createRoom(payload.public, payload.defaultName, payload.type);
|
2022-02-18 09:43:19 +01:00
|
|
|
|
|
|
|
|
|
|
// View the welcome or home page if we need something to look at
|
|
|
|
|
|
this.viewSomethingBehindModal();
|
2015-09-18 18:39:16 +01:00
|
|
|
|
break;
|
2020-06-08 20:33:21 -06:00
|
|
|
|
case Action.ViewRoomDirectory: {
|
2022-11-22 15:05:09 +00:00
|
|
|
|
Modal.createDialog(
|
|
|
|
|
|
RovingSpotlightDialog,
|
|
|
|
|
|
{
|
2021-11-30 18:08:46 +00:00
|
|
|
|
initialText: payload.initialText,
|
2022-11-22 15:05:09 +00:00
|
|
|
|
initialFilter: Filter.PublicRooms,
|
|
|
|
|
|
},
|
|
|
|
|
|
"mx_SpotlightDialog_wrapper",
|
|
|
|
|
|
false,
|
|
|
|
|
|
true,
|
|
|
|
|
|
);
|
2019-01-29 23:25:07 -07:00
|
|
|
|
|
2019-02-11 13:31:27 +00:00
|
|
|
|
// View the welcome or home page if we need something to look at
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.viewSomethingBehindModal();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
break;
|
2019-01-29 15:40:19 +01:00
|
|
|
|
}
|
2019-02-07 16:25:09 +00:00
|
|
|
|
case "view_welcome_page":
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.viewWelcome();
|
2019-02-07 16:25:09 +00:00
|
|
|
|
break;
|
2022-02-22 11:04:27 +01:00
|
|
|
|
case Action.ViewHomePage:
|
2020-11-02 17:24:47 +00:00
|
|
|
|
this.viewHome(payload.justRegistered);
|
2016-11-13 14:10:46 +00:00
|
|
|
|
break;
|
2022-02-22 11:04:27 +01:00
|
|
|
|
case Action.ViewStartChatOrReuse:
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.chatCreateOrReuse(payload.user_id);
|
2017-06-01 14:16:25 +01:00
|
|
|
|
break;
|
2016-09-05 10:29:03 +01:00
|
|
|
|
case "view_create_chat":
|
2020-11-11 13:36:17 +00:00
|
|
|
|
showStartChatInviteDialog(payload.initialText || "");
|
2022-02-18 09:43:19 +01:00
|
|
|
|
|
|
|
|
|
|
// View the welcome or home page if we need something to look at
|
|
|
|
|
|
this.viewSomethingBehindModal();
|
2016-09-01 16:45:24 +01:00
|
|
|
|
break;
|
2021-09-29 14:04:02 +01:00
|
|
|
|
case "view_invite": {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const room = MatrixClientPeg.safeGet().getRoom(payload.roomId);
|
2021-09-29 14:04:02 +01:00
|
|
|
|
if (room?.isSpaceRoom()) {
|
|
|
|
|
|
showSpaceInvite(room);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showRoomInviteDialog(payload.roomId);
|
|
|
|
|
|
}
|
2016-09-13 14:28:03 +01:00
|
|
|
|
break;
|
2021-09-29 14:04:02 +01:00
|
|
|
|
}
|
2019-11-25 16:51:48 -07:00
|
|
|
|
case "view_last_screen":
|
|
|
|
|
|
// This function does what we want, despite the name. The idea is that it shows
|
|
|
|
|
|
// the last room we were looking at or some reasonable default/guess. We don't
|
|
|
|
|
|
// have to worry about email invites or similar being re-triggered because the
|
|
|
|
|
|
// function will have cleared that state and not execute that path.
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.showScreenAfterLogin();
|
2019-11-25 16:51:48 -07:00
|
|
|
|
break;
|
2015-10-11 13:49:44 +01:00
|
|
|
|
case "hide_left_panel":
|
|
|
|
|
|
this.setState(
|
|
|
|
|
|
{
|
2017-08-25 12:10:13 +01:00
|
|
|
|
collapseLhs: true,
|
2020-07-16 06:05:53 +01:00
|
|
|
|
},
|
|
|
|
|
|
() => {
|
|
|
|
|
|
this.state.resizeNotifier.notifyLeftHandleResized();
|
2015-10-11 13:49:44 +01:00
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "show_left_panel":
|
|
|
|
|
|
this.setState(
|
|
|
|
|
|
{
|
2017-08-25 12:10:13 +01:00
|
|
|
|
collapseLhs: false,
|
2020-07-16 06:05:53 +01:00
|
|
|
|
},
|
|
|
|
|
|
() => {
|
|
|
|
|
|
this.state.resizeNotifier.notifyLeftHandleResized();
|
2015-10-11 13:49:44 +01:00
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
break;
|
2020-12-23 19:02:01 +00:00
|
|
|
|
case Action.OpenDialPad:
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(DialPadModal, {}, "mx_Dialog_dialPadWrapper");
|
2020-12-23 19:02:01 +00:00
|
|
|
|
break;
|
2022-05-26 09:56:53 +01:00
|
|
|
|
case Action.OnLoggedIn:
|
2023-06-15 15:11:49 +01:00
|
|
|
|
this.stores.client = MatrixClientPeg.safeGet();
|
2020-01-15 21:13:56 +00:00
|
|
|
|
if (
|
2021-02-05 17:18:13 +00:00
|
|
|
|
// Skip this handling for token login as that always calls onLoggedIn itself
|
|
|
|
|
|
!this.tokenLogin &&
|
2020-01-15 21:13:56 +00:00
|
|
|
|
!Lifecycle.isSoftLogout() &&
|
2020-04-23 10:12:50 +01:00
|
|
|
|
this.state.view !== Views.LOGIN &&
|
|
|
|
|
|
this.state.view !== Views.REGISTER &&
|
|
|
|
|
|
this.state.view !== Views.COMPLETE_SECURITY &&
|
2022-07-13 15:43:44 +02:00
|
|
|
|
this.state.view !== Views.E2E_SETUP &&
|
|
|
|
|
|
this.state.view !== Views.USE_CASE_SELECTION
|
2020-01-15 21:13:56 +00:00
|
|
|
|
) {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.onLoggedIn();
|
2019-07-03 16:46:37 -06:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "on_client_not_viable":
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.onSoftLogout();
|
2016-08-02 14:04:20 +01:00
|
|
|
|
break;
|
2022-05-26 09:56:53 +01:00
|
|
|
|
case Action.OnLoggedOut:
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.onLoggedOut();
|
2016-08-02 14:04:20 +01:00
|
|
|
|
break;
|
|
|
|
|
|
case "will_start_client":
|
2021-06-29 13:11:58 +01:00
|
|
|
|
this.setState({ ready: false }, () => {
|
2017-06-23 10:48:21 +01:00
|
|
|
|
// 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.
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.onWillStartClient();
|
2017-06-23 10:48:21 +01:00
|
|
|
|
});
|
2016-08-10 00:03:29 +01:00
|
|
|
|
break;
|
2017-11-04 20:13:23 -07:00
|
|
|
|
case "client_started":
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.onClientStarted();
|
2017-11-04 20:13:23 -07:00
|
|
|
|
break;
|
2017-06-16 16:12:52 +01:00
|
|
|
|
case "send_event":
|
|
|
|
|
|
this.onSendEvent(payload.room_id, payload.event);
|
|
|
|
|
|
break;
|
2018-02-08 22:51:07 +01:00
|
|
|
|
case "aria_hide_main_app":
|
|
|
|
|
|
this.setState({
|
|
|
|
|
|
hideToSRUsers: true,
|
|
|
|
|
|
});
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "aria_unhide_main_app":
|
|
|
|
|
|
this.setState({
|
|
|
|
|
|
hideToSRUsers: false,
|
|
|
|
|
|
});
|
|
|
|
|
|
break;
|
2021-12-06 09:39:33 +11:00
|
|
|
|
case Action.PseudonymousAnalyticsAccept:
|
2020-05-22 22:04:21 +01:00
|
|
|
|
hideAnalyticsToast();
|
2021-12-06 09:39:33 +11:00
|
|
|
|
SettingsStore.setValue("pseudonymousAnalyticsOptIn", null, SettingLevel.ACCOUNT, true);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case Action.PseudonymousAnalyticsReject:
|
|
|
|
|
|
hideAnalyticsToast();
|
|
|
|
|
|
SettingsStore.setValue("pseudonymousAnalyticsOptIn", null, SettingLevel.ACCOUNT, false);
|
2018-05-15 13:15:40 +01:00
|
|
|
|
break;
|
2022-07-23 14:13:49 +02:00
|
|
|
|
case Action.ShowThread: {
|
|
|
|
|
|
const { rootEvent, initialEvent, highlighted, scrollIntoView, push } = payload as ShowThreadPayload;
|
|
|
|
|
|
|
|
|
|
|
|
const threadViewCard = {
|
|
|
|
|
|
phase: RightPanelPhases.ThreadView,
|
|
|
|
|
|
state: {
|
|
|
|
|
|
threadHeadEvent: rootEvent,
|
|
|
|
|
|
initialEvent: initialEvent,
|
|
|
|
|
|
isInitialEventHighlighted: highlighted,
|
|
|
|
|
|
initialEventScrollIntoView: scrollIntoView,
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
if (push ?? false) {
|
|
|
|
|
|
RightPanelStore.instance.pushCard(threadViewCard);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
RightPanelStore.instance.setCards([{ phase: RightPanelPhases.ThreadPanel }, threadViewCard]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Focus the composer
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: Action.FocusSendMessageComposer,
|
|
|
|
|
|
context: TimelineRenderingType.Thread,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2023-08-21 10:39:20 +01:00
|
|
|
|
case Action.OpenSpotlight:
|
|
|
|
|
|
Modal.createDialog(
|
|
|
|
|
|
RovingSpotlightDialog,
|
|
|
|
|
|
{
|
|
|
|
|
|
initialText: payload.initialText,
|
|
|
|
|
|
initialFilter: payload.initialFilter,
|
|
|
|
|
|
},
|
|
|
|
|
|
"mx_SpotlightDialog_wrapper",
|
|
|
|
|
|
false,
|
|
|
|
|
|
true,
|
|
|
|
|
|
);
|
|
|
|
|
|
break;
|
2015-06-12 17:34:17 +01:00
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2015-06-12 17:34:17 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private setPage(pageType: PageType): void {
|
2015-12-10 21:53:14 +00:00
|
|
|
|
this.setState({
|
2015-12-14 11:07:59 +00:00
|
|
|
|
page_type: pageType,
|
2015-12-10 21:53:14 +00:00
|
|
|
|
});
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2015-12-10 21:53:14 +00:00
|
|
|
|
|
2024-09-13 12:12:04 +01:00
|
|
|
|
private async startRegistration(params: { [key: string]: string }, isMobileRegistration?: boolean): Promise<void> {
|
2024-09-20 12:24:39 +01:00
|
|
|
|
// If registration is disabled or mobile registration is requested but not enabled in settings redirect to the welcome screen
|
|
|
|
|
|
if (
|
|
|
|
|
|
!SettingsStore.getValue(UIFeature.Registration) ||
|
|
|
|
|
|
(isMobileRegistration && !SettingsStore.getValue("Registration.mobileRegistrationHelper"))
|
|
|
|
|
|
) {
|
2024-07-15 11:02:23 +01:00
|
|
|
|
this.showScreen("welcome");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
const newState: Partial<IState> = {
|
2020-04-23 10:12:50 +01:00
|
|
|
|
view: Views.REGISTER,
|
2018-02-07 15:51:03 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
2024-09-20 12:24:39 +01:00
|
|
|
|
if (isMobileRegistration && params.hs_url) {
|
2024-09-13 16:59:11 +01:00
|
|
|
|
try {
|
|
|
|
|
|
const config = await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(params.hs_url);
|
|
|
|
|
|
newState.serverConfig = config;
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
logger.warn("Failed to load hs_url param:", params.hs_url);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (params.client_secret && params.session_id && params.hs_url && params.is_url && params.sid) {
|
|
|
|
|
|
// Only honour params if they are all present, otherwise we reset
|
|
|
|
|
|
// HS and IS URLs when switching to registration.
|
2019-06-12 18:11:58 +01:00
|
|
|
|
newState.serverConfig = await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(
|
|
|
|
|
|
params.hs_url,
|
|
|
|
|
|
params.is_url,
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2021-10-19 09:43:34 +01:00
|
|
|
|
// If the hs url matches then take the hs name we know locally as it is likely prettier
|
2022-03-18 10:12:36 -06:00
|
|
|
|
const defaultConfig = SdkConfig.get("validated_server_config");
|
2021-10-19 09:43:34 +01:00
|
|
|
|
if (defaultConfig && defaultConfig.hsUrl === newState.serverConfig.hsUrl) {
|
|
|
|
|
|
newState.serverConfig.hsName = defaultConfig.hsName;
|
|
|
|
|
|
newState.serverConfig.hsNameIsDifferent = defaultConfig.hsNameIsDifferent;
|
|
|
|
|
|
newState.serverConfig.isDefault = defaultConfig.isDefault;
|
|
|
|
|
|
newState.serverConfig.isNameResolvable = defaultConfig.isNameResolvable;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-02-07 15:51:03 +00:00
|
|
|
|
newState.register_client_secret = params.client_secret;
|
|
|
|
|
|
newState.register_session_id = params.session_id;
|
|
|
|
|
|
newState.register_id_sid = params.sid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-20 12:24:39 +01:00
|
|
|
|
newState.isMobileRegistration = isMobileRegistration;
|
2024-09-13 12:12:04 +01:00
|
|
|
|
|
2018-02-07 15:51:03 +00:00
|
|
|
|
this.setStateForNewView(newState);
|
2020-01-31 13:18:01 +00:00
|
|
|
|
ThemeController.isLogin = true;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.themeWatcher.recheck();
|
2024-09-20 12:24:39 +01:00
|
|
|
|
this.notifyNewScreen(isMobileRegistration ? "mobile_register" : "register");
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2017-05-19 13:53:11 +01:00
|
|
|
|
|
2016-02-01 16:31:12 +00:00
|
|
|
|
// switch view to the given room
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private async viewRoom(roomInfo: ViewRoomPayload): Promise<void> {
|
2024-04-10 14:13:08 +01:00
|
|
|
|
this.focusNext = roomInfo.focusNext ?? "composer";
|
2019-07-23 09:13:51 +02:00
|
|
|
|
|
2017-06-07 22:41:02 +01:00
|
|
|
|
if (roomInfo.room_alias) {
|
2021-12-06 09:25:05 +00:00
|
|
|
|
logger.log(`Switching to room alias ${roomInfo.room_alias} at event ${roomInfo.event_id}`);
|
2017-06-07 22:41:02 +01:00
|
|
|
|
} else {
|
2021-12-06 09:25:05 +00:00
|
|
|
|
logger.log(`Switching to room id ${roomInfo.room_id} at event ${roomInfo.event_id}`);
|
2016-02-01 16:31:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-06 11:30:47 +01:00
|
|
|
|
// Wait for the first sync to complete so that if a room does have an alias,
|
|
|
|
|
|
// it would have been retrieved.
|
2017-04-06 11:44:15 +01:00
|
|
|
|
if (!this.firstSyncComplete) {
|
2017-04-06 11:30:47 +01:00
|
|
|
|
if (!this.firstSyncPromise) {
|
2021-10-15 16:31:29 +02:00
|
|
|
|
logger.warn("Cannot view a room before first sync. room_id:", roomInfo.room_id);
|
2017-04-06 11:30:47 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2021-12-06 09:25:05 +00:00
|
|
|
|
await this.firstSyncPromise.promise;
|
2017-04-06 11:30:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-28 09:45:36 +01:00
|
|
|
|
let presentedId = roomInfo.room_alias || roomInfo.room_id!;
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const room = MatrixClientPeg.safeGet().getRoom(roomInfo.room_id);
|
2021-12-06 09:25:05 +00:00
|
|
|
|
if (room) {
|
|
|
|
|
|
// Not all timeline events are decrypted ahead of time anymore
|
|
|
|
|
|
// Only the critical ones for a typical UI are
|
|
|
|
|
|
// This will start the decryption process for all events when a
|
|
|
|
|
|
// user views a room
|
|
|
|
|
|
room.decryptAllEvents();
|
|
|
|
|
|
const theAlias = Rooms.getDisplayAliasForRoom(room);
|
|
|
|
|
|
if (theAlias) {
|
|
|
|
|
|
presentedId = theAlias;
|
|
|
|
|
|
// Store display alias of the presented room in cache to speed future
|
|
|
|
|
|
// navigation.
|
|
|
|
|
|
storeRoomAliasInCache(theAlias, room.roomId);
|
2015-12-10 16:26:36 +00:00
|
|
|
|
}
|
2016-01-08 03:22:38 +00:00
|
|
|
|
|
2021-12-06 09:25:05 +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.
|
2022-05-26 10:19:00 +01:00
|
|
|
|
localStorage?.setItem("mx_last_room_id", room.roomId);
|
2021-12-06 09:25:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If we are redirecting to a Room Alias and it is for the room we already showing then replace history item
|
2022-07-20 09:26:25 +02:00
|
|
|
|
let replaceLast = presentedId[0] === "#" && roomInfo.room_id === this.state.currentRoomId;
|
|
|
|
|
|
|
|
|
|
|
|
if (isLocalRoom(this.state.currentRoomId)) {
|
|
|
|
|
|
// Replace local room history items
|
|
|
|
|
|
replaceLast = true;
|
|
|
|
|
|
}
|
2021-12-06 09:25:05 +00:00
|
|
|
|
|
|
|
|
|
|
if (roomInfo.room_id === this.state.currentRoomId) {
|
|
|
|
|
|
// if we are re-viewing the same room then copy any state we already know
|
|
|
|
|
|
roomInfo.threepid_invite = roomInfo.threepid_invite ?? this.state.threepidInvite;
|
|
|
|
|
|
roomInfo.oob_data = roomInfo.oob_data ?? this.state.roomOobData;
|
|
|
|
|
|
roomInfo.forceTimeline = roomInfo.forceTimeline ?? this.state.forceTimeline;
|
|
|
|
|
|
roomInfo.justCreatedOpts = roomInfo.justCreatedOpts ?? this.state.roomJustCreatedOpts;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (roomInfo.event_id && roomInfo.highlighted) {
|
|
|
|
|
|
presentedId += "/" + roomInfo.event_id;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.setState(
|
|
|
|
|
|
{
|
|
|
|
|
|
view: Views.LOGGED_IN,
|
2023-03-10 14:55:06 +00:00
|
|
|
|
currentRoomId: roomInfo.room_id ?? null,
|
2021-12-06 09:25:05 +00:00
|
|
|
|
page_type: PageType.RoomView,
|
|
|
|
|
|
threepidInvite: roomInfo.threepid_invite,
|
|
|
|
|
|
roomOobData: roomInfo.oob_data,
|
|
|
|
|
|
forceTimeline: roomInfo.forceTimeline,
|
|
|
|
|
|
ready: true,
|
|
|
|
|
|
roomJustCreatedOpts: roomInfo.justCreatedOpts,
|
|
|
|
|
|
},
|
|
|
|
|
|
() => {
|
2023-01-16 09:49:41 +00:00
|
|
|
|
ThemeController.isLogin = false;
|
|
|
|
|
|
this.themeWatcher.recheck();
|
2021-12-06 09:25:05 +00:00
|
|
|
|
this.notifyNewScreen("room/" + presentedId, replaceLast);
|
2017-04-06 11:30:47 +01:00
|
|
|
|
},
|
|
|
|
|
|
);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2015-12-10 16:26:36 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private viewSomethingBehindModal(): void {
|
2020-04-23 10:12:50 +01:00
|
|
|
|
if (this.state.view !== Views.LOGGED_IN) {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.viewWelcome();
|
2019-02-11 13:31:27 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-03-22 17:07:37 -06:00
|
|
|
|
if (!this.state.currentRoomId && !this.state.currentUserId) {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.viewHome();
|
2019-02-11 13:31:27 +00:00
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2019-02-11 13:31:27 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private viewWelcome(): void {
|
2021-03-12 15:01:05 -07:00
|
|
|
|
if (shouldUseLoginForWelcome(SdkConfig.get())) {
|
|
|
|
|
|
return this.viewLogin();
|
|
|
|
|
|
}
|
2019-02-07 16:25:09 +00:00
|
|
|
|
this.setStateForNewView({
|
2020-04-23 10:12:50 +01:00
|
|
|
|
view: Views.WELCOME,
|
2019-02-07 16:25:09 +00:00
|
|
|
|
});
|
|
|
|
|
|
this.notifyNewScreen("welcome");
|
2020-01-31 13:18:01 +00:00
|
|
|
|
ThemeController.isLogin = true;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.themeWatcher.recheck();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2019-02-07 16:25:09 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private viewLogin(otherState?: any): void {
|
2021-03-12 15:01:05 -07:00
|
|
|
|
this.setStateForNewView({
|
|
|
|
|
|
view: Views.LOGIN,
|
|
|
|
|
|
...otherState,
|
|
|
|
|
|
});
|
|
|
|
|
|
this.notifyNewScreen("login");
|
|
|
|
|
|
ThemeController.isLogin = true;
|
|
|
|
|
|
this.themeWatcher.recheck();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private viewHome(justRegistered = false): void {
|
2019-01-03 14:22:16 -07:00
|
|
|
|
// The home page requires the "logged in" view, so we'll set that.
|
2018-12-20 17:26:13 -07:00
|
|
|
|
this.setStateForNewView({
|
2020-04-23 10:12:50 +01:00
|
|
|
|
view: Views.LOGGED_IN,
|
2020-11-02 17:24:47 +00:00
|
|
|
|
justRegistered,
|
2021-08-31 17:14:50 +01:00
|
|
|
|
currentRoomId: null,
|
2018-12-20 17:26:13 -07:00
|
|
|
|
});
|
2021-09-27 12:40:34 +02:00
|
|
|
|
this.setPage(PageType.HomePage);
|
2018-05-29 13:16:39 +01:00
|
|
|
|
this.notifyNewScreen("home");
|
2020-01-31 13:18:01 +00:00
|
|
|
|
ThemeController.isLogin = false;
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.themeWatcher.recheck();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2018-05-29 13:16:39 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private viewUser(userId: string, subAction: string): void {
|
2019-04-17 10:57:45 +02:00
|
|
|
|
// Wait for the first sync so that `getRoom` gives us a room object if it's
|
|
|
|
|
|
// in the sync response
|
|
|
|
|
|
const waitForSync = this.firstSyncPromise ? this.firstSyncPromise.promise : Promise.resolve();
|
2019-04-17 18:23:49 +02:00
|
|
|
|
waitForSync.then(() => {
|
2019-04-17 18:26:07 +02:00
|
|
|
|
if (subAction === "chat") {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.chatCreateOrReuse(userId);
|
2019-04-17 10:57:45 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.notifyNewScreen("user/" + userId);
|
2021-06-29 13:11:58 +01:00
|
|
|
|
this.setState({ currentUserId: userId });
|
2021-09-27 12:40:34 +02:00
|
|
|
|
this.setPage(PageType.UserView);
|
2019-04-17 10:57:45 +02:00
|
|
|
|
});
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2019-04-17 10:57:45 +02:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType): Promise<void> {
|
2022-06-14 17:51:51 +01:00
|
|
|
|
const modal = Modal.createDialog(CreateRoomDialog, {
|
2022-04-01 10:36:10 -04:00
|
|
|
|
type,
|
2021-05-19 19:20:58 +01:00
|
|
|
|
defaultPublic,
|
|
|
|
|
|
defaultName,
|
|
|
|
|
|
});
|
2019-08-09 16:47:22 +01:00
|
|
|
|
|
2020-01-23 13:54:28 +00:00
|
|
|
|
const [shouldCreate, opts] = await modal.finished;
|
2019-08-09 16:47:22 +01:00
|
|
|
|
if (shouldCreate) {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
createRoom(MatrixClientPeg.safeGet(), opts!);
|
2019-08-09 16:47:22 +01:00
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2017-06-05 17:45:01 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private chatCreateOrReuse(userId: string): void {
|
2017-06-02 11:42:47 +01:00
|
|
|
|
// Use a deferred action to reshow the dialog once the user has registered
|
2023-06-15 15:11:49 +01:00
|
|
|
|
if (MatrixClientPeg.safeGet().isGuest()) {
|
2024-02-12 15:04:13 +00:00
|
|
|
|
dis.dispatch<DoAfterSyncPreparedPayload<ViewStartChatOrReusePayload>>({
|
|
|
|
|
|
action: Action.DoAfterSyncPrepared,
|
|
|
|
|
|
deferred_action: {
|
|
|
|
|
|
action: Action.ViewStartChatOrReuse,
|
|
|
|
|
|
user_id: userId,
|
2020-02-28 10:47:23 +00:00
|
|
|
|
},
|
2017-06-01 14:16:25 +01:00
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-08-07 12:13:59 -06:00
|
|
|
|
// TODO: Immutable DMs replaces this
|
|
|
|
|
|
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const client = MatrixClientPeg.safeGet();
|
2023-01-30 10:54:05 +01:00
|
|
|
|
const dmRoom = findDMForUser(client, userId);
|
2019-08-07 12:13:59 -06:00
|
|
|
|
|
2023-01-30 10:54:05 +01:00
|
|
|
|
if (dmRoom) {
|
2022-02-10 14:29:55 +00:00
|
|
|
|
dis.dispatch<ViewRoomPayload>({
|
2021-11-25 17:49:43 -03:00
|
|
|
|
action: Action.ViewRoom,
|
2023-01-30 10:54:05 +01:00
|
|
|
|
room_id: dmRoom.roomId,
|
2022-02-17 18:03:27 +00:00
|
|
|
|
metricsTrigger: "MessageUser",
|
2019-08-07 12:13:59 -06:00
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "start_chat",
|
|
|
|
|
|
user_id: userId,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2017-06-01 14:16:25 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private leaveRoomWarnings(roomId: string): JSX.Element[] {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const roomToLeave = MatrixClientPeg.safeGet().getRoom(roomId);
|
2022-03-22 17:07:37 -06:00
|
|
|
|
const isSpace = roomToLeave?.isSpaceRoom();
|
2018-01-19 22:27:48 +00:00
|
|
|
|
// Show a warning if there are additional complications.
|
2023-01-12 13:25:14 +00:00
|
|
|
|
const warnings: JSX.Element[] = [];
|
2020-11-10 15:04:01 -06:00
|
|
|
|
|
2023-03-10 14:55:06 +00:00
|
|
|
|
const memberCount = roomToLeave?.currentState.getJoinedMemberCount();
|
2020-11-10 15:04:01 -06:00
|
|
|
|
if (memberCount === 1) {
|
2020-11-18 13:54:49 -06:00
|
|
|
|
warnings.push(
|
2024-03-06 23:34:14 +00:00
|
|
|
|
<strong className="warning" key="only_member_warning">
|
2021-07-19 22:43:11 +01:00
|
|
|
|
{" " /* Whitespace, otherwise the sentences get smashed together */}
|
2023-10-02 16:13:00 +05:30
|
|
|
|
{_t("leave_room_dialog|last_person_warning")}
|
2024-03-06 23:34:14 +00:00
|
|
|
|
</strong>,
|
2020-11-18 13:54:49 -06:00
|
|
|
|
);
|
2020-11-10 15:04:01 -06:00
|
|
|
|
|
|
|
|
|
|
return warnings;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-10 14:55:06 +00:00
|
|
|
|
const joinRules = roomToLeave?.currentState.getStateEvents("m.room.join_rules", "");
|
2018-01-19 22:27:48 +00:00
|
|
|
|
if (joinRules) {
|
|
|
|
|
|
const rule = joinRules.getContent().join_rule;
|
|
|
|
|
|
if (rule !== "public") {
|
|
|
|
|
|
warnings.push(
|
2024-03-06 23:34:14 +00:00
|
|
|
|
<strong className="warning" key="non_public_warning">
|
2021-07-19 22:43:11 +01:00
|
|
|
|
{" " /* Whitespace, otherwise the sentences get smashed together */}
|
2021-03-02 09:55:55 +00:00
|
|
|
|
{isSpace
|
2023-10-02 16:13:00 +05:30
|
|
|
|
? _t("leave_room_dialog|space_rejoin_warning")
|
|
|
|
|
|
: _t("leave_room_dialog|room_rejoin_warning")}
|
2024-03-06 23:34:14 +00:00
|
|
|
|
</strong>,
|
2018-01-19 22:27:48 +00:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-10-19 12:51:31 +02:00
|
|
|
|
|
|
|
|
|
|
const client = MatrixClientPeg.get();
|
2024-03-21 11:39:47 +00:00
|
|
|
|
if (client && roomToLeave) {
|
|
|
|
|
|
const plEvent = roomToLeave.currentState.getStateEvents(EventType.RoomPowerLevels, "");
|
|
|
|
|
|
const plContent = plEvent ? plEvent.getContent() : {};
|
|
|
|
|
|
const userLevels = plContent.users || {};
|
|
|
|
|
|
const currentUserLevel = userLevels[client.getUserId()!];
|
|
|
|
|
|
const userLevelValues = Object.values(userLevels);
|
|
|
|
|
|
if (userLevelValues.every((x) => typeof x === "number")) {
|
|
|
|
|
|
const maxUserLevel = Math.max(...(userLevelValues as number[]));
|
|
|
|
|
|
// If the user is the only user with highest power level
|
|
|
|
|
|
if (
|
|
|
|
|
|
maxUserLevel === currentUserLevel &&
|
|
|
|
|
|
userLevelValues.lastIndexOf(maxUserLevel) == userLevelValues.indexOf(maxUserLevel)
|
|
|
|
|
|
) {
|
2024-03-21 11:54:02 +00:00
|
|
|
|
const warning =
|
|
|
|
|
|
maxUserLevel >= 100
|
|
|
|
|
|
? _t("leave_room_dialog|room_leave_admin_warning")
|
|
|
|
|
|
: _t("leave_room_dialog|room_leave_mod_warning");
|
2024-03-21 11:39:47 +00:00
|
|
|
|
warnings.push(
|
2024-03-21 11:54:02 +00:00
|
|
|
|
<strong className="warning" key="last_admin_warning">
|
2024-03-21 11:39:47 +00:00
|
|
|
|
{" " /* Whitespace, otherwise the sentences get smashed together */}
|
2024-03-21 11:54:02 +00:00
|
|
|
|
{warning}
|
|
|
|
|
|
</strong>,
|
2024-03-21 11:39:47 +00:00
|
|
|
|
);
|
|
|
|
|
|
}
|
2022-10-19 12:51:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-01-19 22:27:48 +00:00
|
|
|
|
return warnings;
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2018-01-19 22:27:48 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private leaveRoom(roomId: string): void {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const cli = MatrixClientPeg.safeGet();
|
2023-05-23 16:24:12 +01:00
|
|
|
|
const roomToLeave = cli.getRoom(roomId);
|
2020-04-22 13:08:33 +01:00
|
|
|
|
const warnings = this.leaveRoomWarnings(roomId);
|
2018-01-19 22:27:48 +00:00
|
|
|
|
|
2022-03-22 17:07:37 -06:00
|
|
|
|
const isSpace = roomToLeave?.isSpaceRoom();
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(QuestionDialog, {
|
2023-10-03 19:17:26 +01:00
|
|
|
|
title: isSpace ? _t("space|leave_dialog_action") : _t("action|leave_room"),
|
2017-06-02 10:47:08 +01:00
|
|
|
|
description: (
|
|
|
|
|
|
<span>
|
2021-03-02 09:55:55 +00:00
|
|
|
|
{isSpace
|
2023-10-02 16:13:00 +05:30
|
|
|
|
? _t("leave_room_dialog|leave_space_question", {
|
2023-09-04 19:41:39 +01:00
|
|
|
|
spaceName: roomToLeave?.name ?? _t("common|unnamed_space"),
|
2021-06-29 13:42:19 +01:00
|
|
|
|
})
|
2023-10-02 16:13:00 +05:30
|
|
|
|
: _t("leave_room_dialog|leave_room_question", {
|
2023-09-04 19:41:39 +01:00
|
|
|
|
roomName: roomToLeave?.name ?? _t("common|unnamed_room"),
|
2023-03-10 14:55:06 +00:00
|
|
|
|
})}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
{warnings}
|
2017-06-02 10:47:08 +01:00
|
|
|
|
</span>
|
|
|
|
|
|
),
|
2023-08-22 20:55:15 +01:00
|
|
|
|
button: _t("action|leave"),
|
2024-03-21 11:54:02 +00:00
|
|
|
|
danger: warnings.length > 0,
|
2023-05-23 16:24:12 +01:00
|
|
|
|
onFinished: async (shouldLeave) => {
|
2017-05-19 13:53:11 +01:00
|
|
|
|
if (shouldLeave) {
|
2023-05-23 16:24:12 +01:00
|
|
|
|
await leaveRoomBehaviour(cli, roomId);
|
2017-05-19 13:53:11 +01:00
|
|
|
|
|
2022-02-22 11:04:27 +01:00
|
|
|
|
dis.dispatch<AfterLeaveRoomPayload>({
|
|
|
|
|
|
action: Action.AfterLeaveRoom,
|
2021-03-02 10:34:28 +00:00
|
|
|
|
room_id: roomId,
|
|
|
|
|
|
});
|
2017-05-19 13:53:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2016-08-10 00:03:29 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private forgetRoom(roomId: string): void {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const room = MatrixClientPeg.safeGet().getRoom(roomId);
|
|
|
|
|
|
MatrixClientPeg.safeGet()
|
2020-07-13 16:35:03 +01:00
|
|
|
|
.forget(roomId)
|
|
|
|
|
|
.then(() => {
|
2020-12-03 11:15:55 +00:00
|
|
|
|
// Switch to home page if we're currently viewing the forgotten room
|
2020-07-13 16:35:03 +01:00
|
|
|
|
if (this.state.currentRoomId === roomId) {
|
2022-02-22 11:04:27 +01:00
|
|
|
|
dis.dispatch({ action: Action.ViewHomePage });
|
2020-07-13 16:35:03 +01:00
|
|
|
|
}
|
2021-03-18 23:28:59 -06:00
|
|
|
|
|
|
|
|
|
|
// We have to manually update the room list because the forgotten room will not
|
|
|
|
|
|
// be notified to us, therefore the room list will have no other way of knowing
|
|
|
|
|
|
// the room is forgotten.
|
2023-04-20 09:49:10 +01:00
|
|
|
|
if (room) RoomListStore.instance.manualRoomUpdate(room, RoomUpdateCause.RoomRemoved);
|
2020-07-13 17:01:50 +01:00
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
2023-10-03 19:17:26 +01:00
|
|
|
|
const errCode = err.errcode || _td("error|unknown_error_code");
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(ErrorDialog, {
|
2023-10-02 16:13:00 +05:30
|
|
|
|
title: _t("error_dialog|forget_room_failed", { errCode }),
|
2023-09-22 16:39:40 +01:00
|
|
|
|
description: err && err.message ? err.message : _t("invite|failed_generic"),
|
2022-12-12 12:24:14 +01:00
|
|
|
|
});
|
2020-07-13 16:35:03 +01:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private async copyRoom(roomId: string): Promise<void> {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const roomLink = makeRoomPermalink(MatrixClientPeg.safeGet(), roomId);
|
2021-07-14 14:58:18 +01:00
|
|
|
|
const success = await copyPlaintext(roomLink);
|
|
|
|
|
|
if (!success) {
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(ErrorDialog, {
|
2023-10-02 16:13:00 +05:30
|
|
|
|
title: _t("error_dialog|copy_room_link_failed|title"),
|
|
|
|
|
|
description: _t("error_dialog|copy_room_link_failed|description"),
|
2021-07-14 14:58:18 +01:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-02 19:05:05 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Called when a new logged in session has started
|
|
|
|
|
|
*/
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private async onLoggedIn(): Promise<void> {
|
2020-02-21 14:54:56 +00:00
|
|
|
|
ThemeController.isLogin = false;
|
2020-04-30 17:41:14 +01:00
|
|
|
|
this.themeWatcher.recheck();
|
2022-07-13 15:43:44 +02:00
|
|
|
|
StorageManager.tryPersistStorage();
|
|
|
|
|
|
|
|
|
|
|
|
if (MatrixClientPeg.currentUserIsJustRegistered() && SettingsStore.getValue("FTUE.useCaseSelection") === null) {
|
|
|
|
|
|
this.setStateForNewView({ view: Views.USE_CASE_SELECTION });
|
|
|
|
|
|
|
|
|
|
|
|
// Listen to changes in settings and hide the use case screen if appropriate - this is necessary because
|
|
|
|
|
|
// account settings can still be changing at this point in app init (due to the initial sync being cached,
|
|
|
|
|
|
// then subsequent syncs being received from the server)
|
|
|
|
|
|
//
|
|
|
|
|
|
// This seems unlikely for something that should happen directly after registration, but if a user does
|
|
|
|
|
|
// their initial login on another device/browser than they registered on, we want to avoid asking this
|
|
|
|
|
|
// question twice
|
|
|
|
|
|
//
|
|
|
|
|
|
// initPosthogAnalyticsToast pioneered this technique, we’re just reusing it here.
|
|
|
|
|
|
SettingsStore.watchSetting(
|
|
|
|
|
|
"FTUE.useCaseSelection",
|
|
|
|
|
|
null,
|
|
|
|
|
|
(originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => {
|
|
|
|
|
|
if (newValue !== null && this.state.view === Views.USE_CASE_SELECTION) {
|
|
|
|
|
|
this.onShowPostLoginScreen();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return this.onShowPostLoginScreen();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private async onShowPostLoginScreen(useCase?: UseCase): Promise<void> {
|
2022-07-13 15:43:44 +02:00
|
|
|
|
if (useCase) {
|
|
|
|
|
|
PosthogAnalytics.instance.setProperty("ftueUseCaseSelection", useCase);
|
|
|
|
|
|
SettingsStore.setValue("FTUE.useCaseSelection", null, SettingLevel.ACCOUNT, useCase);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-04-23 10:12:50 +01:00
|
|
|
|
this.setStateForNewView({ view: Views.LOGGED_IN });
|
2020-01-18 23:23:46 +00:00
|
|
|
|
// If a specific screen is set to be shown after login, show that above
|
|
|
|
|
|
// all else, as it probably means the user clicked on something already.
|
2023-03-10 14:55:06 +00:00
|
|
|
|
if (this.screenAfterLogin?.screen) {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.showScreen(this.screenAfterLogin.screen, this.screenAfterLogin.params);
|
2023-03-10 14:55:06 +00:00
|
|
|
|
this.screenAfterLogin = undefined;
|
2020-01-18 23:23:46 +00:00
|
|
|
|
} else if (MatrixClientPeg.currentUserIsJustRegistered()) {
|
2019-06-14 15:31:19 +01:00
|
|
|
|
MatrixClientPeg.setJustRegisteredUserId(null);
|
2017-05-26 11:46:33 +01:00
|
|
|
|
|
2024-02-12 15:04:13 +00:00
|
|
|
|
if (ThreepidInviteStore.instance.pickBestInvite()) {
|
2020-09-11 20:20:33 -06:00
|
|
|
|
// The user has a 3pid invite pending - show them that
|
|
|
|
|
|
const threepidInvite = ThreepidInviteStore.instance.pickBestInvite();
|
|
|
|
|
|
|
|
|
|
|
|
// HACK: This is a pretty brutal way of threading the invite back through
|
|
|
|
|
|
// our systems, but it's the safest we have for now.
|
|
|
|
|
|
const params = ThreepidInviteStore.instance.translateToWireFormat(threepidInvite);
|
2021-06-29 13:11:58 +01:00
|
|
|
|
this.showScreen(`room/${threepidInvite.roomId}`, params);
|
2019-06-14 16:04:09 +01:00
|
|
|
|
} else {
|
|
|
|
|
|
// The user has just logged in after registering,
|
|
|
|
|
|
// so show the homepage.
|
2022-02-22 11:04:27 +01:00
|
|
|
|
dis.dispatch<ViewHomePagePayload>({ action: Action.ViewHomePage, justRegistered: true });
|
2017-05-12 17:39:38 +01:00
|
|
|
|
}
|
2017-03-15 12:02:08 +00:00
|
|
|
|
} else {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.showScreenAfterLogin();
|
2017-03-15 12:02:08 +00:00
|
|
|
|
}
|
2020-02-20 00:38:08 +00:00
|
|
|
|
|
2022-03-18 10:12:36 -06:00
|
|
|
|
if (SdkConfig.get("mobile_guide_toast")) {
|
2021-01-28 17:21:36 +00:00
|
|
|
|
// The toast contains further logic to detect mobile platforms,
|
|
|
|
|
|
// check if it has been dismissed before, etc.
|
|
|
|
|
|
showMobileGuideToast();
|
|
|
|
|
|
}
|
2022-11-09 10:50:01 +00:00
|
|
|
|
|
|
|
|
|
|
const userNotice = SdkConfig.get("user_notice");
|
|
|
|
|
|
if (userNotice) {
|
|
|
|
|
|
const key = "user_notice_" + userNotice.title;
|
|
|
|
|
|
if (!userNotice.show_once || !localStorage.getItem(key)) {
|
|
|
|
|
|
ToastStore.sharedInstance().addOrReplaceToast({
|
|
|
|
|
|
key,
|
|
|
|
|
|
title: userNotice.title,
|
|
|
|
|
|
props: {
|
|
|
|
|
|
description: <Linkify>{userNotice.description}</Linkify>,
|
2024-07-30 13:57:15 +01:00
|
|
|
|
primaryLabel: _t("action|ok"),
|
|
|
|
|
|
onPrimaryClick: () => {
|
2022-11-09 10:50:01 +00:00
|
|
|
|
ToastStore.sharedInstance().dismissToast(key);
|
|
|
|
|
|
localStorage.setItem(key, "1");
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
component: GenericToast,
|
|
|
|
|
|
className: "mx_AnalyticsToast",
|
|
|
|
|
|
priority: 100,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2017-03-15 12:02:08 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private initPosthogAnalyticsToast(): void {
|
2021-12-06 09:39:33 +11:00
|
|
|
|
// Show the analytics toast if necessary
|
|
|
|
|
|
if (SettingsStore.getValue("pseudonymousAnalyticsOptIn") === null) {
|
2022-06-14 17:51:51 +01:00
|
|
|
|
showAnalyticsToast();
|
2021-12-06 09:39:33 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Listen to changes in settings and show the toast if appropriate - this is necessary because account
|
|
|
|
|
|
// settings can still be changing at this point in app init (due to the initial sync being cached, then
|
|
|
|
|
|
// subsequent syncs being received from the server)
|
|
|
|
|
|
SettingsStore.watchSetting(
|
|
|
|
|
|
"pseudonymousAnalyticsOptIn",
|
|
|
|
|
|
null,
|
|
|
|
|
|
(originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => {
|
|
|
|
|
|
if (newValue === null) {
|
2022-06-14 17:51:51 +01:00
|
|
|
|
showAnalyticsToast();
|
2021-12-06 09:39:33 +11:00
|
|
|
|
} else {
|
|
|
|
|
|
// It's possible for the value to change if a cached sync loads at page load, but then network
|
|
|
|
|
|
// sync contains a new value of the flag with it set to false (e.g. another device set it since last
|
|
|
|
|
|
// loading the page); so hide the toast.
|
|
|
|
|
|
// (this flipping usually happens before first render so the user won't notice it; anyway flicker
|
|
|
|
|
|
// on/off is probably better than showing the toast again when the user already dismissed it)
|
|
|
|
|
|
hideAnalyticsToast();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private showScreenAfterLogin(): void {
|
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
|
2020-04-22 13:08:33 +01:00
|
|
|
|
if (this.screenAfterLogin && this.screenAfterLogin.screen) {
|
|
|
|
|
|
this.showScreen(this.screenAfterLogin.screen, this.screenAfterLogin.params);
|
2023-03-10 14:55:06 +00:00
|
|
|
|
this.screenAfterLogin = undefined;
|
2017-04-06 11:30:47 +01:00
|
|
|
|
} else if (localStorage && localStorage.getItem("mx_last_room_id")) {
|
|
|
|
|
|
// Before defaulting to directory, show the last viewed room
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.viewLastRoom();
|
2017-03-08 15:11:38 +00:00
|
|
|
|
} else {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
if (MatrixClientPeg.safeGet().isGuest()) {
|
2021-06-29 13:11:58 +01:00
|
|
|
|
dis.dispatch({ action: "view_welcome_page" });
|
2019-02-14 12:35:09 +00:00
|
|
|
|
} else {
|
2022-02-22 11:04:27 +01:00
|
|
|
|
dis.dispatch({ action: Action.ViewHomePage });
|
2019-02-08 12:12:43 +00:00
|
|
|
|
}
|
2017-02-28 15:05:49 +00:00
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2015-06-12 14:59:33 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private viewLastRoom(): void {
|
2022-02-10 14:29:55 +00:00
|
|
|
|
dis.dispatch<ViewRoomPayload>({
|
2021-11-25 17:49:43 -03:00
|
|
|
|
action: Action.ViewRoom,
|
2023-03-10 14:55:06 +00:00
|
|
|
|
room_id: localStorage.getItem("mx_last_room_id") ?? undefined,
|
2022-02-17 18:03:27 +00:00
|
|
|
|
metricsTrigger: undefined, // other
|
2019-07-08 12:43:16 -06:00
|
|
|
|
});
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2019-07-08 12:43:16 -06:00
|
|
|
|
|
2016-08-02 19:05:05 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Called when the session is logged out
|
|
|
|
|
|
*/
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private onLoggedOut(): void {
|
2021-03-12 15:01:05 -07:00
|
|
|
|
this.viewLogin({
|
2016-08-02 14:04:20 +01:00
|
|
|
|
ready: false,
|
2017-08-25 12:10:13 +01:00
|
|
|
|
collapseLhs: false,
|
2016-11-24 14:58:37 +00:00
|
|
|
|
currentRoomId: null,
|
2016-08-02 14:04:20 +01:00
|
|
|
|
});
|
2019-09-23 22:01:49 +01:00
|
|
|
|
this.subTitleStatus = "";
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.setPageSubtitle();
|
2023-03-27 10:07:43 +02:00
|
|
|
|
this.stores.onLoggedOut();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2016-08-02 14:04:20 +01:00
|
|
|
|
|
2019-07-03 16:46:37 -06:00
|
|
|
|
/**
|
|
|
|
|
|
* Called when the session is softly logged out
|
|
|
|
|
|
*/
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private onSoftLogout(): void {
|
2019-07-03 16:46:37 -06:00
|
|
|
|
this.notifyNewScreen("soft_logout");
|
|
|
|
|
|
this.setStateForNewView({
|
2020-04-23 10:12:50 +01:00
|
|
|
|
view: Views.SOFT_LOGOUT,
|
2019-07-03 16:46:37 -06:00
|
|
|
|
ready: false,
|
|
|
|
|
|
collapseLhs: false,
|
|
|
|
|
|
currentRoomId: null,
|
|
|
|
|
|
});
|
2019-09-23 22:01:49 +01:00
|
|
|
|
this.subTitleStatus = "";
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.setPageSubtitle();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2019-07-03 16:46:37 -06:00
|
|
|
|
|
2016-08-02 19:05:05 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Called just before the matrix client is started
|
2016-08-03 09:53:02 +01:00
|
|
|
|
* (useful for setting listeners)
|
2016-08-02 19:05:05 +01:00
|
|
|
|
*/
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private onWillStartClient(): void {
|
2017-06-21 11:27:18 +01: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;
|
2019-11-12 11:45:28 +00:00
|
|
|
|
this.firstSyncPromise = defer();
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const cli = MatrixClientPeg.safeGet();
|
2016-08-02 14:04:20 +01: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.
|
2020-08-03 16:02:26 +01:00
|
|
|
|
// https://github.com/vector-im/element-web/issues/3307#issuecomment-282895568
|
2020-04-22 13:08:33 +01:00
|
|
|
|
cli.setCanResetTimelineCallback((roomId) => {
|
2021-09-21 17:48:09 +02:00
|
|
|
|
logger.log("Request to reset timeline in room ", roomId, " viewing:", this.state.currentRoomId);
|
2020-04-22 13:08:33 +01:00
|
|
|
|
if (roomId !== this.state.currentRoomId) {
|
2017-03-22 15:06:52 +00:00
|
|
|
|
// 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.
|
2020-05-07 10:02:40 +01:00
|
|
|
|
if (!this.loggedInView.current) {
|
2017-03-22 15:06:52 +00:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2020-04-22 13:08:33 +01:00
|
|
|
|
return this.loggedInView.current.canResetTimelineInRoom(roomId);
|
2017-03-22 15:06:52 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
2023-08-10 09:01:14 +01:00
|
|
|
|
cli.on(ClientEvent.Sync, (state: SyncState, prevState: SyncState | null, data?: SyncStateData) => {
|
2021-12-17 11:02:06 +00:00
|
|
|
|
if (state === SyncState.Error || state === SyncState.Reconnecting) {
|
2023-03-10 14:55:06 +00:00
|
|
|
|
this.setState({ syncError: data?.error ?? null });
|
2020-04-22 13:08:33 +01:00
|
|
|
|
} else if (this.state.syncError) {
|
2021-06-29 13:11:58 +01:00
|
|
|
|
this.setState({ syncError: null });
|
2018-09-07 12:18:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
if (state === SyncState.Syncing && prevState === SyncState.Syncing) {
|
2024-08-07 09:35:57 +01:00
|
|
|
|
// We know we have performabed a live update and known rooms should be in a good state.
|
|
|
|
|
|
// Now is a good time to clean up drafts.
|
|
|
|
|
|
cleanUpDraftsIfRequired();
|
2015-12-15 14:23:58 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-08-07 09:41:39 +01:00
|
|
|
|
logger.debug(`MatrixClient sync state => ${state}`);
|
2021-12-17 11:02:06 +00:00
|
|
|
|
if (state !== SyncState.Prepared) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2017-04-06 11:30:47 +01:00
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.firstSyncComplete = true;
|
|
|
|
|
|
this.firstSyncPromise.resolve();
|
2015-09-25 17:22:42 +01:00
|
|
|
|
|
2020-11-02 17:25:48 +00:00
|
|
|
|
if (Notifier.shouldShowPrompt() && !MatrixClientPeg.userRegisteredWithinLastHours(24)) {
|
|
|
|
|
|
showNotificationsToast(false);
|
2020-05-28 19:03:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-08 17:36:31 +02:00
|
|
|
|
dis.fire(Action.FocusSendMessageComposer);
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.setState({
|
2019-03-29 15:19:39 +00:00
|
|
|
|
ready: true,
|
|
|
|
|
|
});
|
2015-06-12 14:59:33 +01:00
|
|
|
|
});
|
2020-09-16 13:44:24 +01:00
|
|
|
|
|
2022-02-22 12:18:08 +00:00
|
|
|
|
cli.on(HttpApiEvent.SessionLoggedOut, function (errObj) {
|
2018-07-15 22:33:00 +01:00
|
|
|
|
if (Lifecycle.isLoggingOut()) return;
|
2019-07-03 16:46:37 -06:00
|
|
|
|
|
2021-02-05 09:24:12 +00:00
|
|
|
|
// A modal might have been open when we were logged out by the server
|
2024-07-05 14:39:13 +01:00
|
|
|
|
Modal.forceCloseAllModals();
|
2021-02-05 09:24:12 +00:00
|
|
|
|
|
2019-07-03 16:46:37 -06:00
|
|
|
|
if (errObj.httpStatus === 401 && errObj.data && errObj.data["soft_logout"]) {
|
2021-10-15 16:31:29 +02:00
|
|
|
|
logger.warn("Soft logout issued by server - avoiding data deletion");
|
2019-07-03 16:46:37 -06:00
|
|
|
|
Lifecycle.softLogout();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(ErrorDialog, {
|
2023-09-21 18:16:04 +01:00
|
|
|
|
title: _t("auth|session_logged_out_title"),
|
|
|
|
|
|
description: _t("auth|session_logged_out_description"),
|
2016-03-15 10:48:16 +00:00
|
|
|
|
});
|
2021-02-04 09:33:21 +00:00
|
|
|
|
|
2016-03-15 10:48:16 +00:00
|
|
|
|
dis.dispatch({
|
2017-05-19 13:53:11 +01:00
|
|
|
|
action: "logout",
|
2016-03-15 10:48:16 +00:00
|
|
|
|
});
|
|
|
|
|
|
});
|
2022-02-22 12:18:08 +00:00
|
|
|
|
cli.on(HttpApiEvent.NoConsent, function (message, consentUri) {
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(
|
|
|
|
|
|
QuestionDialog,
|
|
|
|
|
|
{
|
2023-09-21 18:16:04 +01:00
|
|
|
|
title: _t("terms|tac_title"),
|
2018-05-22 15:47:31 +01:00
|
|
|
|
description: (
|
|
|
|
|
|
<div>
|
2023-09-21 18:16:04 +01:00
|
|
|
|
<p> {_t("terms|tac_description", { homeserverDomain: cli.getDomain() })}</p>
|
2018-05-22 15:47:31 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
),
|
2023-09-21 18:16:04 +01:00
|
|
|
|
button: _t("terms|tac_button"),
|
2023-08-23 11:57:22 +01:00
|
|
|
|
cancelButton: _t("action|dismiss"),
|
2018-05-22 15:47:31 +01:00
|
|
|
|
onFinished: (confirmed) => {
|
|
|
|
|
|
if (confirmed) {
|
2023-03-10 14:55:06 +00:00
|
|
|
|
const wnd = window.open(consentUri, "_blank")!;
|
2020-02-23 22:22:12 +00:00
|
|
|
|
wnd.opener = null;
|
2018-05-22 15:47:31 +01:00
|
|
|
|
}
|
2022-12-12 12:24:14 +01:00
|
|
|
|
},
|
2018-05-22 15:47:31 +01:00
|
|
|
|
},
|
2023-03-10 14:55:06 +00:00
|
|
|
|
undefined,
|
2018-05-22 15:47:31 +01:00
|
|
|
|
true,
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2024-05-20 10:53:50 -04:00
|
|
|
|
DecryptionFailureTracker.instance
|
|
|
|
|
|
.start(cli)
|
|
|
|
|
|
.catch((e) => logger.error("Unable to start DecryptionFailureTracker", e));
|
2018-06-15 13:33:07 +01:00
|
|
|
|
|
2022-02-22 12:18:08 +00:00
|
|
|
|
cli.on(ClientEvent.Room, (room) => {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
if (cli.isCryptoEnabled()) {
|
2017-11-05 14:56:41 -07:00
|
|
|
|
const blacklistEnabled = SettingsStore.getValueAt(
|
|
|
|
|
|
SettingLevel.ROOM_DEVICE,
|
|
|
|
|
|
"blacklistUnverifiedDevices",
|
|
|
|
|
|
room.roomId,
|
2017-11-08 17:41:32 -07:00
|
|
|
|
/*explicit=*/ true,
|
2017-11-05 14:56:41 -07:00
|
|
|
|
);
|
|
|
|
|
|
room.setBlacklistUnverifiedDevices(blacklistEnabled);
|
|
|
|
|
|
}
|
2017-11-04 20:13:23 -07:00
|
|
|
|
});
|
2022-02-22 12:18:08 +00:00
|
|
|
|
cli.on(CryptoEvent.Warning, (type) => {
|
2017-12-06 15:28:20 +00:00
|
|
|
|
switch (type) {
|
|
|
|
|
|
case "CRYPTO_WARNING_OLD_VERSION_DETECTED":
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(ErrorDialog, {
|
2023-09-21 18:16:04 +01:00
|
|
|
|
title: _t("encryption|old_version_detected_title"),
|
|
|
|
|
|
description: _t("encryption|old_version_detected_description", {
|
|
|
|
|
|
brand: SdkConfig.get().brand,
|
|
|
|
|
|
}),
|
2017-12-06 15:28:20 +00:00
|
|
|
|
});
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2023-01-12 13:25:14 +00:00
|
|
|
|
cli.on(CryptoEvent.KeyBackupFailed, async (errcode): Promise<void> => {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
let haveNewVersion: boolean | undefined;
|
2024-07-04 16:50:07 +01:00
|
|
|
|
let newVersionInfo: KeyBackupInfo | null = null;
|
2019-01-11 13:15:09 +00:00
|
|
|
|
// if key backup is still enabled, there must be a new backup in place
|
2023-06-15 15:11:49 +01:00
|
|
|
|
if (cli.getKeyBackupEnabled()) {
|
2019-01-11 13:15:09 +00:00
|
|
|
|
haveNewVersion = true;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// otherwise check the server to see if there's a new one
|
|
|
|
|
|
try {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
newVersionInfo = await cli.getKeyBackupVersion();
|
2019-01-11 13:15:09 +00:00
|
|
|
|
if (newVersionInfo !== null) haveNewVersion = true;
|
|
|
|
|
|
} catch (e) {
|
2021-10-15 16:30:53 +02:00
|
|
|
|
logger.error("Saw key backup error but failed to check backup version!", e);
|
2019-01-10 15:13:44 -06:00
|
|
|
|
return;
|
2019-01-11 13:15:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (haveNewVersion) {
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialogAsync(
|
2021-10-23 05:32:16 +02:00
|
|
|
|
import(
|
|
|
|
|
|
"../../async-components/views/dialogs/security/NewRecoveryMethodDialog"
|
2023-02-28 10:31:48 +00:00
|
|
|
|
) as unknown as Promise<typeof NewRecoveryMethodDialog>,
|
2023-06-15 15:11:49 +01:00
|
|
|
|
{ newVersionInfo: newVersionInfo! },
|
2019-01-11 13:15:09 +00:00
|
|
|
|
);
|
|
|
|
|
|
} else {
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialogAsync(
|
2021-10-23 05:32:16 +02:00
|
|
|
|
import(
|
|
|
|
|
|
"../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog"
|
2023-02-28 10:31:48 +00:00
|
|
|
|
) as unknown as Promise<typeof RecoveryMethodRemovedDialog>,
|
2019-01-11 13:15:09 +00:00
|
|
|
|
);
|
2019-01-10 15:13:44 -06:00
|
|
|
|
}
|
2018-12-13 15:55:48 +00:00
|
|
|
|
});
|
2018-10-15 14:41:00 -06:00
|
|
|
|
|
2022-02-22 12:18:08 +00:00
|
|
|
|
cli.on(CryptoEvent.KeySignatureUploadFailure, (failures, source, continuation) => {
|
2020-03-17 10:20:58 +00:00
|
|
|
|
Modal.createDialog(KeySignatureUploadFailedDialog, { failures, source, continuation });
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2023-06-28 11:11:18 +01:00
|
|
|
|
cli.on(CryptoEvent.VerificationRequestReceived, (request) => {
|
2020-03-06 17:22:56 +01:00
|
|
|
|
if (request.verifier) {
|
2022-06-14 17:51:51 +01:00
|
|
|
|
Modal.createDialog(
|
|
|
|
|
|
IncomingSasDialog,
|
|
|
|
|
|
{
|
2020-03-06 17:22:56 +01:00
|
|
|
|
verifier: request.verifier,
|
2020-03-06 17:20:08 +01:00
|
|
|
|
},
|
2023-03-10 14:55:06 +00:00
|
|
|
|
undefined,
|
2020-03-06 17:20:08 +01:00
|
|
|
|
/* priority = */ false,
|
|
|
|
|
|
/* static = */ true,
|
|
|
|
|
|
);
|
|
|
|
|
|
} else if (request.pending) {
|
2020-03-06 16:50:39 +01:00
|
|
|
|
ToastStore.sharedInstance().addOrReplaceToast({
|
2023-06-07 15:43:44 +01:00
|
|
|
|
key: "verifreq_" + request.transactionId,
|
2023-09-21 18:16:04 +01:00
|
|
|
|
title: _t("encryption|verification_requested_toast_title"),
|
2023-04-28 16:56:26 +02:00
|
|
|
|
icon: "verification",
|
2021-06-29 13:11:58 +01:00
|
|
|
|
props: { request },
|
2021-07-03 12:24:07 +02:00
|
|
|
|
component: VerificationRequestToast,
|
2020-05-22 12:57:48 +01:00
|
|
|
|
priority: 90,
|
2020-03-06 16:50:39 +01:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2022-10-21 09:30:02 +02:00
|
|
|
|
|
|
|
|
|
|
this.voiceBroadcastResumer = new VoiceBroadcastResumer(cli);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2017-11-04 20:13:23 -07:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Called shortly after the matrix client has started. Useful for
|
|
|
|
|
|
* setting up anything that requires the client to be started.
|
|
|
|
|
|
* @private
|
|
|
|
|
|
*/
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private onClientStarted(): void {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
const cli = MatrixClientPeg.safeGet();
|
2017-11-04 20:13:23 -07:00
|
|
|
|
|
2017-11-05 14:56:41 -07:00
|
|
|
|
if (cli.isCryptoEnabled()) {
|
|
|
|
|
|
const blacklistEnabled = SettingsStore.getValueAt(SettingLevel.DEVICE, "blacklistUnverifiedDevices");
|
|
|
|
|
|
cli.setGlobalBlacklistUnverifiedDevices(blacklistEnabled);
|
2020-01-13 21:54:14 +00:00
|
|
|
|
|
|
|
|
|
|
// With cross-signing enabled, we send to unknown devices
|
|
|
|
|
|
// without prompting. Any bad-device status the user should
|
|
|
|
|
|
// be aware of will be signalled through the room shield
|
|
|
|
|
|
// changing colour. More advanced behaviour will come once
|
|
|
|
|
|
// we implement more settings.
|
2020-05-27 10:28:25 +01:00
|
|
|
|
cli.setGlobalErrorOnUnknownDevices(false);
|
2017-11-05 14:56:41 -07:00
|
|
|
|
}
|
2022-07-29 15:03:25 +01:00
|
|
|
|
|
|
|
|
|
|
// Cannot be done in OnLoggedIn as at that point the AccountSettingsHandler doesn't yet have a client
|
|
|
|
|
|
// Will be moved to a pre-login flow as well
|
|
|
|
|
|
if (PosthogAnalytics.instance.isEnabled() && SettingsStore.isLevelSupported(SettingLevel.ACCOUNT)) {
|
|
|
|
|
|
this.initPosthogAnalyticsToast();
|
|
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2015-07-15 19:25:36 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
public showScreen(screen: string, params?: { [key: string]: any }): void {
|
2020-11-16 15:56:54 +00:00
|
|
|
|
const cli = MatrixClientPeg.get();
|
|
|
|
|
|
const isLoggedOutOrGuest = !cli || cli.isGuest();
|
|
|
|
|
|
if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) {
|
|
|
|
|
|
// user is logged in and landing on an auth page which will uproot their session, redirect them home instead
|
2022-02-22 11:04:27 +01:00
|
|
|
|
dis.dispatch({ action: Action.ViewHomePage });
|
2020-11-16 15:56:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-04-27 23:59:07 +01:00
|
|
|
|
if (screen === "register") {
|
2015-07-15 20:33:12 +01:00
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "start_registration",
|
2017-05-19 13:53:11 +01:00
|
|
|
|
params: params,
|
2015-07-15 20:33:12 +01:00
|
|
|
|
});
|
2021-05-19 10:07:02 +01:00
|
|
|
|
PerformanceMonitor.instance.start(PerformanceEntryNames.REGISTER);
|
2024-09-13 12:12:04 +01:00
|
|
|
|
} else if (screen === "mobile_register") {
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "start_mobile_registration",
|
|
|
|
|
|
params: params,
|
|
|
|
|
|
});
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen === "login") {
|
2015-07-15 20:33:12 +01:00
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "start_login",
|
2017-05-19 13:53:11 +01:00
|
|
|
|
params: params,
|
2015-07-15 20:33:12 +01:00
|
|
|
|
});
|
2021-05-19 10:07:02 +01:00
|
|
|
|
PerformanceMonitor.instance.start(PerformanceEntryNames.LOGIN);
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen === "forgot_password") {
|
2016-01-12 17:20:16 +00:00
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "start_password_recovery",
|
2017-05-19 13:53:11 +01:00
|
|
|
|
params: params,
|
2016-01-12 17:20:16 +00:00
|
|
|
|
});
|
2019-07-08 12:43:16 -06:00
|
|
|
|
} else if (screen === "soft_logout") {
|
2023-06-15 15:11:49 +01:00
|
|
|
|
if (!!cli?.getUserId() && !Lifecycle.isSoftLogout()) {
|
2019-07-08 12:43:16 -06:00
|
|
|
|
// Logged in - visit a room
|
2020-04-27 23:59:07 +01:00
|
|
|
|
this.viewLastRoom();
|
2019-07-08 12:43:16 -06:00
|
|
|
|
} else {
|
|
|
|
|
|
// Ultimately triggers soft_logout if needed
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "start_login",
|
|
|
|
|
|
params: params,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen === "new") {
|
2015-11-11 02:01:48 +01:00
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "view_create_room",
|
|
|
|
|
|
});
|
2022-02-18 09:43:19 +01:00
|
|
|
|
} else if (screen === "dm") {
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "view_create_chat",
|
|
|
|
|
|
});
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen === "settings") {
|
2020-05-13 21:07:19 -06:00
|
|
|
|
dis.fire(Action.ViewUserSettings);
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen === "welcome") {
|
2019-02-07 16:25:09 +00:00
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "view_welcome_page",
|
|
|
|
|
|
});
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen === "home") {
|
2016-11-13 14:10:46 +00:00
|
|
|
|
dis.dispatch({
|
2022-02-22 11:04:27 +01:00
|
|
|
|
action: Action.ViewHomePage,
|
2016-11-13 14:10:46 +00:00
|
|
|
|
});
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen === "directory") {
|
2020-06-08 20:33:21 -06:00
|
|
|
|
dis.fire(Action.ViewRoomDirectory);
|
2020-06-25 22:00:22 +01:00
|
|
|
|
} else if (screen === "start_sso" || screen === "start_cas") {
|
|
|
|
|
|
let cli = MatrixClientPeg.get();
|
|
|
|
|
|
if (!cli) {
|
2023-04-28 11:16:07 +01:00
|
|
|
|
const { hsUrl, isUrl } = this.getServerProperties().serverConfig;
|
2021-03-18 20:50:34 -06:00
|
|
|
|
cli = createClient({
|
2020-06-25 22:00:22 +01:00
|
|
|
|
baseUrl: hsUrl,
|
|
|
|
|
|
idBaseUrl: isUrl,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const type = screen === "start_sso" ? "sso" : "cas";
|
2023-03-10 14:55:06 +00:00
|
|
|
|
PlatformPeg.get()?.startSingleSignOn(cli, type, this.getFragmentAfterLogin());
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen.indexOf("room/") === 0) {
|
2019-12-24 15:06:50 +01:00
|
|
|
|
// Rooms can have the following formats:
|
|
|
|
|
|
// #room_alias:domain or !opaque_id:domain
|
|
|
|
|
|
const room = screen.substring(5);
|
|
|
|
|
|
const domainOffset = room.indexOf(":") + 1; // 0 in case room does not contain a :
|
|
|
|
|
|
let eventOffset = room.length;
|
|
|
|
|
|
// room aliases can contain slashes only look for slash after domain
|
|
|
|
|
|
if (room.substring(domainOffset).indexOf("/") > -1) {
|
|
|
|
|
|
eventOffset = domainOffset + room.substring(domainOffset).indexOf("/");
|
|
|
|
|
|
}
|
|
|
|
|
|
const roomString = room.substring(0, eventOffset);
|
2023-03-10 14:55:06 +00:00
|
|
|
|
let eventId: string | undefined = room.substring(eventOffset + 1); // empty string if no event id given
|
2019-03-25 23:02:25 -06:00
|
|
|
|
|
|
|
|
|
|
// Previously we pulled the eventID from the segments in such a way
|
|
|
|
|
|
// where if there was no eventId then we'd get undefined. However, we
|
|
|
|
|
|
// now do a splice and join to handle v3 event IDs which results in
|
|
|
|
|
|
// an empty string. To maintain our potential contract with the rest
|
|
|
|
|
|
// of the app, we coerce the eventId to be undefined where applicable.
|
|
|
|
|
|
if (!eventId) eventId = undefined;
|
|
|
|
|
|
|
2020-08-03 16:02:26 +01:00
|
|
|
|
// TODO: Handle encoded room/event IDs: https://github.com/vector-im/element-web/issues/9149
|
2016-03-01 18:23:57 +00:00
|
|
|
|
|
2023-03-10 14:55:06 +00:00
|
|
|
|
let threepidInvite: IThreepidInvite | undefined;
|
2021-02-05 17:18:13 +00:00
|
|
|
|
// if we landed here from a 3PID invite, persist it
|
2023-03-10 14:55:06 +00:00
|
|
|
|
if (params?.signurl && params?.email) {
|
2020-09-11 19:49:48 -06:00
|
|
|
|
threepidInvite = ThreepidInviteStore.instance.storeInvite(
|
|
|
|
|
|
roomString,
|
|
|
|
|
|
params as IThreepidInviteWireFormat,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2021-02-05 17:18:13 +00:00
|
|
|
|
// otherwise check that this room doesn't already have a known invite
|
|
|
|
|
|
if (!threepidInvite) {
|
|
|
|
|
|
const invites = ThreepidInviteStore.instance.getInvites();
|
|
|
|
|
|
threepidInvite = invites.find((invite) => invite.roomId === roomString);
|
|
|
|
|
|
}
|
2016-03-01 18:23:57 +00:00
|
|
|
|
|
2018-10-19 13:30:38 -06: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.
|
2023-03-10 14:55:06 +00:00
|
|
|
|
let via: string[] = [];
|
|
|
|
|
|
if (params?.via) {
|
2018-10-19 13:30:38 -06:00
|
|
|
|
if (typeof params.via === "string") via = [params.via];
|
|
|
|
|
|
else via = params.via;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-10 14:29:55 +00:00
|
|
|
|
const payload: ViewRoomPayload = {
|
2021-11-25 17:49:43 -03:00
|
|
|
|
action: Action.ViewRoom,
|
2016-06-10 15:12:42 +01:00
|
|
|
|
event_id: eventId,
|
2018-10-19 13:30:38 -06:00
|
|
|
|
via_servers: via,
|
2017-06-08 17:57:37 +01: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 14:17:49 +01:00
|
|
|
|
highlighted: Boolean(eventId),
|
2020-09-11 19:49:48 -06:00
|
|
|
|
threepid_invite: threepidInvite,
|
2020-09-11 19:55:15 -06:00
|
|
|
|
// TODO: Replace oob_data with the threepidInvite (which has the same info).
|
|
|
|
|
|
// This isn't done yet because it's threaded through so many more places.
|
|
|
|
|
|
// See https://github.com/vector-im/element-web/issues/15157
|
2020-09-11 19:49:48 -06:00
|
|
|
|
oob_data: {
|
|
|
|
|
|
name: threepidInvite?.roomName,
|
|
|
|
|
|
avatarUrl: threepidInvite?.roomAvatarUrl,
|
|
|
|
|
|
inviterName: threepidInvite?.inviterName,
|
|
|
|
|
|
},
|
2020-04-27 23:59:07 +01:00
|
|
|
|
room_alias: undefined,
|
|
|
|
|
|
room_id: undefined,
|
2022-02-17 18:03:27 +00:00
|
|
|
|
metricsTrigger: undefined, // unknown or external trigger
|
2016-06-10 15:12:42 +01:00
|
|
|
|
};
|
2020-04-27 23:59:07 +01:00
|
|
|
|
if (roomString[0] === "#") {
|
2016-06-10 15:12:42 +01:00
|
|
|
|
payload.room_alias = roomString;
|
2015-09-18 18:39:16 +01:00
|
|
|
|
} else {
|
2016-06-10 15:12:42 +01:00
|
|
|
|
payload.room_id = roomString;
|
2016-06-09 18:49:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-02-11 13:49:18 +00:00
|
|
|
|
dis.dispatch(payload);
|
2020-04-27 23:59:07 +01:00
|
|
|
|
} else if (screen.indexOf("user/") === 0) {
|
2017-05-19 13:53:11 +01:00
|
|
|
|
const userId = screen.substring(5);
|
2019-04-17 18:26:07 +02:00
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: "view_user_info",
|
|
|
|
|
|
userId: userId,
|
2023-03-10 14:55:06 +00:00
|
|
|
|
subAction: params?.action,
|
2019-04-17 18:26:07 +02:00
|
|
|
|
});
|
2017-05-19 13:53:11 +01:00
|
|
|
|
} else {
|
2023-05-05 11:56:15 +01:00
|
|
|
|
logger.info(`Ignoring showScreen for '${screen}'`);
|
2015-11-20 14:26:49 +00:00
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2015-07-15 19:25:36 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private notifyNewScreen(screen: string, replaceLast = false): void {
|
2015-07-15 19:25:36 +01:00
|
|
|
|
if (this.props.onNewScreen) {
|
2020-09-09 16:52:46 +01:00
|
|
|
|
this.props.onNewScreen(screen, replaceLast);
|
2015-07-15 19:25:36 +01:00
|
|
|
|
}
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.setPageSubtitle();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2021-12-17 11:02:06 +00:00
|
|
|
|
|
2023-05-12 09:49:37 +01:00
|
|
|
|
private onLogoutClick(event: ButtonEvent): void {
|
2015-11-30 18:11:04 +00:00
|
|
|
|
dis.dispatch({
|
2017-05-19 13:53:11 +01:00
|
|
|
|
action: "logout",
|
2015-11-30 18:11:04 +00:00
|
|
|
|
});
|
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
|
event.preventDefault();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2015-11-30 18:11:04 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private handleResize = (): void => {
|
2021-05-25 09:50:09 +01:00
|
|
|
|
const LHS_THRESHOLD = 1000;
|
2021-05-25 10:25:36 +01:00
|
|
|
|
const width = UIStore.instance.windowWidth;
|
2015-11-30 18:11:04 +00:00
|
|
|
|
|
2021-05-28 10:03:46 +01:00
|
|
|
|
if (this.prevWindowWidth < LHS_THRESHOLD && width >= LHS_THRESHOLD) {
|
2015-11-30 18:11:04 +00:00
|
|
|
|
dis.dispatch({ action: "show_left_panel" });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-28 10:03:46 +01:00
|
|
|
|
if (this.prevWindowWidth >= LHS_THRESHOLD && width < LHS_THRESHOLD) {
|
|
|
|
|
|
dis.dispatch({ action: "hide_left_panel" });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.prevWindowWidth = width;
|
2019-03-12 16:36:12 +01:00
|
|
|
|
this.state.resizeNotifier.notifyWindowResized();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2015-11-30 18:11:04 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private dispatchTimelineResize(): void {
|
2019-03-29 14:32:26 +01:00
|
|
|
|
dis.dispatch({ action: "timeline_resize" });
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2019-03-12 16:37:20 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private onRegisterClick = (): void => {
|
2015-11-30 18:11:04 +00:00
|
|
|
|
this.showScreen("register");
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2015-11-30 18:11:04 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private onLoginClick = (): void => {
|
2015-11-30 18:11:04 +00:00
|
|
|
|
this.showScreen("login");
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2015-11-30 18:11:04 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private onForgotPasswordClick = (): void => {
|
2016-01-12 17:20:16 +00:00
|
|
|
|
this.showScreen("forgot_password");
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2016-01-12 17:20:16 +00:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private onRegisterFlowComplete = (credentials: IMatrixClientCreds, password: string): Promise<void> => {
|
2020-01-25 15:28:06 +00:00
|
|
|
|
return this.onUserCompletedLoginFlow(credentials, password);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2020-01-24 19:11:57 +00:00
|
|
|
|
|
2017-06-19 10:22:18 +01:00
|
|
|
|
// returns a promise which resolves to the new MatrixClient
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private onRegistered(credentials: IMatrixClientCreds): Promise<MatrixClient> {
|
2017-06-19 10:22:18 +01:00
|
|
|
|
return Lifecycle.setLoggedIn(credentials);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2017-02-13 14:36:03 +00:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private onSendEvent(roomId: string, event: MatrixEvent): void {
|
2017-06-16 16:12:52 +01:00
|
|
|
|
const cli = MatrixClientPeg.get();
|
2021-09-14 17:49:18 +02:00
|
|
|
|
if (!cli) return;
|
2015-12-21 12:55:13 +00:00
|
|
|
|
|
2024-03-25 12:48:48 +00:00
|
|
|
|
cli.sendEvent(roomId, event.getType() as keyof TimelineEvents, event.getContent()).then(() => {
|
2021-06-29 13:11:58 +01:00
|
|
|
|
dis.dispatch({ action: "message_sent" });
|
2017-06-16 16:12:52 +01:00
|
|
|
|
});
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2017-06-16 16:12:52 +01:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private setPageSubtitle(subtitle = ""): void {
|
2019-09-23 22:01:49 +01:00
|
|
|
|
if (this.state.currentRoomId) {
|
2019-09-24 12:53:33 +02:00
|
|
|
|
const client = MatrixClientPeg.get();
|
2023-05-10 08:41:55 +01:00
|
|
|
|
const room = client?.getRoom(this.state.currentRoomId);
|
2019-09-23 22:01:49 +01:00
|
|
|
|
if (room) {
|
2019-11-12 15:12:54 -07:00
|
|
|
|
subtitle = `${this.subTitleStatus} | ${room.name} ${subtitle}`;
|
2019-09-23 22:01:49 +01:00
|
|
|
|
}
|
2019-11-12 15:12:54 -07:00
|
|
|
|
} else {
|
|
|
|
|
|
subtitle = `${this.subTitleStatus} ${subtitle}`;
|
2019-09-23 22:01:49 +01:00
|
|
|
|
}
|
2020-09-27 21:20:41 +01:00
|
|
|
|
|
2020-09-27 21:06:02 +01:00
|
|
|
|
const title = `${SdkConfig.get().brand} ${subtitle}`;
|
|
|
|
|
|
|
|
|
|
|
|
if (document.title !== title) {
|
|
|
|
|
|
document.title = title;
|
|
|
|
|
|
}
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
2017-06-20 15:31:12 +01:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private onUpdateStatusIndicator = (notificationState: SummarizedNotificationState, state: SyncState): void => {
|
2020-07-21 20:24:16 -06:00
|
|
|
|
const numUnreadRooms = notificationState.numUnreadStates; // we know that states === rooms here
|
2016-03-16 06:32:49 +05:30
|
|
|
|
|
2016-11-02 15:10:21 +00:00
|
|
|
|
if (PlatformPeg.get()) {
|
2023-03-10 14:55:06 +00:00
|
|
|
|
PlatformPeg.get()!.setErrorStatus(state === SyncState.Error);
|
|
|
|
|
|
PlatformPeg.get()!.setNotificationCount(numUnreadRooms);
|
2016-01-27 15:19:25 +00:00
|
|
|
|
}
|
2016-11-02 15:10:21 +00:00
|
|
|
|
|
2019-09-23 22:01:49 +01:00
|
|
|
|
this.subTitleStatus = "";
|
2021-12-17 11:02:06 +00:00
|
|
|
|
if (state === SyncState.Error) {
|
2023-08-22 18:47:33 +01:00
|
|
|
|
this.subTitleStatus += `[${_t("common|offline")}] `;
|
2017-06-07 11:40:46 +01:00
|
|
|
|
}
|
2020-07-21 20:24:16 -06:00
|
|
|
|
if (numUnreadRooms > 0) {
|
|
|
|
|
|
this.subTitleStatus += `[${numUnreadRooms}]`;
|
2024-01-15 15:25:48 +00:00
|
|
|
|
} else if (notificationState.level >= NotificationLevel.Activity) {
|
2023-02-05 21:31:16 -05:00
|
|
|
|
this.subTitleStatus += `*`;
|
2017-06-07 11:40:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.setPageSubtitle();
|
2021-12-17 11:02:06 +00:00
|
|
|
|
};
|
2015-12-21 12:55:13 +00:00
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
|
private onServerConfigChange = (serverConfig: ValidatedServerConfig): void => {
|
2021-06-29 13:11:58 +01:00
|
|
|
|
this.setState({ serverConfig });
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2018-12-04 23:34:57 -07:00
|
|
|
|
|
2020-09-15 15:25:50 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* After registration or login, we run various post-auth steps before entering the app
|
|
|
|
|
|
* proper, such setting up cross-signing or verifying the new session.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Note: SSO users (and any others using token login) currently do not pass through
|
|
|
|
|
|
* this, as they instead jump straight into the app after `attemptTokenLogin`.
|
|
|
|
|
|
*/
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private onUserCompletedLoginFlow = async (credentials: IMatrixClientCreds, password: string): Promise<void> => {
|
2023-02-23 08:46:49 +01:00
|
|
|
|
this.stores.accountPasswordStore.setPassword(password);
|
2020-01-28 12:30:39 +00:00
|
|
|
|
|
2020-06-05 17:52:09 +01:00
|
|
|
|
// Create and start the client
|
|
|
|
|
|
await Lifecycle.setLoggedIn(credentials);
|
2021-01-27 12:50:12 +00:00
|
|
|
|
await this.postLoginSetup();
|
2021-06-15 10:24:07 +01:00
|
|
|
|
|
2021-05-19 10:07:02 +01:00
|
|
|
|
PerformanceMonitor.instance.stop(PerformanceEntryNames.LOGIN);
|
|
|
|
|
|
PerformanceMonitor.instance.stop(PerformanceEntryNames.REGISTER);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2020-01-15 21:13:56 +00:00
|
|
|
|
|
2020-01-24 19:11:57 +00:00
|
|
|
|
// complete security / e2e setup has finished
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private onCompleteSecurityE2eSetupFinished = (): void => {
|
2020-04-22 13:08:33 +01:00
|
|
|
|
this.onLoggedIn();
|
2020-04-22 11:55:03 +01:00
|
|
|
|
};
|
2020-01-15 21:13:56 +00:00
|
|
|
|
|
2021-12-17 11:02:06 +00:00
|
|
|
|
private getFragmentAfterLogin(): string {
|
2020-05-13 06:24:04 +01:00
|
|
|
|
let fragmentAfterLogin = "";
|
2020-06-29 15:40:20 +01:00
|
|
|
|
const initialScreenAfterLogin = this.props.initialScreenAfterLogin;
|
|
|
|
|
|
if (
|
|
|
|
|
|
initialScreenAfterLogin &&
|
2020-08-03 16:02:26 +01:00
|
|
|
|
// XXX: workaround for https://github.com/vector-im/element-web/issues/11643 causing a login-loop
|
2020-06-29 15:40:20 +01:00
|
|
|
|
!["welcome", "login", "register", "start_sso", "start_cas"].includes(initialScreenAfterLogin.screen)
|
2020-06-02 16:26:07 +01:00
|
|
|
|
) {
|
2020-06-29 15:40:20 +01:00
|
|
|
|
fragmentAfterLogin = `/${initialScreenAfterLogin.screen}`;
|
2020-05-13 06:24:04 +01:00
|
|
|
|
}
|
2020-06-25 22:00:22 +01:00
|
|
|
|
return fragmentAfterLogin;
|
|
|
|
|
|
}
|
2020-05-13 06:24:04 +01:00
|
|
|
|
|
2023-02-13 17:01:43 +00:00
|
|
|
|
public render(): React.ReactNode {
|
2020-06-25 22:00:22 +01:00
|
|
|
|
const fragmentAfterLogin = this.getFragmentAfterLogin();
|
2023-03-07 10:45:55 +00:00
|
|
|
|
let view: JSX.Element;
|
2019-10-02 16:26:23 +01:00
|
|
|
|
|
2020-04-23 10:12:50 +01:00
|
|
|
|
if (this.state.view === Views.LOADING) {
|
2019-10-02 16:26:23 +01:00
|
|
|
|
view = (
|
2016-08-10 11:33:58 +01:00
|
|
|
|
<div className="mx_MatrixChat_splash">
|
|
|
|
|
|
<Spinner />
|
|
|
|
|
|
</div>
|
2016-08-10 00:03:29 +01:00
|
|
|
|
);
|
2023-08-24 09:28:43 +01:00
|
|
|
|
} else if (this.state.view === Views.CONFIRM_LOCK_THEFT) {
|
|
|
|
|
|
view = (
|
|
|
|
|
|
<ConfirmSessionLockTheftView
|
|
|
|
|
|
onConfirm={() => {
|
|
|
|
|
|
this.setState({ view: Views.LOADING });
|
|
|
|
|
|
this.startInitSession();
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
);
|
2020-04-23 10:12:50 +01:00
|
|
|
|
} else if (this.state.view === Views.COMPLETE_SECURITY) {
|
2020-01-24 19:11:57 +00:00
|
|
|
|
view = <CompleteSecurity onFinished={this.onCompleteSecurityE2eSetupFinished} />;
|
2020-04-23 10:12:50 +01:00
|
|
|
|
} else if (this.state.view === Views.E2E_SETUP) {
|
2020-01-24 19:11:57 +00:00
|
|
|
|
view = (
|
|
|
|
|
|
<E2eSetup
|
|
|
|
|
|
onFinished={this.onCompleteSecurityE2eSetupFinished}
|
2023-02-23 08:46:49 +01:00
|
|
|
|
accountPassword={this.stores.accountPasswordStore.getPassword()}
|
2021-01-27 12:50:12 +00:00
|
|
|
|
tokenLogin={!!this.tokenLogin}
|
2020-01-15 21:13:56 +00:00
|
|
|
|
/>
|
|
|
|
|
|
);
|
2020-04-23 10:12:50 +01:00
|
|
|
|
} else if (this.state.view === Views.LOGGED_IN) {
|
2017-06-15 17:36:57 +01: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.
|
2024-03-22 14:26:08 +00:00
|
|
|
|
if (this.state.ready && this.state.page_type) {
|
2017-06-15 17:36:57 +01: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.
|
|
|
|
|
|
*/
|
2019-10-02 16:26:23 +01:00
|
|
|
|
view = (
|
2020-04-23 10:12:50 +01:00
|
|
|
|
<LoggedInView
|
|
|
|
|
|
{...this.props}
|
|
|
|
|
|
{...this.state}
|
|
|
|
|
|
ref={this.loggedInView}
|
2023-06-15 15:11:49 +01:00
|
|
|
|
matrixClient={MatrixClientPeg.safeGet()}
|
2017-06-15 17:36:57 +01:00
|
|
|
|
onRegistered={this.onRegistered}
|
|
|
|
|
|
currentRoomId={this.state.currentRoomId}
|
|
|
|
|
|
/>
|
|
|
|
|
|
);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// we think we are logged in, but are still waiting for the /sync to complete
|
2019-10-02 16:26:23 +01:00
|
|
|
|
view = (
|
2024-01-04 18:12:08 +00:00
|
|
|
|
<LoginSplashView
|
2024-01-17 07:14:49 +00:00
|
|
|
|
matrixClient={MatrixClientPeg.safeGet()}
|
2024-01-04 18:12:08 +00:00
|
|
|
|
onLogoutClick={this.onLogoutClick}
|
2024-03-22 14:26:08 +00:00
|
|
|
|
syncError={this.state.syncError}
|
2024-01-04 18:12:08 +00:00
|
|
|
|
/>
|
2017-06-15 17:36:57 +01:00
|
|
|
|
);
|
|
|
|
|
|
}
|
2020-04-23 10:12:50 +01:00
|
|
|
|
} else if (this.state.view === Views.WELCOME) {
|
2020-06-25 22:02:39 +01:00
|
|
|
|
view = <Welcome />;
|
2020-09-17 11:55:10 +01:00
|
|
|
|
} else if (this.state.view === Views.REGISTER && SettingsStore.getValue(UIFeature.Registration)) {
|
2020-09-11 20:20:33 -06:00
|
|
|
|
const email = ThreepidInviteStore.instance.pickBestInvite()?.toEmail;
|
2019-10-02 16:26:23 +01:00
|
|
|
|
view = (
|
2015-11-30 18:11:04 +00:00
|
|
|
|
<Registration
|
|
|
|
|
|
clientSecret={this.state.register_client_secret}
|
|
|
|
|
|
sessionId={this.state.register_session_id}
|
|
|
|
|
|
idSid={this.state.register_id_sid}
|
2020-09-11 20:20:33 -06:00
|
|
|
|
email={email}
|
2016-06-02 11:50:00 +01:00
|
|
|
|
brand={this.props.config.brand}
|
2020-01-24 19:11:57 +00:00
|
|
|
|
onLoggedIn={this.onRegisterFlowComplete}
|
2016-03-06 14:33:36 -05:00
|
|
|
|
onLoginClick={this.onLoginClick}
|
2018-02-07 15:51:03 +00:00
|
|
|
|
onServerConfigChange={this.onServerConfigChange}
|
2020-01-30 11:27:54 +00:00
|
|
|
|
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
2020-11-24 12:09:11 +00:00
|
|
|
|
fragmentAfterLogin={fragmentAfterLogin}
|
2024-09-13 12:12:04 +01:00
|
|
|
|
mobileRegister={this.state.isMobileRegistration}
|
2019-06-12 18:11:58 +01:00
|
|
|
|
{...this.getServerProperties()}
|
2019-05-02 23:09:07 -06:00
|
|
|
|
/>
|
2015-11-30 18:11:04 +00:00
|
|
|
|
);
|
2020-09-17 11:55:10 +01:00
|
|
|
|
} else if (this.state.view === Views.FORGOT_PASSWORD && SettingsStore.getValue(UIFeature.PasswordReset)) {
|
2019-10-02 16:26:23 +01:00
|
|
|
|
view = (
|
2016-01-12 17:20:16 +00:00
|
|
|
|
<ForgotPassword
|
2016-03-06 14:33:36 -05:00
|
|
|
|
onComplete={this.onLoginClick}
|
2019-05-02 23:09:07 -06:00
|
|
|
|
onLoginClick={this.onLoginClick}
|
|
|
|
|
|
{...this.getServerProperties()}
|
|
|
|
|
|
/>
|
2016-01-12 17:20:16 +00:00
|
|
|
|
);
|
2020-04-23 10:12:50 +01:00
|
|
|
|
} else if (this.state.view === Views.LOGIN) {
|
2020-09-17 11:55:10 +01:00
|
|
|
|
const showPasswordReset = SettingsStore.getValue(UIFeature.PasswordReset);
|
2019-10-02 16:26:23 +01:00
|
|
|
|
view = (
|
2015-11-30 18:11:04 +00:00
|
|
|
|
<Login
|
2020-04-15 12:21:49 +01:00
|
|
|
|
isSyncing={this.state.pendingInitialSync}
|
2020-01-15 21:13:56 +00:00
|
|
|
|
onLoggedIn={this.onUserCompletedLoginFlow}
|
2015-11-30 18:11:04 +00:00
|
|
|
|
onRegisterClick={this.onRegisterClick}
|
2016-05-27 14:57:43 +01:00
|
|
|
|
fallbackHsUrl={this.getFallbackHsUrl()}
|
2016-08-12 11:41:06 +01:00
|
|
|
|
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
2020-09-17 11:55:10 +01:00
|
|
|
|
onForgotPasswordClick={showPasswordReset ? this.onForgotPasswordClick : undefined}
|
2018-02-07 15:51:03 +00:00
|
|
|
|
onServerConfigChange={this.onServerConfigChange}
|
2020-05-13 06:24:04 +01:00
|
|
|
|
fragmentAfterLogin={fragmentAfterLogin}
|
2023-04-20 09:49:10 +01:00
|
|
|
|
defaultUsername={this.props.startingFragmentQueryParams?.defaultUsername as string | undefined}
|
2019-05-02 23:09:07 -06:00
|
|
|
|
{...this.getServerProperties()}
|
2016-09-01 11:08:40 +01:00
|
|
|
|
/>
|
2015-11-30 18:11:04 +00:00
|
|
|
|
);
|
2020-04-23 10:12:50 +01:00
|
|
|
|
} else if (this.state.view === Views.SOFT_LOGOUT) {
|
2019-10-02 16:26:23 +01:00
|
|
|
|
view = (
|
2019-07-08 12:43:16 -06:00
|
|
|
|
<SoftLogout
|
|
|
|
|
|
realQueryParams={this.props.realQueryParams}
|
|
|
|
|
|
onTokenLoginCompleted={this.props.onTokenLoginCompleted}
|
2020-05-13 06:24:04 +01:00
|
|
|
|
fragmentAfterLogin={fragmentAfterLogin}
|
2019-07-08 12:43:16 -06:00
|
|
|
|
/>
|
2019-07-03 16:46:37 -06:00
|
|
|
|
);
|
2022-07-13 15:43:44 +02:00
|
|
|
|
} else if (this.state.view === Views.USE_CASE_SELECTION) {
|
2023-01-12 13:25:14 +00:00
|
|
|
|
view = <UseCaseSelection onFinished={(useCase): Promise<void> => this.onShowPostLoginScreen(useCase)} />;
|
2023-08-24 09:28:43 +01:00
|
|
|
|
} else if (this.state.view === Views.LOCK_STOLEN) {
|
|
|
|
|
|
view = <SessionLockStolenView />;
|
2019-10-02 16:26:23 +01:00
|
|
|
|
} else {
|
2021-10-15 16:30:53 +02:00
|
|
|
|
logger.error(`Unknown view ${this.state.view}`);
|
2023-03-07 10:45:55 +00:00
|
|
|
|
return null;
|
2019-07-03 16:46:37 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-10-02 16:26:23 +01:00
|
|
|
|
return (
|
|
|
|
|
|
<ErrorBoundary>
|
2024-04-12 14:56:23 +02:00
|
|
|
|
<SDKContext.Provider value={this.stores}>{view}</SDKContext.Provider>
|
2019-10-02 16:26:23 +01:00
|
|
|
|
</ErrorBoundary>
|
|
|
|
|
|
);
|
2020-04-22 11:55:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|