From 04cbf0c3325fa0ae2e9bb3d751cfcf9fe08b39cc Mon Sep 17 00:00:00 2001 From: Sorunome Date: Sat, 5 Sep 2020 13:45:03 +0200 Subject: [PATCH] feat: open links better --- CHANGELOG.md | 5 ++ lib/components/html_message.dart | 10 +--- lib/components/message_content.dart | 4 +- lib/utils/url_launcher.dart | 91 ++++++++++++++++++++++------- lib/views/chat_details.dart | 5 +- pubspec.lock | 52 ++++++++++++----- pubspec.yaml | 7 +-- 7 files changed, 127 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3359a7b..7b634a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Version 0.18.0 - 2020-09-?? ### Features - Added translations: Armenian, Turkish, Chinese (Simplified) +- Url-ify matrix identifiers +### Changes +- Tapping links, pills, etc. now does stuff +### Fixes: +- Various html rendering and url-ifying fixes # Version 0.17.0 - 2020-08-31 ### Features diff --git a/lib/components/html_message.dart b/lib/components/html_message.dart index 2008ee0..c7ea8b8 100644 --- a/lib/components/html_message.dart +++ b/lib/components/html_message.dart @@ -1,7 +1,7 @@ import 'package:famedlysdk/famedlysdk.dart'; import 'package:flutter_matrix_html/flutter_html.dart'; import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; +import '../utils/url_launcher.dart'; import 'matrix.dart'; @@ -42,12 +42,8 @@ class HtmlMessage extends StatelessWidget { ), shrinkToFit: true, maxLines: maxLines, - onLinkTap: (String url) { - if (url == null || url.isEmpty) { - return; - } - launch(url); - }, + onLinkTap: (url) => UrlLauncher(context, url).launchUrl(), + onPillTap: (url) => UrlLauncher(context, url).launchUrl(), getMxcUrl: (String mxc, double width, double height) { final ratio = MediaQuery.of(context).devicePixelRatio; return Uri.parse(mxc)?.getThumbnail( diff --git a/lib/components/message_content.dart b/lib/components/message_content.dart index 5064010..3142b48 100644 --- a/lib/components/message_content.dart +++ b/lib/components/message_content.dart @@ -4,11 +4,12 @@ import 'package:fluffychat/components/image_bubble.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/utils/event_extension.dart'; import 'package:flutter/material.dart'; -import 'package:link_text/link_text.dart'; +import 'package:matrix_link_text/link_text.dart'; import 'package:url_launcher/url_launcher.dart'; import 'matrix.dart'; import 'message_download_content.dart'; import 'html_message.dart'; +import '../utils/url_launcher.dart'; class MessageContent extends StatelessWidget { final Event event; @@ -84,6 +85,7 @@ class MessageContent extends StatelessWidget { fontSize: DefaultTextStyle.of(context).style.fontSize, decoration: event.redacted ? TextDecoration.lineThrough : null, ), + onLinkTap: (url) => UrlLauncher(context, url).launchUrl(), ); } break; diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index ebc776b..9c6d314 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -12,7 +12,8 @@ class UrlLauncher { const UrlLauncher(this.context, this.url); void launchUrl() { - if (url.startsWith('https://matrix.to/#/')) { + if (url.startsWith('https://matrix.to/#/') || + {'#', '@', '!', '+', '\$'}.contains(url[0])) { return openMatrixToUrl(); } launch(url); @@ -21,33 +22,83 @@ class UrlLauncher { void openMatrixToUrl() async { final matrix = Matrix.of(context); final identifier = url.replaceAll('https://matrix.to/#/', ''); - if (identifier.substring(0, 1) == '#') { - final response = await SimpleDialogs(context).tryRequestWithLoadingDialog( - matrix.client.joinRoom( - Uri.encodeComponent(identifier), - ), - ); - if (response == false) return; - await Navigator.pushAndRemoveUntil( - context, - AppRoute.defaultRoute(context, ChatView(response['room_id'])), - (r) => r.isFirst, - ); - } else if (identifier.substring(0, 1) == '@') { + if (identifier[0] == '#' || identifier[0] == '!') { + var room = matrix.client.getRoomByAlias(identifier); + room ??= matrix.client.getRoomById(identifier); + var roomId = room?.id; + var servers = []; + if (room == null && identifier == '#') { + // we were unable to find the room locally...so resolve it + final response = + await SimpleDialogs(context).tryRequestWithLoadingDialog( + matrix.client.requestRoomAliasInformations(identifier), + ); + if (response != false) { + roomId = response.roomId; + servers = response.servers; + room = matrix.client.getRoomById(roomId); + } + } + if (room != null) { + // we have the room, so....just open it! + await Navigator.pushAndRemoveUntil( + context, + AppRoute.defaultRoute(context, ChatView(room.id)), + (r) => r.isFirst, + ); + return; + } + if (identifier == '!') { + roomId = identifier; + } + if (roomId == null) { + // we haven't found this room....so let's ignore it + return; + } + if (await SimpleDialogs(context) + .askConfirmation(titleText: 'Join room $identifier')) { + final response = + await SimpleDialogs(context).tryRequestWithLoadingDialog( + matrix.client.joinRoomOrAlias( + Uri.encodeComponent(roomId), + servers: servers, + ), + ); + if (response == false) return; + await Navigator.pushAndRemoveUntil( + context, + AppRoute.defaultRoute(context, ChatView(response['room_id'])), + (r) => r.isFirst, + ); + } + } else if (identifier[0] == '@') { final user = User( identifier, room: Room(id: '', client: matrix.client), ); - final String roomID = await SimpleDialogs(context) - .tryRequestWithLoadingDialog(user.startDirectChat()); - Navigator.of(context).pop(); - - if (roomID != null) { + var roomId = matrix.client.getDirectChatFromUserId(identifier); + if (roomId != null) { await Navigator.pushAndRemoveUntil( context, - AppRoute.defaultRoute(context, ChatView(roomID)), + AppRoute.defaultRoute(context, ChatView(roomId)), (r) => r.isFirst, ); + return; + } + + if (await SimpleDialogs(context) + .askConfirmation(titleText: 'Message user $identifier')) { + roomId = await SimpleDialogs(context) + .tryRequestWithLoadingDialog(user.startDirectChat()); + Navigator.of(context).pop(); + + if (roomId != null) { + await Navigator.pushAndRemoveUntil( + context, + AppRoute.defaultRoute(context, ChatView(roomId)), + (r) => r.isFirst, + ); + } } } } diff --git a/lib/views/chat_details.dart b/lib/views/chat_details.dart index 12f5235..4d2ba39 100644 --- a/lib/views/chat_details.dart +++ b/lib/views/chat_details.dart @@ -14,9 +14,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:link_text/link_text.dart'; +import 'package:matrix_link_text/link_text.dart'; import 'package:memoryfilepicker/memoryfilepicker.dart'; import './settings_emotes.dart'; +import '../utils/url_launcher.dart'; class ChatDetails extends StatefulWidget { final Room room; @@ -222,6 +223,8 @@ class _ChatDetailsState extends State { .bodyText2 .color, ), + onLinkTap: (url) => + UrlLauncher(context, url).launchUrl(), ), onTap: widget.room.canSendEvent('m.room.topic') ? () => setTopicAction(context) diff --git a/pubspec.lock b/pubspec.lock index 8b36763..28b5883 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -78,6 +78,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.9+1" + cached_network_image: + dependency: transitive + description: + name: cached_network_image + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" canonical_json: dependency: transitive description: @@ -270,12 +277,10 @@ packages: flutter_matrix_html: dependency: "direct main" description: - path: "." - ref: "530df434b50002e04cbad63f53d6f0f5d5adbab5" - resolved-ref: "530df434b50002e04cbad63f53d6f0f5d5adbab5" - url: "https://github.com/Sorunome/flutter_matrix_html" - source: git - version: "0.1.2" + name: flutter_matrix_html + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" flutter_olm: dependency: "direct main" description: @@ -426,13 +431,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.3-nullsafety" - link_text: - dependency: "direct main" - description: - name: link_text - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.2" localstorage: dependency: "direct main" description: @@ -468,6 +466,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" + matrix_link_text: + dependency: "direct main" + description: + name: matrix_link_text + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" memoryfilepicker: dependency: "direct main" description: @@ -524,6 +529,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.4.12" + octo_image: + dependency: transitive + description: + name: octo_image + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" olm: dependency: transitive description: @@ -685,6 +697,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.4.0+2" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.dartlang.org" + source: hosted + version: "0.24.1" share: dependency: "direct main" description: @@ -886,6 +905,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.2" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 82097db..e864bb0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,7 +40,7 @@ dependencies: ref: master firebase_messaging: ^6.0.13 flutter_local_notifications: ^1.4.3 - link_text: ^0.1.1 + matrix_link_text: ^0.1.4 path_provider: ^1.5.1 webview_flutter: ^0.3.19+9 share: ^0.6.3+5 @@ -54,10 +54,7 @@ dependencies: open_file: ^3.0.1 mime_type: ^0.3.0 bot_toast: ^3.0.0 - flutter_matrix_html: - git: - url: https://github.com/Sorunome/flutter_matrix_html - ref: 530df434b50002e04cbad63f53d6f0f5d5adbab5 + flutter_matrix_html: ^0.1.4 moor: ^3.3.1 sqlite3: ^0.1.4 random_string: ^2.0.1