feat: Handle matrix: URIs as per MSC2312

This commit is contained in:
Sorunome 2021-01-10 18:00:27 +01:00
commit 03058d44e6
15 changed files with 41 additions and 101 deletions

View file

@ -22,6 +22,7 @@ abstract class AppConfig {
static const bool hideTypingUsernames = false;
static const bool hideAllStateEvents = false;
static const String inviteLinkPrefix = 'https://matrix.to/#/';
static const String schemePrefix = 'matrix:';
static const String pushNotificationsChannelId = 'fluffychat_push';
static const String pushNotificationsChannelName = 'FluffyChat push channel';
static const String pushNotificationsChannelDescription =

View file

@ -1,6 +1,6 @@
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/encryption.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

View file

@ -53,14 +53,15 @@ class HtmlMessage extends StatelessWidget {
maxLines: maxLines,
onLinkTap: (url) => UrlLauncher(context, url).launchUrl(),
onPillTap: (url) => UrlLauncher(context, url).launchUrl(),
getMxcUrl: (String mxc, double width, double height) {
getMxcUrl: (String mxc, double width, double height,
{bool animated = false}) {
final ratio = MediaQuery.of(context).devicePixelRatio;
return Uri.parse(mxc)?.getThumbnail(
matrix.client,
width: (width ?? 800) * ratio,
height: (height ?? 800) * ratio,
method: ThumbnailMethod.scale,
animated: true,
animated: animated,
);
},
setCodeLanguage: (String key, String value) async {
@ -69,11 +70,16 @@ class HtmlMessage extends StatelessWidget {
getCodeLanguage: (String key) async {
return await matrix.store.getItem('${SettingKeys.codeLanguage}.$key');
},
getPillInfo: (String identifier) async {
getPillInfo: (String url) async {
if (room == null) {
return null;
}
if (identifier[0] == '@') {
final identityParts = url.parseIdentifierIntoParts();
final identifier = identityParts?.primaryIdentifier;
if (identifier == null) {
return null;
}
if (identifier.sigil == '@') {
// we have a user pill
final user = room.getState('m.room.member', identifier);
if (user != null) {
@ -89,7 +95,7 @@ class HtmlMessage extends StatelessWidget {
}
return null;
}
if (identifier[0] == '#') {
if (identifier.sigil == '#') {
// we have an alias pill
for (final r in room.client.rooms) {
final state = r.getState('m.room.canonical_alias');
@ -107,7 +113,7 @@ class HtmlMessage extends StatelessWidget {
}
return null;
}
if (identifier[0] == '!') {
if (identifier.sigil == '!') {
// we have a room ID pill
final r = room.client.getRoomById(identifier);
if (r == null) {

View file

@ -1,5 +1,4 @@
import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';

View file

@ -1,33 +0,0 @@
import '../app_config.dart';
extension MatrixIdentifierStringExtension on String {
/// Separates room identifiers with an event id and possibly a query parameter into its components.
MatrixIdentifierStringExtensionResults parseIdentifierIntoParts() {
final isUrl = startsWith(AppConfig.inviteLinkPrefix);
var s = this;
if (isUrl) {
// as we decode a component we may only call it on the url part *before* the "query" part
final parts = replaceFirst(AppConfig.inviteLinkPrefix, '').split('?');
s = Uri.decodeComponent(parts.removeAt(0)) + '?' + parts.join('?');
}
final match = RegExp(r'^([#!@+][^:]*:[^\/?]*)(?:\/(\$[^?]*))?(?:\?(.*))?$')
.firstMatch(s);
if (match == null) {
return null;
}
return MatrixIdentifierStringExtensionResults(
primaryIdentifier: match.group(1),
secondaryIdentifier: match.group(2),
queryString: match.group(3)?.isNotEmpty ?? false ? match.group(3) : null,
);
}
}
class MatrixIdentifierStringExtensionResults {
final String primaryIdentifier;
final String secondaryIdentifier;
final String queryString;
MatrixIdentifierStringExtensionResults(
{this.primaryIdentifier, this.secondaryIdentifier, this.queryString});
}

View file

@ -8,7 +8,6 @@ import 'package:fluffychat/views/chat.dart';
import 'package:fluffychat/views/discover_view.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'matrix_identifier_string_extension.dart';
class UrlLauncher {
final String url;
@ -16,8 +15,9 @@ class UrlLauncher {
const UrlLauncher(this.context, this.url);
void launchUrl() {
if (url.startsWith(AppConfig.inviteLinkPrefix) ||
{'#', '@', '!', '+', '\$'}.contains(url[0])) {
if (url.toLowerCase().startsWith(AppConfig.inviteLinkPrefix) ||
{'#', '@', '!', '+', '\$'}.contains(url[0]) ||
url.toLowerCase().startsWith(AppConfig.schemePrefix)) {
return openMatrixToUrl();
}
launch(url);

View file

@ -4,7 +4,6 @@ import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/views/chat_permissions_settings.dart';
import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:file_picker_cross/file_picker_cross.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';

View file

@ -105,7 +105,9 @@ class _ChatListState extends State<ChatList> {
if (Navigator.of(context).canPop()) {
Navigator.of(context).popUntil((r) => r.isFirst);
}
if (text.startsWith(AppConfig.inviteLinkPrefix)) {
if (text.toLowerCase().startsWith(AppConfig.inviteLinkPrefix) ||
(text.toLowerCase().startsWith(AppConfig.schemePrefix) &&
!RegExp(r'\s').hasMatch(text))) {
UrlLauncher(context, text).openMatrixToUrl();
return;
}

View file

@ -3,7 +3,6 @@ import 'dart:async';
import 'package:fluffychat/components/default_app_bar_search_field.dart';
import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/avatar.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';

View file

@ -1,4 +1,4 @@
import 'package:famedlysdk/matrix_api.dart' as api;
import 'package:famedlysdk/famedlysdk.dart' as sdk;
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart';
@ -37,9 +37,9 @@ class _NewGroupState extends State<_NewGroup> {
context: context,
future: () => matrix.client.createRoom(
preset: publicGroup
? api.CreateRoomPreset.public_chat
: api.CreateRoomPreset.private_chat,
visibility: publicGroup ? api.Visibility.public : null,
? sdk.CreateRoomPreset.public_chat
: sdk.CreateRoomPreset.private_chat,
visibility: publicGroup ? sdk.Visibility.public : null,
roomAliasName:
publicGroup && controller.text.isNotEmpty ? controller.text : null,
name: controller.text.isNotEmpty ? controller.text : null,

View file

@ -1,7 +1,6 @@
import 'dart:async';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/avatar.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';