From ba6ebfc922b131e32970051391abadf41cd060dc Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 22 May 2026 22:32:47 +0200 Subject: [PATCH 1/2] Directly open Matrix URI when showing link This should directly offer to open the default Matrix client a user has, if they have any and confirm the process. This should provide a more seamless experience once matrix: URIs are more widely adopted. If the user doesn't have any such Matrix client, this will do nothing. Signed-off-by: Nicolas Werner --- src/open/OpenLinkViewModel.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/open/OpenLinkViewModel.js b/src/open/OpenLinkViewModel.js index 2b5d2954..edd85a79 100644 --- a/src/open/OpenLinkViewModel.js +++ b/src/open/OpenLinkViewModel.js @@ -21,6 +21,7 @@ import {PreviewViewModel} from "../preview/PreviewViewModel.js"; import {ServerConsentViewModel} from "./ServerConsentViewModel.js"; import {getLabelForLinkKind} from "../Link.js"; import {orderedUnique} from "../utils/unique.js"; +import {LinkKind} from "./types.js"; export class OpenLinkViewModel extends ViewModel { constructor(options) { @@ -37,6 +38,36 @@ export class OpenLinkViewModel extends ViewModel { } else { this._showLink(); } + + this._openLink(); + } + + async _openLink() { + // Proactively try to open the default Matrix client of the user. + let link = this._link; + let identifier = encodeURIComponent(link.identifier.substring(1)); + let isRoomid = link.identifier.substring(0, 1) === '!'; + let fragmentPath; + switch (link.kind) { + case LinkKind.User: + fragmentPath = `u/${identifier}?action=chat`; + break; + case LinkKind.Room: + case LinkKind.Event: + if (isRoomid) + fragmentPath = `roomid/${identifier}`; + else + fragmentPath = `r/${identifier}`; + + if (link.kind === LinkKind.Event) + fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`; + fragmentPath += '?action=join'; + fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join(''); + break; + case LinkKind.Group: + return; + } + window.open(`matrix:${fragmentPath}`, '_self'); } _showServerConsent() { From cbdced34cde9a78fe719e6c51aed39d89ae503fb Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 22 May 2026 22:45:55 +0200 Subject: [PATCH 2/2] Deduplicate Matrix URI generation code Signed-off-by: Nicolas Werner --- src/Link.js | 26 ++++++++++++++++++++++++++ src/open/OpenLinkViewModel.js | 27 ++------------------------- src/open/clients/Fractal.js | 25 ++----------------------- src/open/clients/NeoChat.js | 25 ++----------------------- src/open/clients/Nheko.js | 25 ++----------------------- 5 files changed, 34 insertions(+), 94 deletions(-) diff --git a/src/Link.js b/src/Link.js index 9eb96cea..32fa7b83 100644 --- a/src/Link.js +++ b/src/Link.js @@ -216,4 +216,30 @@ export class Link { return `/${this.identifier}`; } } + + static toMatrixUri(link) { + let identifier = encodeURIComponent(link.identifier.substring(1)); + let isRoomid = link.identifier.substring(0, 1) === '!'; + let fragmentPath; + switch (link.kind) { + case LinkKind.User: + fragmentPath = `u/${identifier}?action=chat`; + break; + case LinkKind.Room: + case LinkKind.Event: + if (isRoomid) + fragmentPath = `roomid/${identifier}`; + else + fragmentPath = `r/${identifier}`; + + if (link.kind === LinkKind.Event) + fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`; + fragmentPath += '?action=join'; + fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join(''); + break; + case LinkKind.Group: + return; + } + return `matrix:${fragmentPath}`; + } } diff --git a/src/open/OpenLinkViewModel.js b/src/open/OpenLinkViewModel.js index edd85a79..7825a69a 100644 --- a/src/open/OpenLinkViewModel.js +++ b/src/open/OpenLinkViewModel.js @@ -21,7 +21,7 @@ import {PreviewViewModel} from "../preview/PreviewViewModel.js"; import {ServerConsentViewModel} from "./ServerConsentViewModel.js"; import {getLabelForLinkKind} from "../Link.js"; import {orderedUnique} from "../utils/unique.js"; -import {LinkKind} from "./types.js"; +import {Link} from "../Link.js" export class OpenLinkViewModel extends ViewModel { constructor(options) { @@ -44,30 +44,7 @@ export class OpenLinkViewModel extends ViewModel { async _openLink() { // Proactively try to open the default Matrix client of the user. - let link = this._link; - let identifier = encodeURIComponent(link.identifier.substring(1)); - let isRoomid = link.identifier.substring(0, 1) === '!'; - let fragmentPath; - switch (link.kind) { - case LinkKind.User: - fragmentPath = `u/${identifier}?action=chat`; - break; - case LinkKind.Room: - case LinkKind.Event: - if (isRoomid) - fragmentPath = `roomid/${identifier}`; - else - fragmentPath = `r/${identifier}`; - - if (link.kind === LinkKind.Event) - fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`; - fragmentPath += '?action=join'; - fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join(''); - break; - case LinkKind.Group: - return; - } - window.open(`matrix:${fragmentPath}`, '_self'); + window.open(Link.toMatrixUri(this._link), '_self'); } _showServerConsent() { diff --git a/src/open/clients/Fractal.js b/src/open/clients/Fractal.js index b2c06373..c77a98ed 100644 --- a/src/open/clients/Fractal.js +++ b/src/open/clients/Fractal.js @@ -15,6 +15,7 @@ limitations under the License. */ import {Maturity, Platform, LinkKind, FlathubLink} from "../types.js"; +import {Link} from "../../Link.js" /** * Information on how to deep link to a given matrix client. @@ -31,29 +32,7 @@ export class Fractal { getDeepLink(platform, link) { if (platform === Platform.Linux) { - let identifier = encodeURIComponent(link.identifier.substring(1)); - let isRoomid = link.identifier.substring(0, 1) === '!'; - let fragmentPath; - switch (link.kind) { - case LinkKind.User: - fragmentPath = `u/${identifier}?action=chat`; - break; - case LinkKind.Room: - case LinkKind.Event: - if (isRoomid) - fragmentPath = `roomid/${identifier}`; - else - fragmentPath = `r/${identifier}`; - - if (link.kind === LinkKind.Event) - fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`; - fragmentPath += '?action=join'; - fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join(''); - break; - case LinkKind.Group: - return; - } - return `matrix:${fragmentPath}`; + return Link.toMatrixUri(link); } } diff --git a/src/open/clients/NeoChat.js b/src/open/clients/NeoChat.js index 2e43a11d..2c72b1ff 100644 --- a/src/open/clients/NeoChat.js +++ b/src/open/clients/NeoChat.js @@ -16,6 +16,7 @@ limitations under the License. */ import {Maturity, Platform, LinkKind, FlathubLink, style} from "../types.js"; +import {Link} from "../../Link.js" export class NeoChat { get id() { return "neochat"; } @@ -28,29 +29,7 @@ export class NeoChat { getMaturity(platform) { return Maturity.Beta; } getDeepLink(platform, link) { if (platform === Platform.Linux || platform === Platform.Windows) { - let identifier = encodeURIComponent(link.identifier.substring(1)); - let isRoomid = link.identifier.substring(0, 1) === '!'; - let fragmentPath; - switch (link.kind) { - case LinkKind.User: - fragmentPath = `u/${identifier}?action=chat`; - break; - case LinkKind.Room: - case LinkKind.Event: - if (isRoomid) - fragmentPath = `roomid/${identifier}`; - else - fragmentPath = `r/${identifier}`; - - if (link.kind === LinkKind.Event) - fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`; - fragmentPath += '?action=join'; - fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join(''); - break; - case LinkKind.Group: - return; - } - return `matrix:${fragmentPath}`; + return Link.toMatrixUri(link); } } canInterceptMatrixToLinks(platform) { return false; } diff --git a/src/open/clients/Nheko.js b/src/open/clients/Nheko.js index e8615267..6c10fcc4 100644 --- a/src/open/clients/Nheko.js +++ b/src/open/clients/Nheko.js @@ -15,6 +15,7 @@ limitations under the License. */ import {Maturity, Platform, LinkKind, FlathubLink, WebsiteLink, style} from "../types.js"; +import {Link} from "../../Link.js" /** * Information on how to deep link to a given matrix client. @@ -30,29 +31,7 @@ export class Nheko { getMaturity(platform) { return Maturity.Beta; } getDeepLink(platform, link) { if (platform === Platform.Linux || platform === Platform.Windows) { - let identifier = encodeURIComponent(link.identifier.substring(1)); - let isRoomid = link.identifier.substring(0, 1) === '!'; - let fragmentPath; - switch (link.kind) { - case LinkKind.User: - fragmentPath = `u/${identifier}?action=chat`; - break; - case LinkKind.Room: - case LinkKind.Event: - if (isRoomid) - fragmentPath = `roomid/${identifier}`; - else - fragmentPath = `r/${identifier}`; - - if (link.kind === LinkKind.Event) - fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`; - fragmentPath += '?action=join'; - fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join(''); - break; - case LinkKind.Group: - return; - } - return `matrix:${fragmentPath}`; + return Link.toMatrixUri(link); } } canInterceptMatrixToLinks(platform) { return false; }