mirror of
https://github.com/element-hq/element-web.git
synced 2025-12-15 02:00:24 +00:00
Compare commits
1 Commits
hs/track-k
...
hs/url-han
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa90f14e66 |
@@ -524,4 +524,10 @@ export default abstract class BasePlatform {
|
|||||||
* @returns {Promise<boolean>} True if the lock was acquired, false otherwise.
|
* @returns {Promise<boolean>} True if the lock was acquired, false otherwise.
|
||||||
*/
|
*/
|
||||||
public abstract getSessionLock(_onNewInstance: () => Promise<void>): Promise<boolean>;
|
public abstract getSessionLock(_onNewInstance: () => Promise<void>): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param urlPattern
|
||||||
|
*/
|
||||||
|
public registerProtocolHandler?(urlPattern: `${string}%s`): Promise<void>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ enum Views {
|
|||||||
|
|
||||||
// Another instance of the application has started up. We just show an error page.
|
// Another instance of the application has started up. We just show an error page.
|
||||||
LOCK_STOLEN,
|
LOCK_STOLEN,
|
||||||
|
|
||||||
|
// Another instance of the application has opened and this session had a matrixuri, so we
|
||||||
|
// just show a warning and close.
|
||||||
|
SENT_URI,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Views;
|
export default Views;
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ import { ShareFormat, type SharePayload } from "../../dispatcher/payloads/ShareP
|
|||||||
import Markdown from "../../Markdown";
|
import Markdown from "../../Markdown";
|
||||||
import { sanitizeHtmlParams } from "../../Linkify";
|
import { sanitizeHtmlParams } from "../../Linkify";
|
||||||
import { isOnlyAdmin } from "../../utils/membership";
|
import { isOnlyAdmin } from "../../utils/membership";
|
||||||
|
import mxModuleApi from "../../modules/Api";
|
||||||
|
|
||||||
// legacy export
|
// legacy export
|
||||||
export { default as Views } from "../../Views";
|
export { default as Views } from "../../Views";
|
||||||
@@ -234,6 +235,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
private fontWatcher?: FontWatcher;
|
private fontWatcher?: FontWatcher;
|
||||||
private readonly stores: SdkContextClass;
|
private readonly stores: SdkContextClass;
|
||||||
private loadSessionAbortController = new AbortController();
|
private loadSessionAbortController = new AbortController();
|
||||||
|
private newUriBroadcastChannel = new BroadcastChannel("io.element.broadcast.new_uri");
|
||||||
|
|
||||||
private sessionLoadStarted = false;
|
private sessionLoadStarted = false;
|
||||||
|
|
||||||
@@ -283,6 +285,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
// object field used for tracking the status info appended to the title tag.
|
// 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.
|
// we don't do it as react state as i'm scared about triggering needless react refreshes.
|
||||||
this.subTitleStatus = "";
|
this.subTitleStatus = "";
|
||||||
|
|
||||||
|
this.newUriBroadcastChannel.addEventListener("message", (ev) => {
|
||||||
|
const { screen, params } = ev.data;
|
||||||
|
console.log(ev, ev.data);
|
||||||
|
this.showScreen(screen, params);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -470,6 +478,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
|
|
||||||
initSentry(SdkConfig.get("sentry"));
|
initSentry(SdkConfig.get("sentry"));
|
||||||
window.addEventListener("resize", this.onWindowResized);
|
window.addEventListener("resize", this.onWindowResized);
|
||||||
|
console.log("MatrixCHAT IS LOADING")
|
||||||
|
|
||||||
// Once we start loading the MatrixClient, we can't stop, even if MatrixChat gets unmounted (as it does
|
// Once we start loading the MatrixClient, we can't stop, even if MatrixChat gets unmounted (as it does
|
||||||
// in React's Strict Mode). So, start loading the session now, but only if this MatrixChat was not previously
|
// in React's Strict Mode). So, start loading the session now, but only if this MatrixChat was not previously
|
||||||
@@ -478,8 +487,18 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
this.sessionLoadStarted = true;
|
this.sessionLoadStarted = true;
|
||||||
const platform = PlatformPeg.get();
|
const platform = PlatformPeg.get();
|
||||||
if (platform && !platform.checkSessionLockFree()) {
|
if (platform && !platform.checkSessionLockFree()) {
|
||||||
// another instance holds the lock; confirm its theft before proceeding
|
console.log("screenAfterLogin", this.screenAfterLogin);
|
||||||
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
|
if (this.screenAfterLogin?.screen.startsWith("matrix")) {
|
||||||
|
console.log("Got URI req");
|
||||||
|
// The user has clicked on a matrixuri link, so we need to forward it to them.
|
||||||
|
this.newUriBroadcastChannel.postMessage({screen: this.screenAfterLogin.screen, params: this.screenAfterLogin.params});
|
||||||
|
// This will put the application in a final state so the other instance can handle the URI.
|
||||||
|
setTimeout(() => this.setState({ view: Views.SENT_URI }), 0);
|
||||||
|
} else {
|
||||||
|
// another instance holds the lock; confirm its theft before proceeding
|
||||||
|
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
|
||||||
|
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.startInitSession();
|
this.startInitSession();
|
||||||
}
|
}
|
||||||
@@ -1752,6 +1771,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public showScreen(screen: string, params?: { [key: string]: any }): void {
|
public showScreen(screen: string, params?: { [key: string]: any }): void {
|
||||||
|
if (this.state.view === Views.SENT_URI) {
|
||||||
|
// Ignore any screens once we've reached this state.
|
||||||
|
return;
|
||||||
|
}
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const isLoggedOutOrGuest = !cli || cli.isGuest();
|
const isLoggedOutOrGuest = !cli || cli.isGuest();
|
||||||
if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) {
|
if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) {
|
||||||
@@ -1817,6 +1840,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
}
|
}
|
||||||
} else if (screen === "settings") {
|
} else if (screen === "settings") {
|
||||||
dis.fire(Action.ViewUserSettings);
|
dis.fire(Action.ViewUserSettings);
|
||||||
|
} else if (screen.startsWith("matrix")) {
|
||||||
|
console.log("matrix:", screen, params);
|
||||||
|
mxModuleApi.navigation.toMatrixToLink(screen, false).catch((ex) => {
|
||||||
|
console.log('Failed to handle matrix uri', ex);
|
||||||
|
})
|
||||||
} else if (screen === "welcome") {
|
} else if (screen === "welcome") {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: "view_welcome_page",
|
action: "view_welcome_page",
|
||||||
@@ -2098,6 +2126,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
} else if (this.state.view === Views.SENT_URI) {
|
||||||
|
view = (
|
||||||
|
<b>PLACEHOLDER: The URI has been broadcast to the other app.</b>
|
||||||
|
);
|
||||||
} else if (this.state.view === Views.COMPLETE_SECURITY) {
|
} else if (this.state.view === Views.COMPLETE_SECURITY) {
|
||||||
view = <CompleteSecurity onFinished={this.onCompleteSecurityE2eSetupFinished} />;
|
view = <CompleteSecurity onFinished={this.onCompleteSecurityE2eSetupFinished} />;
|
||||||
} else if (this.state.view === Views.E2E_SETUP) {
|
} else if (this.state.view === Views.E2E_SETUP) {
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
|
|||||||
<SettingsSubsection heading={_t("common|general")} stretchContent>
|
<SettingsSubsection heading={_t("common|general")} stretchContent>
|
||||||
{this.renderGroup(PreferencesUserSettingsTab.GENERAL_SETTINGS)}
|
{this.renderGroup(PreferencesUserSettingsTab.GENERAL_SETTINGS)}
|
||||||
|
|
||||||
|
<SettingsFlag name="protocolHandlerRegistered" level={SettingLevel.DEVICE} />
|
||||||
|
|
||||||
<SettingsFlag name="Electron.showTrayIcon" level={SettingLevel.PLATFORM} hideIfCannotSet />
|
<SettingsFlag name="Electron.showTrayIcon" level={SettingLevel.PLATFORM} hideIfCannotSet />
|
||||||
<SettingsFlag
|
<SettingsFlag
|
||||||
name="Electron.enableHardwareAcceleration"
|
name="Electron.enableHardwareAcceleration"
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import { SortingAlgorithm } from "../stores/room-list-v3/skip-list/sorters/index
|
|||||||
import MediaPreviewConfigController from "./controllers/MediaPreviewConfigController.ts";
|
import MediaPreviewConfigController from "./controllers/MediaPreviewConfigController.ts";
|
||||||
import InviteRulesConfigController from "./controllers/InviteRulesConfigController.ts";
|
import InviteRulesConfigController from "./controllers/InviteRulesConfigController.ts";
|
||||||
import { type ComputedInviteConfig } from "../@types/invite-rules.ts";
|
import { type ComputedInviteConfig } from "../@types/invite-rules.ts";
|
||||||
|
import ProtocolHandlerController from "./controllers/ProtocolHandlerController.ts";
|
||||||
|
|
||||||
export const defaultWatchManager = new WatchManager();
|
export const defaultWatchManager = new WatchManager();
|
||||||
|
|
||||||
@@ -370,6 +371,7 @@ export interface Settings {
|
|||||||
"mediaPreviewConfig": IBaseSetting<MediaPreviewConfig>;
|
"mediaPreviewConfig": IBaseSetting<MediaPreviewConfig>;
|
||||||
"inviteRules": IBaseSetting<ComputedInviteConfig>;
|
"inviteRules": IBaseSetting<ComputedInviteConfig>;
|
||||||
"Developer.elementCallUrl": IBaseSetting<string>;
|
"Developer.elementCallUrl": IBaseSetting<string>;
|
||||||
|
protocolHandlerRegistered: IBaseSetting<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SettingKey = keyof Settings;
|
export type SettingKey = keyof Settings;
|
||||||
@@ -1345,6 +1347,11 @@ export const SETTINGS: Settings = {
|
|||||||
// Contains room IDs
|
// Contains room IDs
|
||||||
shouldExportToRageshake: false,
|
shouldExportToRageshake: false,
|
||||||
},
|
},
|
||||||
|
"protocolHandlerRegistered": {
|
||||||
|
default: false,
|
||||||
|
controller: new ProtocolHandlerController(),
|
||||||
|
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Enable or disable the release announcement feature
|
* Enable or disable the release announcement feature
|
||||||
*/
|
*/
|
||||||
|
|||||||
26
src/settings/controllers/ProtocolHandlerController.ts
Normal file
26
src/settings/controllers/ProtocolHandlerController.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2024 New Vector Ltd.
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import SettingController from "./SettingController";
|
||||||
|
import PlatformPeg from "../../PlatformPeg";
|
||||||
|
|
||||||
|
export default class ProtocolHandlerController extends SettingController {
|
||||||
|
public constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get settingDisabled() {
|
||||||
|
return PlatformPeg.get()?.registerProtocolHandler === undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onChange(): void {
|
||||||
|
const platform = PlatformPeg.get()!;
|
||||||
|
const uri = platform.baseUrl;
|
||||||
|
platform.registerProtocolHandler!(`${uri}#/%s`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -277,4 +277,8 @@ export default class WebPlatform extends BasePlatform {
|
|||||||
public async getSessionLock(onNewInstance: () => Promise<void>): Promise<boolean> {
|
public async getSessionLock(onNewInstance: () => Promise<void>): Promise<boolean> {
|
||||||
return SessionLock.getSessionLock(onNewInstance);
|
return SessionLock.getSessionLock(onNewInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async registerProtocolHandler(urlPattern: `${string}%s`) {
|
||||||
|
navigator.registerProtocolHandler("matrix", urlPattern);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user