diff --git a/lib/expandable_text.dart b/lib/expandable_text.dart index 7757456..3b10bd4 100644 --- a/lib/expandable_text.dart +++ b/lib/expandable_text.dart @@ -41,6 +41,7 @@ class ExpandableText extends StatefulWidget { this.animationDuration, this.animationCurve, this.semanticsLabel, + this.mentionsWithSpace }) : assert(maxLines > 0), super(key: key); @@ -73,6 +74,7 @@ class ExpandableText extends StatefulWidget { final Duration? animationDuration; final Curve? animationCurve; final String? semanticsLabel; + final bool? mentionsWithSpace; @override ExpandableTextState createState() => ExpandableTextState(); @@ -248,7 +250,7 @@ class ExpandableTextState extends State _expanded ? _textSegments : parseText( - widget.text.substring(0, max(endOffset, 0))), + widget.text.substring(0, max(endOffset, 0)), widget.mentionsWithSpace ?? false), effectiveTextStyle!, recognizer), ) @@ -318,7 +320,7 @@ class ExpandableTextState extends State return; } - _textSegments = parseText(widget.text); + _textSegments = parseText(widget.text, widget.mentionsWithSpace ?? false); _textSegments.forEach((element) { if (element.isUrl && widget.onUrlTap != null) { @@ -377,4 +379,4 @@ class ExpandableTextState extends State return spans; } -} +} \ No newline at end of file diff --git a/lib/text_parser.dart b/lib/text_parser.dart index 9f0e6d8..1bbb21d 100644 --- a/lib/text_parser.dart +++ b/lib/text_parser.dart @@ -12,7 +12,7 @@ class TextSegment { [this.name, this.isHashtag = false, this.isMention = false, - this.isUrl = false]); + this.isUrl = false,]); @override bool operator ==(Object other) => @@ -38,7 +38,7 @@ class TextSegment { /// /// Mentions are all words that start with @, e.g. @mention. /// Hashtags are all words that start with #, e.g. #hashtag. -List parseText(String? text) { +List parseText(String? text, bool withSpace) { final segments = []; if (text == null || text.isEmpty) { @@ -46,12 +46,16 @@ List parseText(String? text) { } // parse urls and words starting with @ (mention) or # (hashtag) - RegExp exp = RegExp( + RegExp exp = withSpace ?RegExp( + r'(?(#|@)([\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]+)(?:\s[\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]+)|(?(?:(?:https?|ftp):\/\/)?[-a-z0-9@:%._\+~#=]{1,256}\.[a-z0-9]{1,6}(\/[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)?))', + unicode: true) + :RegExp( r'(?(#|@)([\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]+)|(?(?:(?:https?|ftp):\/\/)?[-a-z0-9@:%._\+~#=]{1,256}\.[a-z0-9]{1,6}(\/[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)?))', unicode: true); final matches = exp.allMatches(text); var start = 0; + String previousKeyword = ""; matches.forEach((match) { // text before the keyword if (match.start > start) { @@ -65,6 +69,7 @@ List parseText(String? text) { final url = match.namedGroup('url'); final keyword = match.namedGroup('keyword'); + previousKeyword = keyword ?? ""; if (url != null) { segments.add(TextSegment(url, url, false, false, true)); @@ -76,7 +81,8 @@ List parseText(String? text) { } final isHashtag = keyword.startsWith('#'); - final isMention = keyword.startsWith('@'); + final isMention = keyword.startsWith('@') || previousKeyword.startsWith('@'); + segments.add( TextSegment(keyword, keyword.substring(1), isHashtag, isMention));