1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00
This commit is contained in:
Zhiyuan Zheng
2021-05-23 23:19:37 +02:00
parent 61459cd2d2
commit f8366bb777
5 changed files with 75 additions and 90 deletions

View File

@ -12,21 +12,7 @@ import React, {
useReducer useReducer
} from 'react' } from 'react'
import FastImage from 'react-native-fast-image' import FastImage from 'react-native-fast-image'
import EmojisContext, { import EmojisContext, { emojisReducer } from './Emojis/helpers/EmojisContext'
EmojisAction,
EmojisState
} from './Emojis/helpers/EmojisContext'
const emojisReducer = (state: EmojisState, action: EmojisAction) => {
switch (action.type) {
case 'activate':
return { ...state, active: action.payload }
case 'load':
return { ...state, emojis: action.payload }
case 'shortcode':
return { ...state, shortcode: action.payload }
}
}
const prefetchEmojis = ( const prefetchEmojis = (
sortedEmojis: { title: string; data: Mastodon.Emoji[][] }[], sortedEmojis: { title: string; data: Mastodon.Emoji[][] }[],

View File

@ -27,4 +27,15 @@ type ContextType = {
} }
const EmojisContext = createContext<ContextType>({} as ContextType) const EmojisContext = createContext<ContextType>({} as ContextType)
export const emojisReducer = (state: EmojisState, action: EmojisAction) => {
switch (action.type) {
case 'activate':
return { ...state, active: action.payload }
case 'load':
return { ...state, emojis: action.payload }
case 'shortcode':
return { ...state, shortcode: action.payload }
}
}
export default EmojisContext export default EmojisContext

View File

@ -3,7 +3,7 @@ import { useEmojisQuery } from '@utils/queryHooks/emojis'
import { useSearchQuery } from '@utils/queryHooks/search' import { useSearchQuery } from '@utils/queryHooks/search'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { forEach, groupBy, sortBy } from 'lodash' import { chunk, forEach, groupBy, sortBy } from 'lodash'
import React, { import React, {
useCallback, useCallback,
useContext, useContext,
@ -28,15 +28,17 @@ import ComposeContext from './utils/createContext'
import ComposeDrafts from './Root/Drafts' import ComposeDrafts from './Root/Drafts'
import FastImage from 'react-native-fast-image' import FastImage from 'react-native-fast-image'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager' import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { ComposeState } from './utils/types'
const prefetchEmojis = ( const prefetchEmojis = (
sortedEmojis: { title: string; data: Mastodon.Emoji[] }[], sortedEmojis: NonNullable<ComposeState['emoji']['emojis']>,
reduceMotionEnabled: boolean reduceMotionEnabled: boolean
) => { ) => {
const prefetches: { uri: string }[] = [] const prefetches: { uri: string }[] = []
let requestedIndex = 0 let requestedIndex = 0
sortedEmojis.forEach(sorted => { sortedEmojis.forEach(sorted => {
sorted.data.forEach(emoji => { sorted.data.forEach(emojis =>
emojis.forEach(emoji => {
if (requestedIndex > 40) { if (requestedIndex > 40) {
return return
} }
@ -45,6 +47,7 @@ const prefetchEmojis = (
}) })
requestedIndex++ requestedIndex++
}) })
)
}) })
try { try {
FastImage.preload(prefetches) FastImage.preload(prefetches)
@ -90,10 +93,11 @@ const ComposeRoot = React.memo(
const { data: emojisData } = useEmojisQuery({}) const { data: emojisData } = useEmojisQuery({})
useEffect(() => { useEffect(() => {
if (emojisData && emojisData.length) { if (emojisData && emojisData.length) {
let sortedEmojis: { title: string; data: Mastodon.Emoji[] }[] = [] let sortedEmojis: { title: string; data: Mastodon.Emoji[][] }[] = []
forEach( forEach(
groupBy(sortBy(emojisData, ['category', 'shortcode']), 'category'), groupBy(sortBy(emojisData, ['category', 'shortcode']), 'category'),
(value, key) => sortedEmojis.push({ title: key, data: value }) (value, key) =>
sortedEmojis.push({ title: key, data: chunk(value, 5) })
) )
composeDispatch({ composeDispatch({
type: 'emoji', type: 'emoji',

View File

@ -1,15 +1,8 @@
import analytics from '@components/analytics'
import haptics from '@components/haptics' import haptics from '@components/haptics'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager' import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import React, { import React, { RefObject, useCallback, useContext, useEffect } from 'react'
RefObject,
useCallback,
useContext,
useEffect,
useMemo
} from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { import {
AccessibilityInfo, AccessibilityInfo,
@ -25,52 +18,15 @@ import validUrl from 'valid-url'
import updateText from '../../updateText' import updateText from '../../updateText'
import ComposeContext from '../../utils/createContext' import ComposeContext from '../../utils/createContext'
const SingleEmoji = ({ emoji }: { emoji: Mastodon.Emoji }) => {
const { t } = useTranslation()
const { reduceMotionEnabled } = useAccessibility()
const { composeState, composeDispatch } = useContext(ComposeContext)
const onPress = useCallback(() => {
analytics('compose_emoji_add')
updateText({
composeState,
composeDispatch,
newText: `:${emoji.shortcode}:`,
type: 'emoji'
})
haptics('Light')
}, [composeState])
const children = useMemo(() => {
const uri = reduceMotionEnabled ? emoji.static_url : emoji.url
if (validUrl.isHttpsUri(uri)) {
return (
<FastImage
accessibilityLabel={t('common:customEmoji.accessibilityLabel', {
emoji: emoji.shortcode
})}
accessibilityHint={t(
'screenCompose:content.root.footer.emojis.accessibilityHint'
)}
source={{ uri: reduceMotionEnabled ? emoji.static_url : emoji.url }}
style={styles.emoji}
/>
)
} else {
return null
}
}, [])
return (
<Pressable key={emoji.shortcode} onPress={onPress} children={children} />
)
}
export interface Props { export interface Props {
accessibleRefEmojis: RefObject<SectionList> accessibleRefEmojis: RefObject<SectionList>
} }
const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => { const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
const { composeState } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
const { reduceMotionEnabled } = useAccessibility()
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation()
useEffect(() => { useEffect(() => {
const tagEmojis = findNodeHandle(accessibleRefEmojis.current) const tagEmojis = findNodeHandle(accessibleRefEmojis.current)
@ -86,21 +42,49 @@ const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
[] []
) )
const emojiList = useCallback(
section =>
section.data.map((emoji: Mastodon.Emoji) => (
<SingleEmoji key={emoji.shortcode} emoji={emoji} />
)),
[]
)
const listItem = useCallback( const listItem = useCallback(
({ section, index }) => ({ index, item }: { item: Mastodon.Emoji[]; index: number }) => {
index === 0 ? ( return (
<View key={section.title} style={styles.emojis}> <View key={index} style={styles.emojis}>
{emojiList(section)} {item.map(emoji => {
const uri = reduceMotionEnabled ? emoji.static_url : emoji.url
if (validUrl.isHttpsUri(uri)) {
return (
<Pressable
key={emoji.shortcode}
onPress={() => {
updateText({
composeState,
composeDispatch,
newText: `:${emoji.shortcode}:`,
type: 'emoji'
})
haptics('Light')
}}
>
<FastImage
accessibilityLabel={t(
'common:customEmoji.accessibilityLabel',
{
emoji: emoji.shortcode
}
)}
accessibilityHint={t(
'screenCompose:content.root.footer.emojis.accessibilityHint'
)}
source={{ uri }}
style={styles.emoji}
/>
</Pressable>
)
} else {
return null
}
})}
</View> </View>
) : null, )
[] },
[composeState]
) )
return ( return (
@ -111,7 +95,7 @@ const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
horizontal horizontal
keyboardShouldPersistTaps='always' keyboardShouldPersistTaps='always'
sections={composeState.emoji.emojis || []} sections={composeState.emoji.emojis || []}
keyExtractor={item => item.shortcode} keyExtractor={item => item[0].shortcode}
renderSectionHeader={listHeader} renderSectionHeader={listHeader}
renderItem={listItem} renderItem={listItem}
windowSize={2} windowSize={2}

View File

@ -40,7 +40,7 @@ export type ComposeState = {
} }
emoji: { emoji: {
active: boolean active: boolean
emojis: { title: string; data: Mastodon.Emoji[] }[] | undefined emojis: { title: string; data: Mastodon.Emoji[][] }[] | undefined
} }
poll: { poll: {
active: boolean active: boolean