diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3f2d6f8e..0f17bb45 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -38,6 +38,12 @@ android:scheme="https" android:host="matrix.to"/> + + + + + + @@ -67,4 +73,4 @@ android:name="flutterEmbedding" android:value="2" /> - \ No newline at end of file + diff --git a/lib/app_config.dart b/lib/app_config.dart index aa527e43..39fa61da 100644 --- a/lib/app_config.dart +++ b/lib/app_config.dart @@ -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 = diff --git a/lib/components/dialogs/key_verification_dialog.dart b/lib/components/dialogs/key_verification_dialog.dart index 256fcb20..64aa817b 100644 --- a/lib/components/dialogs/key_verification_dialog.dart +++ b/lib/components/dialogs/key_verification_dialog.dart @@ -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'; diff --git a/lib/components/html_message.dart b/lib/components/html_message.dart index bdac0a9d..0828cbd6 100644 --- a/lib/components/html_message.dart +++ b/lib/components/html_message.dart @@ -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) { diff --git a/lib/components/list_items/public_room_list_item.dart b/lib/components/list_items/public_room_list_item.dart index 429cd770..d22d8a67 100644 --- a/lib/components/list_items/public_room_list_item.dart +++ b/lib/components/list_items/public_room_list_item.dart @@ -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'; diff --git a/lib/utils/matrix_identifier_string_extension.dart b/lib/utils/matrix_identifier_string_extension.dart deleted file mode 100644 index 846fb8b9..00000000 --- a/lib/utils/matrix_identifier_string_extension.dart +++ /dev/null @@ -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}); -} diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index a915237e..21db6cd1 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -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); diff --git a/lib/views/chat_details.dart b/lib/views/chat_details.dart index c4ada971..33b9ddae 100644 --- a/lib/views/chat_details.dart +++ b/lib/views/chat_details.dart @@ -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'; diff --git a/lib/views/chat_list.dart b/lib/views/chat_list.dart index 5ae3eff4..85cedbca 100644 --- a/lib/views/chat_list.dart +++ b/lib/views/chat_list.dart @@ -105,7 +105,9 @@ class _ChatListState extends State { 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; } diff --git a/lib/views/invitation_selection.dart b/lib/views/invitation_selection.dart index f9804915..1d826ef0 100644 --- a/lib/views/invitation_selection.dart +++ b/lib/views/invitation_selection.dart @@ -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'; diff --git a/lib/views/new_group.dart b/lib/views/new_group.dart index 1befce32..eb634a0b 100644 --- a/lib/views/new_group.dart +++ b/lib/views/new_group.dart @@ -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, diff --git a/lib/views/new_private_chat.dart b/lib/views/new_private_chat.dart index 12a5bf33..c23b2319 100644 --- a/lib/views/new_private_chat.dart +++ b/lib/views/new_private_chat.dart @@ -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'; diff --git a/pubspec.lock b/pubspec.lock index 98a02127..805ee7e3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -202,7 +202,7 @@ packages: description: path: "." ref: main - resolved-ref: ed8af418f0ed6087ec5378433281c5ba39585c6f + resolved-ref: "0a89ac5564e1a8a98236960aac8eaa251118a051" url: "https://gitlab.com/famedly/famedlysdk.git" source: git version: "0.0.1" @@ -369,7 +369,7 @@ packages: name: flutter_matrix_html url: "https://pub.dartlang.org" source: hosted - version: "0.1.14" + version: "0.2.0" flutter_olm: dependency: "direct main" description: @@ -569,6 +569,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.10-nullsafety.1" + matrix_api_lite: + dependency: transitive + description: + name: matrix_api_lite + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" matrix_file_e2ee: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d1d6bd79..1da28100 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,7 +40,7 @@ dependencies: mime_type: ^0.3.2 flushbar: ^1.10.4 adaptive_dialog: ^0.9.3 - flutter_matrix_html: ^0.1.14 + flutter_matrix_html: ^0.2.0 moor: ^3.4.0 sqlite3_flutter_libs: ^0.3.0 sqlite3: ^0.1.8 diff --git a/test/matrix_identifier_string_extension_test.dart b/test/matrix_identifier_string_extension_test.dart deleted file mode 100644 index d2095689..00000000 --- a/test/matrix_identifier_string_extension_test.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:fluffychat/utils/matrix_identifier_string_extension.dart'; - -void main() { - group('Matrix Identifier String Extension', () { - test('parseIdentifierIntoParts', () { - var res = '#alias:beep'.parseIdentifierIntoParts(); - expect(res.primaryIdentifier, '#alias:beep'); - expect(res.secondaryIdentifier, null); - expect(res.queryString, null); - res = 'blha'.parseIdentifierIntoParts(); - expect(res, null); - res = '#alias:beep/\$event'.parseIdentifierIntoParts(); - expect(res.primaryIdentifier, '#alias:beep'); - expect(res.secondaryIdentifier, '\$event'); - expect(res.queryString, null); - res = '#alias:beep?blubb'.parseIdentifierIntoParts(); - expect(res.primaryIdentifier, '#alias:beep'); - expect(res.secondaryIdentifier, null); - expect(res.queryString, 'blubb'); - res = '#alias:beep/\$event?blubb'.parseIdentifierIntoParts(); - expect(res.primaryIdentifier, '#alias:beep'); - expect(res.secondaryIdentifier, '\$event'); - expect(res.queryString, 'blubb'); - res = '#/\$?:beep/\$event?blubb?b'.parseIdentifierIntoParts(); - expect(res.primaryIdentifier, '#/\$?:beep'); - expect(res.secondaryIdentifier, '\$event'); - expect(res.queryString, 'blubb?b'); - - res = 'https://matrix.to/#/#alias:beep'.parseIdentifierIntoParts(); - expect(res.primaryIdentifier, '#alias:beep'); - expect(res.secondaryIdentifier, null); - expect(res.queryString, null); - res = 'https://matrix.to/#/%23alias%3abeep'.parseIdentifierIntoParts(); - expect(res.primaryIdentifier, '#alias:beep'); - expect(res.secondaryIdentifier, null); - expect(res.queryString, null); - res = 'https://matrix.to/#/%23alias%3abeep?boop%F0%9F%A7%A1%F0%9F%A6%8A' - .parseIdentifierIntoParts(); - expect(res.primaryIdentifier, '#alias:beep'); - expect(res.secondaryIdentifier, null); - expect(res.queryString, 'boop%F0%9F%A7%A1%F0%9F%A6%8A'); - }); - }); -}