Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clickable roomId on message #1268

Merged
merged 6 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changes/1268-clickable-room-id.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- [enhance] Copy room link instead of roomId
- [fix] Click on room link will perform appropriate action
1 change: 1 addition & 0 deletions app/lib/common/utils/rooms.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Future<void> joinRoom(
if (!context.mounted) {
return;
}
Navigator.of(context, rootNavigator: true).pop();
showAdaptiveDialog(
barrierDismissible: false,
context: context,
Expand Down
119 changes: 117 additions & 2 deletions app/lib/features/chat/chat_utils/chat_utils.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import 'package:html/dom.dart';
import 'package:acter/common/providers/room_providers.dart';
import 'package:acter/common/utils/rooms.dart';
import 'package:acter/common/utils/routes.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:html/dom.dart' as html;

class UserMentionMessageData {
String parsedMessage;
Expand All @@ -14,7 +20,7 @@ class UserMentionMessageData {

UserMentionMessageData parseUserMentionMessage(
String message,
Element aTagElement,
html.Element aTagElement,
) {
String msg = message;
String userName = '';
Expand Down Expand Up @@ -51,3 +57,112 @@ UserMentionMessageData parseUserMentionMessage(
displayName: displayName,
);
}

String? getRoomIdFromLink(Uri uri) {
final link = Uri.decodeFull(uri.toString());

// Match regex for matrix room link
final urlRegexp = RegExp(
r'https://matrix\.to/#/(?<roomId>.+):(?<server>.+)+',
caseSensitive: false,
);
final matches = urlRegexp.firstMatch(link);
Comment on lines +65 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

matrix:// is also a valid link format: https://spec.matrix.org/v1.9/appendices/#uris

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can I get link like matrix:// from Acter or Element general?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure which clients are sending those at the moment... the element-x iOS maybe?

Copy link
Contributor Author

@kumarpalsinh25 kumarpalsinh25 Jan 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gnunicorn
No, I have check element web and element iOS. Both are sending matrix.to url.

And matrix:// is not a link url,I believe It is url schema which is generally used in deep linking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gnunicorn

  • Is there any platform or way using with I can get matrix:// and test it?
  • If matrix:// type of url are consider as url schema then still I have to handle condition for it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

matrix.to is the old, matrix: is the new way of doing it.

@gnunicorn
Sorry but I'm not agree with that.

Not sure but based on the my knowledge matrix:// and matrix.to are different things and have their own purposes.

  • matrix:// is Matrix URI scheme which ideally suitable in deep-linking for direct intent calls
  • matrix.to is Matrix Navigation URL and widely used by all the matrix platforms but general navigations.

For better clarification, I'm looking for any platform which is using matrix:// (Matrix URI Scheme definition).
If you have any idea about such matrix platforms then can you please share it so that I can look into the same and get detail understanding.

And if you don't mind then can we proceed with this PR as this PR is mainly for copying RoomID URL from profile page and user should able to handle it with click on that message like element and other platforms doing because matrix:// is different thing and don't have any use-case at least in Acter App.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are different things and have their own purposes.

That is a misunderstanding though. Quoting the spec, about the matrix.to it says: "This namespacing existed prior to a matrix: scheme." hinting to the fact that they do the same but the existence of both is just an historically artifact to stay backwards compatible when matrix: was added: Both are used for deep-linking (clicking the matrix.to-link on a smartphone with element on it, you will see it come up), and targeting the same objects. From a purpose perspective they do and are the same. With matrix: (no double // after the :by the way) being the one for the future and matrix.to being the fallback.

Thus if want to only use one, we should do the matrix:-format and not the old one but we are only using the legacy with this PR. If you don't want to implement this now, let's open a ticket saying we need matrix:-protocol-support.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @gnunicorn for details understanding.
If matrix:// is the new way then for navigating and deep-link then I would like to integrate that way in Acter and have support for both.

@gnunicorn Do you have idea of any of the matrix platform which is using this new way? I just wanted to confirm certain use-cases with that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have idea of any of the matrix platform which is using this new way? I just wanted to confirm certain use-cases with that.

as said, if Element-X isn't using it, I wouldn't know if any does. According to the original spec proposal fluffychat and nheko have support for it (don't know if they post use it primarily though).

FYI, when I say the "new way" of doing it ... the Spec was merged 2021 .... and looks like even Element doesn't use it primarily yet, so ....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, I see..
Let me create create new ticket for "matrix:-protocol-support" and then we can move on with current matrix.to support.


//Link is type of matrix room link
if (matches != null) {
final roomId = matches.namedGroup('roomId');
var server = matches.namedGroup('server');

//Check & remove if string contains "?via=<server> pattern"
server = server!.split('?via=').first;

//Create complete roomId with home server information
var roomIdWithServer = '$roomId:$server';

//Return roomId
return roomIdWithServer;
}

//Link is other than matrix room link
return null;
}

Future<void> navigateToRoomOrAskToJoin(
BuildContext context,
WidgetRef ref,
String roomId,
) async {
///Get room from roomId
final room = await ref.watch(maybeRoomProvider(roomId).future);
if (!context.mounted) return;

/// Navigate to Room is already joined
if (room != null && room.isJoined()) {
//Navigate to Space
if (room.isSpace()) {
context.pushNamed(
Routes.space.name,
pathParameters: {'spaceId': room.roomIdStr()},
);
}
//Navigate to Chat
else {
context.goNamed(
Routes.chatroom.name,
pathParameters: {'roomId': room.roomIdStr()},
);
}
}

/// Ask to join room if not yet joined
else {
askToJoinRoom(context, ref, roomId);
}
}

void askToJoinRoom(
BuildContext context,
WidgetRef ref,
String roomId,
) async {
showModalBottomSheet(
context: context,
isDismissible: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
),
),
builder: (ctx) => Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'You are not part of this group. Would you like to join?',
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();
final server = roomId.split(':').last;
await joinRoom(
context,
ref,
'Trying to join $roomId',
roomId,
server,
(roomId) => navigateToRoomOrAskToJoin(context, ref, roomId),
);
},
child: const Text('Join Room'),
),
],
),
),
);
}
6 changes: 4 additions & 2 deletions app/lib/features/chat/pages/room_profile_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ class RoomProfilePage extends ConsumerWidget {
tiles: [
SettingsTile(
onPressed: (ctx) {
//FIXME : ?via=$serverName data should be handle from rust helper function
final serverName = roomId.split(':').last;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't really how via is meant to work. See the matrix URI spec for details. But ideally via tells you about (additional) servers that we know to be in the room as alternative ways to connect to the room (in particular if the homeserver isn't available). Just repeating the homeserver is a bit of a short-cut that doesn't in practice actually help doing the right resolution.

We can keep this for now, but should probably add a helper function on the rust side that compiles the actual correct information including via.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok got it. I will check for matrix specification and do required changes accordingly.

Copy link
Contributor Author

@kumarpalsinh25 kumarpalsinh25 Jan 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have read the documentations, and agree with you that repeating the homeserver doesn't make sense.

I'm adding FIXME comment and once rust side helper function is ready then will change it accordingly.

Clipboard.setData(
ClipboardData(
text: roomId,
text: 'https://matrix.to/#/$roomId?via=$serverName',
),
);
customMsgSnackbar(
Expand All @@ -150,7 +152,7 @@ class RoomProfilePage extends ConsumerWidget {
);
},
title: Text(
'Copy Room ID',
'Copy room link',
style: tileTextTheme,
),
leading: const Icon(Atlas.chain_link_thin, size: 18),
Expand Down
22 changes: 18 additions & 4 deletions app/lib/features/chat/widgets/text_message_builder.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:acter/common/themes/app_theme.dart';
import 'package:acter/common/themes/chat_theme.dart';
import 'package:acter/common/utils/utils.dart';
import 'package:acter/features/chat/chat_utils/chat_utils.dart';
import 'package:acter/features/chat/providers/chat_providers.dart';
import 'package:acter/features/home/providers/client_providers.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart';
Expand Down Expand Up @@ -56,7 +57,7 @@ class _TextMessageBuilderConsumerState
//remove mx-reply tags.
String parsedString = simplifyBody(widget.message.text);
final urlRegexp = RegExp(
r'https://matrix\.to/#/@[A-Za-z0-9\-]+:[A-Za-z0-9\-]+\.[A-Za-z0-9\-]+',
r'https://matrix\.to/#/[@!#][A-Za-z0-9\-]+:[A-Za-z0-9\-]+\.[A-Za-z0-9\-]+',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

matrix:// is also a valid link we need to check for https://spec.matrix.org/v1.9/appendices/#uris

caseSensitive: false,
);
final matches = urlRegexp.allMatches(parsedString);
Expand Down Expand Up @@ -153,9 +154,7 @@ class _TextWidget extends ConsumerWidget {
maxLines: isReply ? 3 : null,
)
: Html(
onLinkTap: (url) async {
await openLink(url.toString(), context);
},
onLinkTap: (url) => onLinkTap(url, context, ref),
backgroundColor: Colors.transparent,
data: message.text,
shrinkToFit: true,
Expand Down Expand Up @@ -184,4 +183,19 @@ class _TextWidget extends ConsumerWidget {
],
);
}

Future<void> onLinkTap(Uri uri, BuildContext context, WidgetRef ref) async {
final roomId = getRoomIdFromLink(uri);

///If link is type of matrix room link
if (roomId != null) {
await navigateToRoomOrAskToJoin(context, ref, roomId);
}

///If link is other than matrix room link
///Then open it on browser
else {
await openLink(uri.toString(), context);
}
}
}
Loading
Loading