onChange method
onChange is a function which is used to perform some action when the text is changed
Implementation
@override
void onChange(
TextEditingController textEditingController, String previousText) {
// Get cursor current position
var cursorPosition = textEditingController.selection.base.offset;
// if text is empty then we will clear the listItems and hide the panel
if (textEditingController.text.isEmpty) {
if (listItems.isNotEmpty) {
resetMentionsTracker();
mentionedUsersMap.clear();
mentionCount.clear();
lastCursorPos = cursorPosition;
CometChatUIEvents.hidePanel(
composerId, CustomUIPosition.composerPreview);
}
return;
}
//first we check if the current text has any part matching the regex pattern
//the following logic is for when copy paste is involved
if (mentionedUsersMap.isNotEmpty &&
textEditingController.text.length > previousText.length + 1) {
int extraCharactersLength =
textEditingController.text.length - previousText.length;
if (listItems.isNotEmpty) {
resetMentionsTracker();
CometChatUIEvents.hidePanel(
composerId, CustomUIPosition.composerPreview);
}
int extraCharactersStartIndex = cursorPosition - extraCharactersLength;
String newText = textEditingController.text
.substring(cursorPosition - extraCharactersLength, cursorPosition);
if (extraCharactersStartIndex > -1 && newText.isNotEmpty) {
String prev = previousText.substring(0, extraCharactersStartIndex);
Map<String, List<User?>> mentionedUsersMapCopy = mentionedUsersMap;
mentionedUsersMap.forEach(
(key, value) {
RegExp currentPattern = RegExp(key);
if (currentPattern.hasMatch(newText)) {
//@john @harry @john
final oldMatchesCount = currentPattern.allMatches(prev).length;
//@john @john @harry @john
final newMatchesCount = currentPattern.allMatches(newText).length;
mentionedUsersMapCopy[key]?.insertAll(
oldMatchesCount,
List<User?>.generate(newMatchesCount, (int index) => null,
growable: false));
}
},
);
mentionedUsersMap = mentionedUsersMapCopy;
}
lastCursorPos = cursorPosition;
return;
}
//check if new text has same length as previous text
if (previousText != textEditingController.text &&
previousText.length > textEditingController.text.length) {
//first check if the mentionTracker is not empty
if (mentionTracker.isNotEmpty) {
if (searchOnActiveMention && cursorPosition == lastCursorPos - 1) {
//check if the user has triggered search by going back to the end of a mention
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
} else if (cursorPosition == mentionStartIndex) {
// if cursor position is at the start of the mentionTracker
// it means the @ the tracking character is removed by the user
resetMentionsTracker();
CometChatUIEvents.hidePanel(
composerId, CustomUIPosition.composerPreview);
} else {
//if the cursor position is between the start and end of the mentionTracker
//it means the user is deleting the mentionTracker
if (cursorPosition > mentionStartIndex &&
cursorPosition <= mentionEndIndex) {
mentionTracker =
mentionTracker.substring(0, cursorPosition - mentionStartIndex);
mentionEndIndex = cursorPosition - 1;
if (mentionTracker.isEmpty && onSearch != null) {
onSearch!(null);
}
} else if (cursorPosition < mentionStartIndex) {
//if the cursor position is before the start of the mentionTracker
//it means the user is deleting the mentionTracker
mentionStartIndex = mentionStartIndex -
(previousText.length - textEditingController.text.length);
mentionEndIndex = mentionEndIndex -
(previousText.length - textEditingController.text.length);
}
}
} else {
if (previousText[cursorPosition] == trackingCharacter) {
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
} else {
int lastIndexOfTrackingChar = textEditingController.text
.substring(0, cursorPosition)
.lastIndexOf(trackingCharacter!);
if (lastIndexOfTrackingChar != -1 &&
(lastIndexOfTrackingChar == 0 ||
lastIndexOfTrackingChar > 1 &&
textEditingController.text[lastIndexOfTrackingChar - 1] ==
" ")) {
String tempTracker = textEditingController.text
.substring(lastIndexOfTrackingChar, cursorPosition);
if ((!tempTracker.contains("\n") &&
!tempTracker.contains(" ")) &&
mentionedUsersMap.containsKey(tempTracker.trim())) {
if (mentionedUsersMap.containsKey(tempTracker)) {
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
}
} else if (cursorPosition < lastCursorPos - 1 ||
cursorPosition > lastCursorPos) {
//if there has been a jump in the cursor position
//we reset the mentionTracker
// we first hide the panel
CometChatUIEvents.hidePanel(
composerId, CustomUIPosition.composerPreview);
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
} else if (!tempTracker.contains("\n") &&
!tempTracker.contains(" ")) {
mentionTracker = tempTracker;
mentionStartIndex = lastIndexOfTrackingChar;
mentionEndIndex = cursorPosition - 1;
}
}
}
}
} else {
String previousCharacter = cursorPosition == 0
? ""
: textEditingController.text[cursorPosition - 1];
bool isSpace = (cursorPosition == 1
// &&( textEditingController.text.length<2 || ( textEditingController.text[1]==" " ))
) ||
(textEditingController.text.length > 1 &&
cursorPosition > 1 &&
(textEditingController.text[cursorPosition - 2] == " " ||
textEditingController.text[cursorPosition - 2] == "\n"));
if (previousCharacter == trackingCharacter && isSpace) {
mentionTracker = trackingCharacter!;
mentionStartIndex = cursorPosition - 1;
checkIfTrackerPlacedCausesDuplication(
cursorPosition - 1, textEditingController);
} else if (previousCharacter == trackingCharacter &&
!isSpace &&
!searchOnActiveMention) {
int lastIndexOfTrackingChar = textEditingController.text
.substring(0, cursorPosition)
.lastIndexOf(trackingCharacter!);
if (lastIndexOfTrackingChar != -1 &&
(lastIndexOfTrackingChar == 0 ||
lastIndexOfTrackingChar > 1 &&
textEditingController.text[lastIndexOfTrackingChar - 1] ==
" ")) {
String tempTracker = textEditingController.text
.substring(lastIndexOfTrackingChar, cursorPosition);
if ((!tempTracker.contains("\n") && !tempTracker.contains(" ")) &&
mentionedUsersMap.containsKey(tempTracker.trim())) {
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
}
}
} else if (searchOnActiveMention && cursorPosition == lastCursorPos + 1) {
searchOnActiveMention = false;
resetMentionsTracker();
} else if (mentionTracker.isNotEmpty) {
mentionTracker += previousCharacter;
mentionEndIndex = cursorPosition - 1;
//if the current text length is greater than the previous text length
if (cursorPosition <= mentionStartIndex) {
//if the cursor position is before the start of the mentionTracker
//it means the user is adding text before the mentionTracker
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
} else if (mentionStartIndex <= cursorPosition &&
mentionEndIndex >= cursorPosition) {
//if the cursor position is between the start and end of the mentionTracker
//it means the user is adding text between the mentionTracker
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
mentionEndIndex = mentionEndIndex +
(textEditingController.text.length - previousText.length);
mentionTracker = textEditingController.text
.substring(mentionStartIndex, mentionEndIndex + 1);
}
} else {
int lastIndexOfTrackingChar = textEditingController.text
.substring(0, cursorPosition)
.lastIndexOf(trackingCharacter!);
if (lastIndexOfTrackingChar != -1 &&
(lastIndexOfTrackingChar == 0 ||
lastIndexOfTrackingChar > 1 &&
textEditingController.text[lastIndexOfTrackingChar - 1] ==
" ")) {
String tempTracker = textEditingController.text
.substring(lastIndexOfTrackingChar, cursorPosition);
// if(tempTracker){}else
if ((!tempTracker.contains("\n") && !tempTracker.contains(" "))
// && (!mentionedUsersMap.containsKey(tempTracker.trim()) && textEditingController.text.length>1 && textEditingController.text[cursorPosition-2]!=" ")
&&
mentionedUsersMap.containsKey(tempTracker.trim())) {
if (mentionedUsersMap.containsKey(tempTracker)) {
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
}
} else if (cursorPosition < lastCursorPos ||
cursorPosition > lastCursorPos + 1) {
//if there has been a jump in the cursor position
//we reset the mentionTracker
// we first hide the panel
CometChatUIEvents.hidePanel(
composerId, CustomUIPosition.composerPreview);
cursorInMentionTracker(
cursorPosition, textEditingController, previousText);
} else if (!tempTracker.contains("\n") &&
!tempTracker.contains(" ")) {
mentionTracker = tempTracker;
mentionStartIndex = lastIndexOfTrackingChar;
mentionEndIndex = cursorPosition - 1;
}
}
}
}
/// if the mention tracker has four consecutive spaces then we will stop tracking the mention
if ((mentionTracker.length > 1 &&
mentionTracker[mentionTracker.length - 1] == "\n") ||
mentionTracker.length > 4 &&
mentionTracker
.substring(mentionTracker.length - 4)
.trim()
.isEmpty) {
String mention = mentionTracker;
if (mentionedUsersMap.containsKey(mention)) {
int matchesFound = textEditingController.text
.substring(0, cursorPosition - mentionTracker.length)
.allMatches(mention)
.length;
mentionedUsersMap[mention]!.insert(matchesFound, null);
} else {
mentionedUsersMap[mention] = [null];
}
mentionTracker = "";
mentionStartIndex = 0;
mentionEndIndex = 0;
if (onSearch != null) {
onSearch!(null);
}
CometChatUIEvents.hidePanel(composerId, CustomUIPosition.composerPreview);
} else if (mentionTracker.isNotEmpty) {
//if 10 users have been mentioned then we will show a message to the user
//that the maximum limit of mentions has been reached
if (mentionCount.length == 10) {
CometChatUIEvents.showPanel(
composerId,
CustomUIPosition.composerPreview,
(context) => Container(
height: 40,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(
AssetConstants.info,
package: UIConstants.packageName,
color: _theme.palette.getAccent(),
height: 16.18,
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
cc.Translations.of(context).mentionsMaxLimitHit),
),
],
),
));
} else {
String searchKeyword = mentionTracker.substring(1);
if ((mentionedUsersMap.containsKey(mentionTracker) &&
!searchOnActiveMention) ||
(interceptedMention != null &&
(cursorPosition < textEditingController.text.length &&
mentionTracker.length < interceptedMention!.length) &&
((cursorPosition +
interceptedMention!.length -
mentionTracker.length <
textEditingController.text.length) &&
mentionTracker +
textEditingController.text.substring(
cursorPosition,
cursorPosition +
interceptedMention!.length -
mentionTracker.length) ==
interceptedMention))) {
String key = interceptedMention ?? mentionTracker;
int leftSideMatches = RegExp(key)
.allMatches(textEditingController.text
.substring(0, cursorPosition - mentionTracker.length))
.length;
mentionedUsersMap[key]!.insert(leftSideMatches, null);
}
if (listItems.isEmpty) {
CometChatUIEvents.showPanel(
composerId,
CustomUIPosition.composerPreview,
(context) => getLoadingIndicator(context, cometChatTheme));
}
if (onSearch != null) {
onSearch!(mentionTracker);
}
initializeFetchRequest(searchKeyword, textEditingController);
}
}
lastCursorPos = cursorPosition;
}