Skip to content

Commit

Permalink
Merge pull request #27687 from ShogunFire/fixFrequentlyUsedEmojiSentM…
Browse files Browse the repository at this point in the history
…ultipleTimes

Only add the new emojis to the frequent emojis list by doing a difference between former and new emojis
  • Loading branch information
Joel Bettner authored Oct 10, 2023
2 parents f78f8aa + f9c43fc commit f878fbd
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 73 deletions.
14 changes: 2 additions & 12 deletions src/components/EmojiPicker/EmojiPickerMenu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ class EmojiPickerMenu extends Component {
return;
}
const emoji = lodashGet(item, ['types', this.props.preferredSkinTone], item.code);
this.addToFrequentAndSelectEmoji(emoji, item);
this.props.onEmojiSelected(emoji, item);
return;
}

Expand Down Expand Up @@ -258,16 +258,6 @@ class EmojiPickerMenu extends Component {
document.removeEventListener('mousemove', this.mouseMoveHandler);
}

/**
* @param {String} emoji
* @param {Object} emojiObject
*/
addToFrequentAndSelectEmoji(emoji, emojiObject) {
const frequentEmojiList = EmojiUtils.getFrequentlyUsedEmojis(emojiObject);
User.updateFrequentlyUsedEmojis(frequentEmojiList);
this.props.onEmojiSelected(emoji, emojiObject);
}

/**
* Focuses the search Input and has the text selected
*/
Expand Down Expand Up @@ -466,7 +456,7 @@ class EmojiPickerMenu extends Component {

return (
<EmojiPickerMenuItem
onPress={(emoji) => this.addToFrequentAndSelectEmoji(emoji, item)}
onPress={(emoji) => this.props.onEmojiSelected(emoji, item)}
onHoverIn={() => this.setState({highlightedIndex: index, isUsingKeyboardMovement: false})}
onHoverOut={() => {
if (this.state.arePointerEventsDisabled) {
Expand Down
12 changes: 1 addition & 11 deletions src/components/EmojiPicker/EmojiPickerMenu/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,6 @@ function EmojiPickerMenu({preferredLocale, onEmojiSelected, preferredSkinTone, t
setHeaderIndices(undefined);
}, 300);

/**
* @param {String} emoji
* @param {Object} emojiObject
*/
const addToFrequentAndSelectEmoji = (emoji, emojiObject) => {
const frequentEmojiList = EmojiUtils.getFrequentlyUsedEmojis(emojiObject);
User.updateFrequentlyUsedEmojis(frequentEmojiList);
onEmojiSelected(emoji, emojiObject);
};

/**
* @param {Number} skinTone
*/
Expand Down Expand Up @@ -152,7 +142,7 @@ function EmojiPickerMenu({preferredLocale, onEmojiSelected, preferredSkinTone, t

return (
<EmojiPickerMenuItem
onPress={singleExecution((emoji) => addToFrequentAndSelectEmoji(emoji, item))}
onPress={singleExecution((emoji) => onEmojiSelected(emoji, item))}
emoji={emojiCode}
/>
);
Expand Down
29 changes: 21 additions & 8 deletions src/libs/EmojiUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,24 +278,35 @@ function extractEmojis(text) {
}

const emojis = [];

// Text can contain similar emojis as well as their skin tone variants. Create a Set to remove duplicate emojis from the search.
const foundEmojiCodes = new Set();

for (let i = 0; i < parsedEmojis.length; i++) {
const character = parsedEmojis[i];
const emoji = Emojis.emojiCodeTableWithSkinTones[character];

// Add the parsed emoji to the final emojis if not already present.
if (emoji && !foundEmojiCodes.has(emoji.code)) {
foundEmojiCodes.add(emoji.code);
if (emoji) {
emojis.push(emoji);
}
}

return emojis;
}

/**
* Take the current emojis and the former emojis and return the emojis that were added, if we add an already existing emoji, we also return it
* @param {Object[]} currentEmojis The array of current emojis
* @param {Object[]} formerEmojis The array of former emojis
* @returns {Object[]} The array of added emojis
*/
function getAddedEmojis(currentEmojis, formerEmojis) {
const newEmojis = [...currentEmojis];
// We are removing the emojis from the newEmojis array if they were already present before.
formerEmojis.forEach((formerEmoji) => {
const indexOfAlreadyPresentEmoji = _.findIndex(newEmojis, (newEmoji) => newEmoji.code === formerEmoji.code);
if (indexOfAlreadyPresentEmoji >= 0) {
newEmojis.splice(indexOfAlreadyPresentEmoji, 1);
}
});
return newEmojis;
}

/**
* Replace any emoji name in a text with the emoji icon.
* If we're on mobile, we also add a space after the emoji granted there's no text after it.
Expand Down Expand Up @@ -484,4 +495,6 @@ export {
getPreferredEmojiCode,
getUniqueEmojiCodes,
replaceAndExtractEmojis,
extractEmojis,
getAddedEmojis,
};
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,14 @@ function ComposerWithSuggestions({
const {preferredLocale} = useLocalize();
const isFocused = useIsFocused();
const navigation = useNavigation();

const [value, setValue] = useState(() => getDraftComment(reportID) || '');
const emojisPresentBefore = useRef([]);
const [value, setValue] = useState(() => {
const draft = getDraftComment(reportID) || '';
if (draft) {
emojisPresentBefore.current = EmojiUtils.extractEmojis(draft);
}
return draft;
});
const commentRef = useRef(value);

const {isSmallScreenWidth} = useWindowDimensions();
Expand Down Expand Up @@ -154,14 +160,6 @@ function ComposerWithSuggestions({
debouncedLowerIsScrollLikelyLayoutTriggered();
}, [debouncedLowerIsScrollLikelyLayoutTriggered]);

const onInsertedEmoji = useCallback(
(emojiObject) => {
insertedEmojisRef.current = [...insertedEmojisRef.current, emojiObject];
debouncedUpdateFrequentlyUsedEmojis(emojiObject);
},
[debouncedUpdateFrequentlyUsedEmojis],
);

/**
* Set the TextInput Ref
*
Expand Down Expand Up @@ -206,10 +204,13 @@ function ComposerWithSuggestions({
const {text: newComment, emojis} = EmojiUtils.replaceAndExtractEmojis(commentValue, preferredSkinTone, preferredLocale);

if (!_.isEmpty(emojis)) {
insertedEmojisRef.current = [...insertedEmojisRef.current, ...emojis];
debouncedUpdateFrequentlyUsedEmojis();
const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current);
if (!_.isEmpty(newEmojis)) {
insertedEmojisRef.current = [...insertedEmojisRef.current, ...newEmojis];
debouncedUpdateFrequentlyUsedEmojis();
}
}

emojisPresentBefore.current = emojis;
setIsCommentEmpty(!!newComment.match(/^(\s)*$/));
setValue(newComment);
if (commentValue !== newComment) {
Expand Down Expand Up @@ -550,7 +551,6 @@ function ComposerWithSuggestions({
isComposerFullSize={isComposerFullSize}
updateComment={updateComment}
composerHeight={composerHeight}
onInsertedEmoji={onInsertedEmoji}
measureParentContainer={measureParentContainer}
// Input
value={value}
Expand Down
8 changes: 1 addition & 7 deletions src/pages/home/report/ReportActionCompose/SuggestionEmoji.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ const propTypes = {
/** Function to clear the input */
resetKeyboardInput: PropTypes.func.isRequired,

/** Callback when a emoji was inserted */
onInsertedEmoji: PropTypes.func.isRequired,

...SuggestionProps.baseProps,
};

Expand All @@ -61,7 +58,6 @@ function SuggestionEmoji({
isAutoSuggestionPickerLarge,
forwardedRef,
resetKeyboardInput,
onInsertedEmoji,
measureParentContainer,
}) {
const [suggestionValues, setSuggestionValues] = useState(defaultSuggestionsValues);
Expand Down Expand Up @@ -102,10 +98,8 @@ function SuggestionEmoji({
end: suggestionValues.colonIndex + emojiCode.length + CONST.SPACE_LENGTH,
});
setSuggestionValues((prevState) => ({...prevState, suggestedEmojis: []}));

onInsertedEmoji(emojiObject);
},
[onInsertedEmoji, preferredSkinTone, resetKeyboardInput, selection.end, setSelection, suggestionValues.colonIndex, suggestionValues.suggestedEmojis, updateComment, value],
[preferredSkinTone, resetKeyboardInput, selection.end, setSelection, suggestionValues.colonIndex, suggestionValues.suggestedEmojis, updateComment, value],
);

/**
Expand Down
18 changes: 1 addition & 17 deletions src/pages/home/report/ReportActionCompose/Suggestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ const propTypes = {
/** A ref to this component */
forwardedRef: PropTypes.shape({current: PropTypes.shape({})}),

/** Callback when a emoji was inserted */
onInsertedEmoji: PropTypes.func.isRequired,

/** Function to clear the input */
resetKeyboardInput: PropTypes.func.isRequired,

Expand All @@ -28,19 +25,7 @@ const defaultProps = {
*
* @returns {React.Component}
*/
function Suggestions({
isComposerFullSize,
value,
setValue,
selection,
setSelection,
updateComment,
composerHeight,
forwardedRef,
onInsertedEmoji,
resetKeyboardInput,
measureParentContainer,
}) {
function Suggestions({isComposerFullSize, value, setValue, selection, setSelection, updateComment, composerHeight, forwardedRef, resetKeyboardInput, measureParentContainer}) {
const suggestionEmojiRef = useRef(null);
const suggestionMentionRef = useRef(null);

Expand Down Expand Up @@ -114,7 +99,6 @@ function Suggestions({
ref={suggestionEmojiRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...baseProps}
onInsertedEmoji={onInsertedEmoji}
resetKeyboardInput={resetKeyboardInput}
/>
<SuggestionMention
Expand Down
18 changes: 14 additions & 4 deletions src/pages/home/report/ReportActionItemMessageEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,14 @@ function ReportActionItemMessageEdit(props) {
const length = getInitialDraft().length;
return {start: length, end: length};
};

const [draft, setDraft] = useState(() => getInitialDraft());
const emojisPresentBefore = useRef([]);
const [draft, setDraft] = useState(() => {
const initialDraft = getInitialDraft();
if (initialDraft) {
emojisPresentBefore.current = EmojiUtils.extractEmojis(initialDraft);
}
return initialDraft;
});
const [selection, setSelection] = useState(getInitialSelection());
const [isFocused, setIsFocused] = useState(false);
const [hasExceededMaxCommentLength, setHasExceededMaxCommentLength] = useState(false);
Expand Down Expand Up @@ -200,9 +206,13 @@ function ReportActionItemMessageEdit(props) {
const {text: newDraft, emojis} = EmojiUtils.replaceAndExtractEmojis(newDraftInput, props.preferredSkinTone, preferredLocale);

if (!_.isEmpty(emojis)) {
insertedEmojis.current = [...insertedEmojis.current, ...emojis];
debouncedUpdateFrequentlyUsedEmojis();
const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current);
if (!_.isEmpty(newEmojis)) {
insertedEmojis.current = [...insertedEmojis.current, ...newEmojis];
debouncedUpdateFrequentlyUsedEmojis();
}
}
emojisPresentBefore.current = emojis;
setDraft((prevDraft) => {
if (newDraftInput !== newDraft) {
const remainder = ComposerUtils.getCommonSuffixLength(prevDraft, newDraft);
Expand Down

0 comments on commit f878fbd

Please sign in to comment.