mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Emoji working for compose
This commit is contained in:
		| @@ -7,7 +7,7 @@ import { getInstanceFrequentEmojis } from '@utils/slices/instancesSlice' | |||||||
| import { chunk, forEach, groupBy, sortBy } from 'lodash' | import { chunk, forEach, groupBy, sortBy } from 'lodash' | ||||||
| import React, { PropsWithChildren, RefObject, useEffect, useReducer, useState } from 'react' | import React, { PropsWithChildren, RefObject, useEffect, useReducer, useState } from 'react' | ||||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||||
| import { Keyboard, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native' | import { Keyboard, KeyboardAvoidingView, TextInput, View } from 'react-native' | ||||||
| import FastImage from 'react-native-fast-image' | import FastImage from 'react-native-fast-image' | ||||||
| import { Edge, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' | import { Edge, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' | ||||||
| import { useSelector } from 'react-redux' | import { useSelector } from 'react-redux' | ||||||
| @@ -74,14 +74,14 @@ const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({ | |||||||
|     if (data && data.length) { |     if (data && data.length) { | ||||||
|       let sortedEmojis: EmojisState['emojis'] = [] |       let sortedEmojis: EmojisState['emojis'] = [] | ||||||
|       forEach(groupBy(sortBy(data, ['category', 'shortcode']), 'category'), (value, key) => |       forEach(groupBy(sortBy(data, ['category', 'shortcode']), 'category'), (value, key) => | ||||||
|         sortedEmojis.push({ title: key, data: chunk(value, 5) }) |         sortedEmojis.push({ title: key, data: chunk(value, 4) }) | ||||||
|       ) |       ) | ||||||
|       if (frequentEmojis.length) { |       if (frequentEmojis.length) { | ||||||
|         sortedEmojis.unshift({ |         sortedEmojis.unshift({ | ||||||
|           title: t('componentEmojis:frequentUsed'), |           title: t('componentEmojis:frequentUsed'), | ||||||
|           data: chunk( |           data: chunk( | ||||||
|             frequentEmojis.map(e => e.emoji), |             frequentEmojis.map(e => e.emoji), | ||||||
|             5 |             4 | ||||||
|           ), |           ), | ||||||
|           type: 'frequent' |           type: 'frequent' | ||||||
|         }) |         }) | ||||||
| @@ -125,7 +125,9 @@ const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({ | |||||||
|             <View |             <View | ||||||
|               style={[ |               style={[ | ||||||
|                 keyboardShown ? { position: 'absolute', bottom: 0, width: '100%' } : null, |                 keyboardShown ? { position: 'absolute', bottom: 0, width: '100%' } : null, | ||||||
|                 { marginBottom: keyboardShown ? insets.bottom : 0 } |                 { | ||||||
|  |                   marginBottom: keyboardShown && emojisState.targetIndex === -1 ? insets.bottom : 0 | ||||||
|  |                 } | ||||||
|               ]} |               ]} | ||||||
|               children={ |               children={ | ||||||
|                 emojisState.targetIndex !== -1 ? ( |                 emojisState.targetIndex !== -1 ? ( | ||||||
|   | |||||||
| @@ -42,7 +42,7 @@ const EmojisList = () => { | |||||||
|     } = emojisState.inputProps[emojisState.targetIndex] |     } = emojisState.inputProps[emojisState.targetIndex] | ||||||
|  |  | ||||||
|     const contentFront = value.slice(0, selection.start) |     const contentFront = value.slice(0, selection.start) | ||||||
|     const contentRear = value.slice(selection.end) |     const contentRear = value.slice(selection.end || selection.start) | ||||||
|  |  | ||||||
|     const spaceFront = value.length === 0 || /\s/g.test(contentFront.slice(-1)) ? '' : ' ' |     const spaceFront = value.length === 0 || /\s/g.test(contentFront.slice(-1)) ? '' : ' ' | ||||||
|     const spaceRear = /\s/g.test(contentRear[0]) ? '' : ' ' |     const spaceRear = /\s/g.test(contentRear[0]) ? '' : ' ' | ||||||
|   | |||||||
| @@ -157,32 +157,19 @@ const ComposeActions: React.FC = () => { | |||||||
|       return colors.secondary |       return colors.secondary | ||||||
|     } |     } | ||||||
|   }, [emojisState.emojis.length, emojisState.targetIndex]) |   }, [emojisState.emojis.length, emojisState.targetIndex]) | ||||||
|   // useEffect(() => { |  | ||||||
|   //   const showSubscription = Keyboard.addListener('keyboardWillShow', () => { |  | ||||||
|   //     composeDispatch({ type: 'emoji/shown', payload: false }) |  | ||||||
|   //   }) |  | ||||||
|  |  | ||||||
|   //   return () => { |  | ||||||
|   //     showSubscription.remove() |  | ||||||
|   //   } |  | ||||||
|   // }, []) |  | ||||||
|   const emojiOnPress = () => { |   const emojiOnPress = () => { | ||||||
|  |     analytics('compose_actions_emojis_press', { | ||||||
|  |       current: emojisState.targetIndex !== -1 | ||||||
|  |     }) | ||||||
|     if (emojisState.targetIndex === -1) { |     if (emojisState.targetIndex === -1) { | ||||||
|       Keyboard.dismiss() |       Keyboard.dismiss() | ||||||
|     } |  | ||||||
|       const focusedPropsIndex = emojisState.inputProps?.findIndex(props => props.isFocused.current) |       const focusedPropsIndex = emojisState.inputProps?.findIndex(props => props.isFocused.current) | ||||||
|       if (focusedPropsIndex === -1) return |       if (focusedPropsIndex === -1) return | ||||||
|       emojisDispatch({ type: 'target', payload: focusedPropsIndex }) |       emojisDispatch({ type: 'target', payload: focusedPropsIndex }) | ||||||
|     // Keyboard.dismiss() |     } else { | ||||||
|     // analytics('compose_actions_emojis_press', { |       emojisDispatch({ type: 'target', payload: -1 }) | ||||||
|     //   current: composeState.emoji.active |       return | ||||||
|     // }) |     } | ||||||
|     // if (composeState.emoji.emojis) { |  | ||||||
|     //   composeDispatch({ |  | ||||||
|     //     type: 'emoji', |  | ||||||
|     //     payload: { ...composeState.emoji, active: !composeState.emoji.active } |  | ||||||
|     //   }) |  | ||||||
|     // } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|   | |||||||
| @@ -1,161 +0,0 @@ | |||||||
| import haptics from '@components/haptics' |  | ||||||
| import CustomText from '@components/Text' |  | ||||||
| import { useAppDispatch } from '@root/store' |  | ||||||
| import { useAccessibility } from '@utils/accessibility/AccessibilityManager' |  | ||||||
| import { countInstanceEmoji } from '@utils/slices/instancesSlice' |  | ||||||
| import { getSettingsStaticEmoji } from '@utils/slices/settingsSlice' |  | ||||||
| import { StyleConstants } from '@utils/styles/constants' |  | ||||||
| import { useTheme } from '@utils/styles/ThemeManager' |  | ||||||
| import React, { RefObject, useCallback, useContext, useEffect } from 'react' |  | ||||||
| import { useTranslation } from 'react-i18next' |  | ||||||
| import { |  | ||||||
|   AccessibilityInfo, |  | ||||||
|   findNodeHandle, |  | ||||||
|   Image, |  | ||||||
|   Pressable, |  | ||||||
|   SectionList, |  | ||||||
|   View |  | ||||||
| } from 'react-native' |  | ||||||
| import FastImage from 'react-native-fast-image' |  | ||||||
| import { useSelector } from 'react-redux' |  | ||||||
| import validUrl from 'valid-url' |  | ||||||
| import updateText from '../../updateText' |  | ||||||
| import ComposeContext from '../../utils/createContext' |  | ||||||
|  |  | ||||||
| export interface Props { |  | ||||||
|   accessibleRefEmojis: RefObject<SectionList> |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => { |  | ||||||
|   const { composeState, composeDispatch } = useContext(ComposeContext) |  | ||||||
|   const { reduceMotionEnabled } = useAccessibility() |  | ||||||
|   const { colors } = useTheme() |  | ||||||
|   const { t } = useTranslation() |  | ||||||
|   const dispatch = useAppDispatch() |  | ||||||
|  |  | ||||||
|   const staticEmoji = useSelector(getSettingsStaticEmoji) |  | ||||||
|  |  | ||||||
|   useEffect(() => { |  | ||||||
|     const tagEmojis = findNodeHandle(accessibleRefEmojis.current) |  | ||||||
|     if (composeState.emoji.active) { |  | ||||||
|       tagEmojis && AccessibilityInfo.setAccessibilityFocus(tagEmojis) |  | ||||||
|     } |  | ||||||
|   }, [composeState.emoji.active]) |  | ||||||
|  |  | ||||||
|   const listItem = useCallback( |  | ||||||
|     ({ index, item }: { item: Mastodon.Emoji[]; index: number }) => { |  | ||||||
|       return ( |  | ||||||
|         <View |  | ||||||
|           key={index} |  | ||||||
|           style={{ |  | ||||||
|             flex: 1, |  | ||||||
|             flexWrap: 'wrap', |  | ||||||
|             marginTop: StyleConstants.Spacing.M, |  | ||||||
|             marginLeft: StyleConstants.Spacing.M |  | ||||||
|           }} |  | ||||||
|         > |  | ||||||
|           {item.map(emoji => { |  | ||||||
|             const uri = reduceMotionEnabled ? emoji.static_url : emoji.url |  | ||||||
|             if (validUrl.isHttpsUri(uri)) { |  | ||||||
|               return ( |  | ||||||
|                 <Pressable |  | ||||||
|                   key={emoji.shortcode} |  | ||||||
|                   onPress={() => { |  | ||||||
|                     haptics('Light') |  | ||||||
|                     updateText({ |  | ||||||
|                       composeState, |  | ||||||
|                       composeDispatch, |  | ||||||
|                       newText: `:${emoji.shortcode}:`, |  | ||||||
|                       type: 'emoji' |  | ||||||
|                     }) |  | ||||||
|                     dispatch(countInstanceEmoji(emoji)) |  | ||||||
|                   }} |  | ||||||
|                 > |  | ||||||
|                   {staticEmoji ? ( |  | ||||||
|                     <Image |  | ||||||
|                       accessibilityLabel={t( |  | ||||||
|                         'common:customEmoji.accessibilityLabel', |  | ||||||
|                         { |  | ||||||
|                           emoji: emoji.shortcode |  | ||||||
|                         } |  | ||||||
|                       )} |  | ||||||
|                       accessibilityHint={t( |  | ||||||
|                         'screenCompose:content.root.footer.emojis.accessibilityHint' |  | ||||||
|                       )} |  | ||||||
|                       source={{ uri }} |  | ||||||
|                       style={{ |  | ||||||
|                         width: 36, |  | ||||||
|                         height: 36, |  | ||||||
|                         padding: StyleConstants.Spacing.S, |  | ||||||
|                         margin: StyleConstants.Spacing.S |  | ||||||
|                       }} |  | ||||||
|                     /> |  | ||||||
|                   ) : ( |  | ||||||
|                     <FastImage |  | ||||||
|                       accessibilityLabel={t( |  | ||||||
|                         'common:customEmoji.accessibilityLabel', |  | ||||||
|                         { |  | ||||||
|                           emoji: emoji.shortcode |  | ||||||
|                         } |  | ||||||
|                       )} |  | ||||||
|                       accessibilityHint={t( |  | ||||||
|                         'screenCompose:content.root.footer.emojis.accessibilityHint' |  | ||||||
|                       )} |  | ||||||
|                       source={{ uri }} |  | ||||||
|                       style={{ |  | ||||||
|                         width: 36, |  | ||||||
|                         height: 36, |  | ||||||
|                         padding: StyleConstants.Spacing.S, |  | ||||||
|                         margin: StyleConstants.Spacing.S |  | ||||||
|                       }} |  | ||||||
|                     /> |  | ||||||
|                   )} |  | ||||||
|                 </Pressable> |  | ||||||
|               ) |  | ||||||
|             } else { |  | ||||||
|               return null |  | ||||||
|             } |  | ||||||
|           })} |  | ||||||
|         </View> |  | ||||||
|       ) |  | ||||||
|     }, |  | ||||||
|     [composeState] |  | ||||||
|   ) |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <View |  | ||||||
|       style={{ |  | ||||||
|         flex: 1, |  | ||||||
|         flexDirection: 'row', |  | ||||||
|         flexWrap: 'wrap', |  | ||||||
|         justifyContent: 'space-around', |  | ||||||
|         height: 280 |  | ||||||
|       }} |  | ||||||
|     > |  | ||||||
|       <SectionList |  | ||||||
|         accessible |  | ||||||
|         ref={accessibleRefEmojis} |  | ||||||
|         horizontal |  | ||||||
|         keyboardShouldPersistTaps='always' |  | ||||||
|         sections={composeState.emoji.emojis || []} |  | ||||||
|         keyExtractor={item => item[0].shortcode} |  | ||||||
|         renderSectionHeader={({ section: { title } }) => ( |  | ||||||
|           <CustomText |  | ||||||
|             fontStyle='S' |  | ||||||
|             style={{ |  | ||||||
|               position: 'absolute', |  | ||||||
|               left: StyleConstants.Spacing.L, |  | ||||||
|               color: colors.secondary |  | ||||||
|             }} |  | ||||||
|           > |  | ||||||
|             {title} |  | ||||||
|           </CustomText> |  | ||||||
|         )} |  | ||||||
|         renderItem={listItem} |  | ||||||
|         windowSize={2} |  | ||||||
|       /> |  | ||||||
|     </View> |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default React.memo(ComposeEmojis, () => true) |  | ||||||
		Reference in New Issue
	
	Block a user