Add useFrequentlyUsedEmojis hook, remove legacy code

This commit is contained in:
Alex Gleason 2024-11-18 11:31:44 -06:00
parent 8ad449cb13
commit f342afde5c
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
4 changed files with 29 additions and 25 deletions

View File

@ -8,12 +8,12 @@ import { closeModal, openModal } from 'soapbox/actions/modals.ts';
import EmojiComponent from 'soapbox/components/ui/emoji.tsx';
import HStack from 'soapbox/components/ui/hstack.tsx';
import IconButton from 'soapbox/components/ui/icon-button.tsx';
import EmojiPickerDropdown, { getFrequentlyUsedEmojis } from 'soapbox/features/emoji/components/emoji-picker-dropdown.tsx';
import EmojiPickerDropdown from 'soapbox/features/emoji/components/emoji-picker-dropdown.tsx';
import emojiData from 'soapbox/features/emoji/data.ts';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { useClickOutside } from 'soapbox/hooks/useClickOutside.ts';
import { useFeatures } from 'soapbox/hooks/useFeatures.ts';
import { useFrequentlyUsedEmojis } from 'soapbox/hooks/useFrequentlyUsedEmojis.ts';
import { useSoapboxConfig } from 'soapbox/hooks/useSoapboxConfig.ts';
import { userTouching } from 'soapbox/is-mobile.ts';
@ -74,7 +74,7 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
}): JSX.Element => {
const { allowedEmoji } = useSoapboxConfig();
const { customEmojiReacts } = useFeatures();
const shortcodes = useAppSelector((state) => getFrequentlyUsedEmojis(state));
const frequentlyUsedEmojis = useFrequentlyUsedEmojis();
const dispatch = useAppDispatch();
const [expanded, setExpanded] = useState(false);
@ -138,7 +138,8 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
onClose?.();
});
const recentEmojis = shortcodes.reduce<string[]>((results, shortcode) => {
/** Frequently used emojis converted from shortcodes to native. */
const frequentNative = frequentlyUsedEmojis.reduce<string[]>((results, shortcode) => {
const emoji = emojiData.emojis[shortcode]?.skins[0]?.native;
if (emoji) {
results.push(emoji);
@ -146,7 +147,8 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
return results;
}, []);
const emojis = new Set([...recentEmojis, ...allowedEmoji]);
/** Set of native emojis to display in the selector. */
const emojis = new Set([...frequentNative, ...allowedEmoji]);
return (
<div

View File

@ -1,7 +1,5 @@
import { Map as ImmutableMap } from 'immutable';
import { useEffect, useState, useLayoutEffect, Suspense } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { createSelector } from 'reselect';
import { chooseEmoji } from 'soapbox/actions/emojis.ts';
import { changeSetting } from 'soapbox/actions/settings.ts';
@ -9,9 +7,8 @@ import { useCustomEmojis } from 'soapbox/api/hooks/useCustomEmojis.ts';
import { buildCustomEmojis } from 'soapbox/features/emoji/index.ts';
import { EmojiPicker } from 'soapbox/features/ui/util/async-components.ts';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { useFrequentlyUsedEmojis } from 'soapbox/hooks/useFrequentlyUsedEmojis.ts';
import { useTheme } from 'soapbox/hooks/useTheme.ts';
import { RootState } from 'soapbox/store.ts';
import type { Emoji, CustomEmoji, NativeEmoji } from 'soapbox/features/emoji/index.ts';
import type { CustomEmoji as MastodonCustomEmoji } from 'soapbox/schemas/custom-emoji.ts';
@ -52,20 +49,6 @@ export interface IEmojiPickerDropdown {
update?: (() => any) | null;
}
const perLine = 8;
const lines = 2;
export const getFrequentlyUsedEmojis = createSelector([
(state: RootState) => state.settings.get('frequentlyUsedEmojis', ImmutableMap()),
], (emojiCounters: ImmutableMap<string, number>) => {
return emojiCounters
.keySeq()
.sort((a, b) => emojiCounters.get(a)! - emojiCounters.get(b)!)
.reverse()
.slice(0, perLine * lines)
.toArray();
});
/** Filter custom emojis to only ones visible in the picker, and sort them alphabetically. */
function filterCustomEmojis(customEmojis: MastodonCustomEmoji[]) {
return customEmojis.filter(e => e.visible_in_picker).sort((a, b) => {
@ -115,7 +98,7 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
const theme = useTheme();
const { customEmojis } = useCustomEmojis();
const frequentlyUsedEmojis = useAppSelector((state) => getFrequentlyUsedEmojis(state));
const frequentlyUsedEmojis = useFrequentlyUsedEmojis();
const handlePick = (emoji: any) => {
setVisible?.(false);
@ -206,7 +189,7 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
custom={withCustom ? [{ emojis: buildCustomEmojis(filterCustomEmojis(customEmojis)) }] : undefined}
title={title}
onEmojiSelect={handlePick}
recent={frequentlyUsedEmojis}
recent={frequentlyUsedEmojis.slice(0, 16)}
perLine={8}
skin={handleSkinTone}
emojiSize={22}

View File

@ -0,0 +1,15 @@
import { useMemo } from 'react';
import { useSettings } from 'soapbox/hooks/useSettings.ts';
/** Return a sorted list of most used emoji **shortcodes** from settings. */
export function useFrequentlyUsedEmojis(): string[] {
const { frequentlyUsedEmojis } = useSettings();
return useMemo(() => {
return Object.entries(frequentlyUsedEmojis)
.sort((a, b) => b[1] - a[1])
.map(([emoji]) => emoji);
}, [frequentlyUsedEmojis]);
}

View File

@ -75,6 +75,10 @@ const settingsSchema = z.object({
}),
/** Settings notifications that have been dismissed. See `useSettingsNotifications` hook. */
dismissedSettingsNotifications: z.array(z.string()).catch([]),
frequentlyUsedEmojis: z.record(
z.string(),
z.number().int().nonnegative(),
).catch({}),
});
type Settings = z.infer<typeof settingsSchema>;