feat(ui, core): minor fixes and improvements
Signed-off-by: xsahil03x <[email protected]>
This commit is contained in:
@@ -895,7 +895,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
_actionsShrunk = value.isNotEmpty && actionsLength > 1;
|
_actionsShrunk = value.isNotEmpty && actionsLength > 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
_checkContainsUrlDebounced.call([value, context]);
|
_checkContainsUrl(value, context);
|
||||||
_checkCommands(value, context);
|
_checkCommands(value, context);
|
||||||
_checkMentions(value, context);
|
_checkMentions(value, context);
|
||||||
_checkEmoji(value, context);
|
_checkEmoji(value, context);
|
||||||
@@ -920,52 +920,65 @@ class MessageInputState extends State<MessageInput>
|
|||||||
|
|
||||||
String? _lastSearchedContainsUrlText;
|
String? _lastSearchedContainsUrlText;
|
||||||
CancelableOperation? _enrichUrlOperation;
|
CancelableOperation? _enrichUrlOperation;
|
||||||
|
final _urlRegex = RegExp(
|
||||||
late final _checkContainsUrlDebounced = debounce(
|
r'(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+',
|
||||||
(String value, BuildContext context) async {
|
|
||||||
// Cancel the previous operation if it's still running
|
|
||||||
_enrichUrlOperation?.cancel();
|
|
||||||
|
|
||||||
// If the text is same as the last time, don't do anything
|
|
||||||
if (_lastSearchedContainsUrlText == value) return;
|
|
||||||
_lastSearchedContainsUrlText = value;
|
|
||||||
|
|
||||||
final matchedUrls =
|
|
||||||
RegExp(r'(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+')
|
|
||||||
.allMatches(value);
|
|
||||||
|
|
||||||
// Reset the og attachment if the text doesn't contain any url
|
|
||||||
if (matchedUrls.isEmpty) {
|
|
||||||
_effectiveController.clearOGAttachment();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final firstMatchedUrl = matchedUrls.first.group(0)!;
|
|
||||||
|
|
||||||
// If the parsed url matches the ogAttachment url, don't do anything
|
|
||||||
if (_effectiveController.ogAttachment?.titleLink == firstMatchedUrl) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final client = StreamChat.of(context).client;
|
|
||||||
|
|
||||||
_enrichUrlOperation = CancelableOperation.fromFuture(
|
|
||||||
client.enrichUrl(firstMatchedUrl),
|
|
||||||
).then(
|
|
||||||
(ogAttachment) {
|
|
||||||
final attachment = Attachment.fromOGAttachment(ogAttachment);
|
|
||||||
_effectiveController.setOGAttachment(attachment);
|
|
||||||
},
|
|
||||||
onError: (error, stackTrace) {
|
|
||||||
// Reset the ogAttachment if there was an error
|
|
||||||
_effectiveController.clearOGAttachment();
|
|
||||||
widget.onError?.call(error, stackTrace);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
const Duration(milliseconds: 650),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void _checkContainsUrl(String value, BuildContext context) async {
|
||||||
|
// Cancel the previous operation if it's still running
|
||||||
|
_enrichUrlOperation?.cancel();
|
||||||
|
|
||||||
|
// If the text is same as the last time, don't do anything
|
||||||
|
if (_lastSearchedContainsUrlText == value) return;
|
||||||
|
_lastSearchedContainsUrlText = value;
|
||||||
|
|
||||||
|
final matchedUrls = _urlRegex.allMatches(value);
|
||||||
|
|
||||||
|
// Reset the og attachment if the text doesn't contain any url
|
||||||
|
if (matchedUrls.isEmpty) {
|
||||||
|
_effectiveController.clearOGAttachment();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final firstMatchedUrl = matchedUrls.first.group(0)!;
|
||||||
|
|
||||||
|
// If the parsed url matches the ogAttachment url, don't do anything
|
||||||
|
if (_effectiveController.ogAttachment?.titleLink == firstMatchedUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final client = StreamChat.of(context).client;
|
||||||
|
|
||||||
|
_enrichUrlOperation = CancelableOperation.fromFuture(
|
||||||
|
_enrichUrl(firstMatchedUrl, client),
|
||||||
|
).then(
|
||||||
|
(ogAttachment) {
|
||||||
|
final attachment = Attachment.fromOGAttachment(ogAttachment);
|
||||||
|
_effectiveController.setOGAttachment(attachment);
|
||||||
|
},
|
||||||
|
onError: (error, stackTrace) {
|
||||||
|
// Reset the ogAttachment if there was an error
|
||||||
|
_effectiveController.clearOGAttachment();
|
||||||
|
widget.onError?.call(error, stackTrace);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final _ogAttachmentCache = <String, OGAttachmentResponse>{};
|
||||||
|
|
||||||
|
Future<OGAttachmentResponse> _enrichUrl(
|
||||||
|
String url,
|
||||||
|
StreamChatClient client,
|
||||||
|
) async {
|
||||||
|
var response = _ogAttachmentCache[url];
|
||||||
|
if (response == null) {
|
||||||
|
final client = StreamChat.of(context).client;
|
||||||
|
response = await client.enrichUrl(url);
|
||||||
|
_ogAttachmentCache[url] = response;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
void _checkEmoji(String value, BuildContext context) {
|
void _checkEmoji(String value, BuildContext context) {
|
||||||
if (value.isNotEmpty &&
|
if (value.isNotEmpty &&
|
||||||
_effectiveController.baseOffset > 0 &&
|
_effectiveController.baseOffset > 0 &&
|
||||||
@@ -1169,11 +1182,14 @@ class MessageInputState extends State<MessageInput>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAttachments() {
|
Widget _buildAttachments() {
|
||||||
if (_effectiveController.attachments.isEmpty) return const Offstage();
|
final nonOGAttachments = _effectiveController.attachments.where(
|
||||||
final fileAttachments = _effectiveController.attachments
|
(it) => it.titleLink == null,
|
||||||
|
);
|
||||||
|
if (nonOGAttachments.isEmpty) return const Offstage();
|
||||||
|
final fileAttachments = nonOGAttachments
|
||||||
.where((it) => it.type == 'file')
|
.where((it) => it.type == 'file')
|
||||||
.toList(growable: false);
|
.toList(growable: false);
|
||||||
final remainingAttachments = _effectiveController.attachments
|
final remainingAttachments = nonOGAttachments
|
||||||
.where((it) => it.type != 'file')
|
.where((it) => it.type != 'file')
|
||||||
.toList(growable: false);
|
.toList(growable: false);
|
||||||
return Column(
|
return Column(
|
||||||
|
|||||||
@@ -66,10 +66,7 @@ class MessageInputController extends ValueNotifier<Message> {
|
|||||||
void _textEditingSyncer() {
|
void _textEditingSyncer() {
|
||||||
final cleanText = value.command == null
|
final cleanText = value.command == null
|
||||||
? value.text
|
? value.text
|
||||||
: value.text?.replaceFirst(
|
: value.text?.replaceFirst('/${value.command} ', '');
|
||||||
'/${value.command} ',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cleanText != _textEditingController.text) {
|
if (cleanText != _textEditingController.text) {
|
||||||
final previousOffset = _textEditingController.value.selection.start;
|
final previousOffset = _textEditingController.value.selection.start;
|
||||||
@@ -207,7 +204,9 @@ class MessageInputController extends ValueNotifier<Message> {
|
|||||||
|
|
||||||
/// Removes the og attachment.
|
/// Removes the og attachment.
|
||||||
void clearOGAttachment() {
|
void clearOGAttachment() {
|
||||||
attachments = [...attachments]..remove(_ogAttachment);
|
if (_ogAttachment != null) {
|
||||||
|
removeAttachment(_ogAttachment!);
|
||||||
|
}
|
||||||
_ogAttachment = null;
|
_ogAttachment = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user