add matrix: URI deeplinking

Fixes #148

Needs cross-platform testing, currently only tested on Android.
This commit is contained in:
Henry Hiles 2026-11-01 11:52:13 -05:00
commit 51e3fe1007
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
2 changed files with 108 additions and 45 deletions

View file

@ -1,15 +1,11 @@
import "package:material_ui/material_ui.dart";
import "package:nexus/helpers/extensions/show_adaptive_sheet.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/event.dart";
import "package:nexus/controllers/room_summary.dart";
import "package:nexus/controllers/user.dart";
import "package:nexus/helpers/extensions/focus_room.dart";
import "package:nexus/helpers/extensions/get_link_info.dart";
import "package:nexus/helpers/extensions/show_user_popover.dart";
import "package:nexus/helpers/extensions/open_link_info.dart";
import "package:nexus/models/content/membership.dart";
import "package:nexus/models/room_summary.dart";
import "package:nexus/widgets/room_summary_sheet.dart";
class const MentionChip(final String content, final String? roomId, {super.key})
extends ConsumerWidget {
@ -28,7 +24,9 @@ class const MentionChip(final String content, final String? roomId, {super.key})
"#" || "!" =>
ref
.watch(
RoomSummaryController.provider(.new(roomIdOrAlias: mention!)),
RoomSummaryController.provider(
.new(roomIdOrAlias: mention!, via: linkInfo!.via),
),
)
.whenOrNull(data: (data) => data) ??
RoomSummary(roomId: mention),
@ -39,43 +37,7 @@ class const MentionChip(final String content, final String? roomId, {super.key})
return mention == null
? SizedBox.shrink()
: InkWell(
onTap: () async {
if (data is MembershipContent) {
context.showUserPopover(mention, roomId: roomId);
} else if (data case RoomSummary summary) {
final eventRowId = linkInfo?.eventId == null
? null
: await ref
.read(
EventController.provider(
.new(
roomId: summary.roomId,
eventId: linkInfo!.eventId!,
),
).selectAsync((data) => data?.rowId),
)
.onError((_, _) => null);
if (!await ref.focusRoom(summary.roomId, eventRowId) &&
context.mounted) {
context.showAdaptiveSheet(
(context) => Consumer(
builder: (context, ref, _) => RoomSummarySheet(
ref
.watch(
RoomSummaryController.provider(
.new(roomIdOrAlias: mention),
),
)
.whenOrNull(data: (data) => data) ??
summary,
via: linkInfo?.via,
),
),
);
}
}
},
onTap: () => ref.openLinkInfo(context, linkInfo!, roomId: roomId),
child: Text(
switch (data) {
RoomSummary summary =>

View file

@ -2,6 +2,9 @@ import "package:flutter_hooks/flutter_hooks.dart";
import "package:material_ui/material_ui.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/controllers/init_complete.dart";
import "package:nexus/controllers/link_request.dart";
import "package:nexus/helpers/extensions/open_link_info.dart";
import "package:nexus/main.dart";
import "package:nexus/controllers/selected_room.dart";
import "package:nexus/controllers/notification_request.dart";
import "package:nexus/helpers/extensions/is_desktop.dart";
@ -33,6 +36,23 @@ class const ChatPage({super.key}) extends HookConsumerWidget {
return null;
}, [notificationRequest, initComplete]);
final linkRequest = ref.watch(LinkRequestController.provider);
// Open Matrix links the OS launched Nexus with, once sync has completed
useEffect(() {
if (linkRequest == null || !initComplete) return null;
WidgetsBinding.instance.addPostFrameCallback((_) {
ref.read(LinkRequestController.provider.notifier).consume();
navigatorKey.currentState?.popUntil((route) => route.isFirst);
final navigatorContext = navigatorKey.currentContext;
if (navigatorContext == null) return;
ref.openLinkInfo(navigatorContext, linkRequest).onError(showError);
});
return null;
}, [linkRequest, initComplete]);
return LayoutBuilder(
builder: (context, constraints) {
final isDesktop = context.isDesktop;