From 2bb75da017426c4285a6f217e07c333eea81b9af Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Thu, 16 Apr 2020 12:06:01 +0200 Subject: [PATCH] Add references support --- lib/helpers/virtual_directory_helper.dart | 52 +++++++++++++++++++++++ lib/ui/routes/home_route.dart | 9 ++-- lib/ui/screens/groups_list_screen.dart | 2 +- lib/ui/widgets/text_widget.dart | 26 ++++++++++-- lib/utils/input_utils.dart | 4 ++ lib/utils/navigation_utils.dart | 42 ++++++++++++++++++ 6 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 lib/helpers/virtual_directory_helper.dart diff --git a/lib/helpers/virtual_directory_helper.dart b/lib/helpers/virtual_directory_helper.dart new file mode 100644 index 0000000..1bcbe8d --- /dev/null +++ b/lib/helpers/virtual_directory_helper.dart @@ -0,0 +1,52 @@ +import 'package:comunic/models/api_request.dart'; +import 'package:flutter/material.dart'; + +/// Virtual directory helper +/// +/// @author Pierre Hubert + +enum VirtualDirectoryType { USER, GROUP, NONE } + +class VirtualDirectoryResult { + final VirtualDirectoryType type; + final int id; + + const VirtualDirectoryResult({ + @required this.type, + this.id, + }) : assert(type != null); +} + +class VirtualDirectoryHelper { + /// Find a virtual directory + Future find(String directory) async { + final response = await APIRequest( + uri: "virtualDirectory/find", + needLogin: true, + args: {"directory": directory}).exec(); + + switch (response.code) { + case 404: + return VirtualDirectoryResult(type: VirtualDirectoryType.NONE); + + case 200: + final id = response.getObject()["id"]; + final kind = response.getObject()["kind"]; + switch (kind) { + case "user": + return VirtualDirectoryResult( + type: VirtualDirectoryType.USER, id: id); + case "group": + return VirtualDirectoryResult( + type: VirtualDirectoryType.GROUP, id: id); + + default: + throw Exception("Unsupported virtual directory kind: $kind"); + } + break; + + default: + throw new Exception("Could not get virtual directory!"); + } + } +} diff --git a/lib/ui/routes/home_route.dart b/lib/ui/routes/home_route.dart index 6359a31..e8f124d 100644 --- a/lib/ui/routes/home_route.dart +++ b/lib/ui/routes/home_route.dart @@ -22,10 +22,6 @@ import 'login_route.dart'; class HomeRoute extends StatefulWidget { @override State createState() => _HomeRouteState(); - - /// Get current instance of Home controller - static HomeController of(BuildContext context) => - context.findAncestorStateOfType(); } class CurrPage { @@ -45,6 +41,11 @@ class CurrPage { /// Public interface of home controller abstract class HomeController extends State { + + /// Get current instance of Home controller + static HomeController of(BuildContext context) => + context.findAncestorStateOfType(); + /// Open a specific group page specified by its [groupID] void openGroup(int groupID); } diff --git a/lib/ui/screens/groups_list_screen.dart b/lib/ui/screens/groups_list_screen.dart index 3391017..d8be8a2 100644 --- a/lib/ui/screens/groups_list_screen.dart +++ b/lib/ui/screens/groups_list_screen.dart @@ -67,7 +67,7 @@ class _GroupsListScreenState extends SafeState { trailing: IconButton( icon: Icon(Icons.delete), onPressed: () => _deleteGroup(g)), - onTap: () => HomeRoute.of(context).openGroup(g.id), + onTap: () => HomeController.of(context).openGroup(g.id), )) .toList(), ), diff --git a/lib/ui/widgets/text_widget.dart b/lib/ui/widgets/text_widget.dart index 70f863f..43f474a 100644 --- a/lib/ui/widgets/text_widget.dart +++ b/lib/ui/widgets/text_widget.dart @@ -1,5 +1,6 @@ import 'package:comunic/utils/bbcode_parser.dart'; import 'package:comunic/utils/input_utils.dart'; +import 'package:comunic/utils/navigation_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_emoji/flutter_emoji.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -32,17 +33,17 @@ class TextWidget extends StatelessWidget { if (this.parseBBcode) return BBCodeParsedWidget( text: content, - parseCallback: (style, text) => _parseLinks(text, style), + parseCallback: (style, text) => _parseLinks(context, text, style), ); // Just parse link return RichText( - text: TextSpan(children: _parseLinks(content, style)), + text: TextSpan(children: _parseLinks(context, content, style)), ); } /// Sub parse function - List _parseLinks(String text, TextStyle style) { + List _parseLinks(BuildContext context, String text, TextStyle style) { var buff = StringBuffer(); final list = new List(); @@ -78,6 +79,25 @@ class TextWidget extends StatelessWidget { buff.write(" "); } + // Check if it is a user reference + else if(validateUserReference(word)) { + changeWordType(); + + list.add( + WidgetSpan( + child: InkWell( + child: Text( + word, + style: style.copyWith(color: Colors.blueAccent), + ), + onTap: () => openVirtualDirectory(context, word), + ), + ), + ); + + buff.write(" "); + } + // Simple word else { buff.write(word); diff --git a/lib/utils/input_utils.dart b/lib/utils/input_utils.dart index d085e3c..9ec1fab 100644 --- a/lib/utils/input_utils.dart +++ b/lib/utils/input_utils.dart @@ -27,3 +27,7 @@ bool validateUrl(String url) { return false; } } + +/// Validate user reference +bool validateUserReference(String ref) => + RegExp(r'@[a-zA-Z0-9]+').hasMatch(ref); diff --git a/lib/utils/navigation_utils.dart b/lib/utils/navigation_utils.dart index ff7f93a..a6b9d50 100644 --- a/lib/utils/navigation_utils.dart +++ b/lib/utils/navigation_utils.dart @@ -1,5 +1,9 @@ +import 'package:comunic/helpers/virtual_directory_helper.dart'; +import 'package:comunic/ui/routes/home_route.dart'; import 'package:comunic/ui/routes/single_post_route.dart'; import 'package:comunic/ui/routes/user_page_route.dart'; +import 'package:comunic/utils/intl_utils.dart'; +import 'package:comunic/utils/ui_utils.dart'; import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; @@ -26,3 +30,41 @@ void openPostFullScreen(int postID, BuildContext context) { Navigator.of(context) .push(MaterialPageRoute(builder: (c) => SinglePostRoute(postID: postID))); } + +/// Open a virtual directory +void openVirtualDirectory(BuildContext context, String directory) async { + if (directory.startsWith("@")) directory = directory.substring(1); + + try { + final result = await VirtualDirectoryHelper().find(directory); + + switch (result.type) { + case VirtualDirectoryType.USER: + openUserPage(context: context, userID: result.id); + break; + + case VirtualDirectoryType.GROUP: + HomeController.of(context).openGroup(result.id); + break; + + case VirtualDirectoryType.NONE: + await showDialog( + context: context, + builder: (c) => AlertDialog( + title: Text(tr("Error")), + content: Text(tr("Could not find related resource!")), + actions: [ + MaterialButton( + child: Text(tr("OK")), + onPressed: () => Navigator.of(c).pop(), + ) + ], + )); + break; + } + } catch (e, stack) { + print(e); + print(stack); + showSimpleSnack(context, tr("Could not search virtual directory!")); + } +}