Closed mohammedbabelly closed 2 years ago
You can create your own custom Linkifier
and use the linkifiers
property on the Linkify
widget.
class HashtagLinkifier extends Linkifier { ... }
class HashtagElement extends LinkableElement { ... }
Linkify(
linkifiers: const [
...defaultLinkifiers,
HashtagLinkifier(),
],
...
),
@VictorUvarov I hope this is not too much, but can you give me snippets on how you dot it? need to support hashtags, email and urls for my text description, Thank you very much!
HashtagLinkifier and HashtagElement. Just update the regex to also support @.
import 'package:linkify/linkify.dart';
final _atUsernameRegex = RegExp(
r'(.*?)(#\w+)',
caseSensitive: false,
dotAll: true,
);
class HashtagLinkifier extends Linkifier {
const HashtagLinkifier();
@override
List<LinkifyElement> parse(elements, options) {
final list = <LinkifyElement>[];
for (var element in elements) {
if (element is TextElement) {
var match = _atUsernameRegex.firstMatch(element.text);
if (match == null) {
list.add(element);
} else {
// create the preceding TextElement
if (match.group(1)?.isNotEmpty ?? false) {
list.add(TextElement(match.group(1)!));
}
// create the AtElement
if (match.group(2)?.isNotEmpty ?? false) {
var withHash = match.group(2)!;
var element = HashtagElement(withHash);
list.add(element);
}
// create the following TextElement
final textWithoutMatch =
element.text.replaceFirst(match.group(0)!, '');
if (textWithoutMatch.isNotEmpty) {
list.addAll(parse([TextElement(textWithoutMatch)], options));
}
}
} else {
list.add(element);
}
}
return list;
}
}
class HashtagElement extends LinkableElement {
HashtagElement(String tag) : super(tag, tag);
@override
String toString() {
return "HashtagElement: '$url' ($text)";
}
@override
bool operator ==(other) => equals(other);
@override
bool equals(other) =>
identical(this, other) ||
other is HashtagElement &&
runtimeType == other.runtimeType &&
text == other.text &&
url == other.url;
@override
int get hashCode => text.hashCode ^ url.hashCode;
}
Tests
group('HashtagLinkifier', () {
test('Parses only hashtag', () {
expectListEqual(
linkify('#trending', linkifiers: [const HashtagLinkifier()]),
[HashtagElement('#trending')],
);
});
test('Parses hashtags with text', () {
expectListEqual(
linkify(
'Lorem ipsum dolor sit amet #tag #stuff',
linkifiers: [const HashtagLinkifier()],
),
[
TextElement('Lorem ipsum dolor sit amet '),
HashtagElement('#tag'),
TextElement(' '),
HashtagElement('#stuff'),
],
);
expectListEqual(
linkify(
'Lorem ipsum dolor sit amet #tag #stuff some more text',
linkifiers: [const HashtagLinkifier()],
),
[
TextElement('Lorem ipsum dolor sit amet '),
HashtagElement('#tag'),
TextElement(' '),
HashtagElement('#stuff'),
TextElement(' some more text'),
],
);
});
});
HashtagLinkifier and HashtagElement. Just update the regex to also support @.
import 'package:linkify/linkify.dart'; final _atUsernameRegex = RegExp( r'(.*?)(#\w+)', caseSensitive: false, dotAll: true, ); class HashtagLinkifier extends Linkifier { const HashtagLinkifier(); @override List<LinkifyElement> parse(elements, options) { final list = <LinkifyElement>[]; for (var element in elements) { if (element is TextElement) { var match = _atUsernameRegex.firstMatch(element.text); if (match == null) { list.add(element); } else { // create the preceding TextElement if (match.group(1)?.isNotEmpty ?? false) { list.add(TextElement(match.group(1)!)); } // create the AtElement if (match.group(2)?.isNotEmpty ?? false) { var withHash = match.group(2)!; var element = HashtagElement(withHash); list.add(element); } // create the following TextElement final textWithoutMatch = element.text.replaceFirst(match.group(0)!, ''); if (textWithoutMatch.isNotEmpty) { list.addAll(parse([TextElement(textWithoutMatch)], options)); } } } else { list.add(element); } } return list; } } class HashtagElement extends LinkableElement { HashtagElement(String tag) : super(tag, tag); @override String toString() { return "HashtagElement: '$url' ($text)"; } @override bool operator ==(other) => equals(other); @override bool equals(other) => identical(this, other) || other is HashtagElement && runtimeType == other.runtimeType && text == other.text && url == other.url; @override int get hashCode => text.hashCode ^ url.hashCode; }
Tests
group('HashtagLinkifier', () { test('Parses only hashtag', () { expectListEqual( linkify('#trending', linkifiers: [const HashtagLinkifier()]), [HashtagElement('#trending')], ); }); test('Parses hashtags with text', () { expectListEqual( linkify( 'Lorem ipsum dolor sit amet #tag #stuff', linkifiers: [const HashtagLinkifier()], ), [ TextElement('Lorem ipsum dolor sit amet '), HashtagElement('#tag'), TextElement(' '), HashtagElement('#stuff'), ], ); expectListEqual( linkify( 'Lorem ipsum dolor sit amet #tag #stuff some more text', linkifiers: [const HashtagLinkifier()], ), [ TextElement('Lorem ipsum dolor sit amet '), HashtagElement('#tag'), TextElement(' '), HashtagElement('#stuff'), TextElement(' some more text'), ], ); }); });
Thank You @VictorUvarov I appreciate your fast response!
HashtagLinkifier and HashtagElement. Just update the regex to also support @.
import 'package:linkify/linkify.dart'; final _atUsernameRegex = RegExp( r'(.*?)(#\w+)', caseSensitive: false, dotAll: true, ); class HashtagLinkifier extends Linkifier { const HashtagLinkifier(); @override List<LinkifyElement> parse(elements, options) { final list = <LinkifyElement>[]; for (var element in elements) { if (element is TextElement) { var match = _atUsernameRegex.firstMatch(element.text); if (match == null) { list.add(element); } else { // create the preceding TextElement if (match.group(1)?.isNotEmpty ?? false) { list.add(TextElement(match.group(1)!)); } // create the AtElement if (match.group(2)?.isNotEmpty ?? false) { var withHash = match.group(2)!; var element = HashtagElement(withHash); list.add(element); } // create the following TextElement final textWithoutMatch = element.text.replaceFirst(match.group(0)!, ''); if (textWithoutMatch.isNotEmpty) { list.addAll(parse([TextElement(textWithoutMatch)], options)); } } } else { list.add(element); } } return list; } } class HashtagElement extends LinkableElement { HashtagElement(String tag) : super(tag, tag); @override String toString() { return "HashtagElement: '$url' ($text)"; } @override bool operator ==(other) => equals(other); @override bool equals(other) => identical(this, other) || other is HashtagElement && runtimeType == other.runtimeType && text == other.text && url == other.url; @override int get hashCode => text.hashCode ^ url.hashCode; }
Tests
group('HashtagLinkifier', () { test('Parses only hashtag', () { expectListEqual( linkify('#trending', linkifiers: [const HashtagLinkifier()]), [HashtagElement('#trending')], ); }); test('Parses hashtags with text', () { expectListEqual( linkify( 'Lorem ipsum dolor sit amet #tag #stuff', linkifiers: [const HashtagLinkifier()], ), [ TextElement('Lorem ipsum dolor sit amet '), HashtagElement('#tag'), TextElement(' '), HashtagElement('#stuff'), ], ); expectListEqual( linkify( 'Lorem ipsum dolor sit amet #tag #stuff some more text', linkifiers: [const HashtagLinkifier()], ), [ TextElement('Lorem ipsum dolor sit amet '), HashtagElement('#tag'), TextElement(' '), HashtagElement('#stuff'), TextElement(' some more text'), ], ); }); });
Could you help me on RegExp for supporting Thai language? Thank you.
Update
I have change regexp to this
RegExp(r'(.*?)(#[\u0E00-\u0E7F\a-zA-Za-zA-Z]+)',caseSensitive: false, dotAll: true, );
It works fine. Thank you.
Could you please add the hashtag support, so it colors the hashtag like emails or allows us to use widgets in the text property so we use other packages like Hatagable